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 | Changelog |
|
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 | 1.4.0 (**2012-09-03**) |
|
46 | 1.4.0 (**2012-09-03**) | |
8 | ---------------------- |
|
47 | ---------------------- | |
9 |
|
48 |
@@ -11,8 +11,8 b' clients. Minimal version of hg client kn' | |||||
11 | **1.6**. If you're using older client, please upgrade. |
|
11 | **1.6**. If you're using older client, please upgrade. | |
12 |
|
12 | |||
13 |
|
13 | |||
14 |
Installing RhodeCode from Cheese |
|
14 | Installing RhodeCode from PyPI (aka "Cheeseshop") | |
15 | ------------------------------------- |
|
15 | ------------------------------------------------- | |
16 |
|
16 | |||
17 | Rhodecode requires python version 2.5 or higher. |
|
17 | Rhodecode requires python version 2.5 or higher. | |
18 |
|
18 | |||
@@ -126,4 +126,4 b' You can now proceed to :ref:`setup`' | |||||
126 | .. _python: http://www.python.org/ |
|
126 | .. _python: http://www.python.org/ | |
127 | .. _mercurial: http://mercurial.selenic.com/ |
|
127 | .. _mercurial: http://mercurial.selenic.com/ | |
128 | .. _celery: http://celeryproject.org/ |
|
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 | Here is a sample excerpt from an Apache Virtual Host configuration file:: |
|
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 | threads=4 \ |
|
671 | threads=4 \ | |
672 | python-path=/home/web/rhodecode/pyenv/lib/python2.6/site-packages |
|
672 | python-path=/home/web/rhodecode/pyenv/lib/python2.6/site-packages | |
673 | WSGIScriptAlias / /home/web/rhodecode/dispatch.wsgi |
|
673 | WSGIScriptAlias / /home/web/rhodecode/dispatch.wsgi | |
674 | WSGIPassAuthorization On |
|
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 | Example wsgi dispatch script:: |
|
685 | Example wsgi dispatch script:: | |
677 |
|
686 | |||
678 | import os |
|
687 | import os |
@@ -4,14 +4,43 b'' | |||||
4 | Upgrade |
|
4 | Upgrade | |
5 | ======= |
|
5 | ======= | |
6 |
|
6 | |||
7 |
Upgrading from Cheese |
|
7 | Upgrading from PyPI (aka "Cheeseshop") | |
8 | -------------------------- |
|
8 | --------------------------------------- | |
9 |
|
9 | |||
10 | .. note:: |
|
10 | .. note:: | |
11 |
Firstly, it is recommended that you **always** perform a database |
|
11 | Firstly, it is recommended that you **always** perform a database and | |
12 | before doing an upgrade. |
|
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 | easy_install -U rhodecode |
|
45 | easy_install -U rhodecode | |
17 |
|
46 | |||
@@ -20,14 +49,13 b' Or::' | |||||
20 | pip install --upgrade rhodecode |
|
49 | pip install --upgrade rhodecode | |
21 |
|
50 | |||
22 |
|
51 | |||
23 |
Then |
|
52 | Then run the following command from the installation directory:: | |
24 |
|
53 | |||
25 | paster make-config RhodeCode production.ini |
|
54 | paster make-config RhodeCode production.ini | |
26 |
|
55 | |||
27 | This will display any changes made by the new version of RhodeCode to your |
|
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 |
|
57 | current configuration. It will try to perform an automerge. It's recommended | |
29 | to make a backup of your configuration file before hand and re check the |
|
58 | that you re-check the content after the automerge. | |
30 | content after the automerge. |
|
|||
31 |
|
59 | |||
32 | .. note:: |
|
60 | .. note:: | |
33 | Please always make sure your .ini files are up to date. Often errors are |
|
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 | The final step is to upgrade the database. To do this simply run:: |
|
70 | The final step is to upgrade the database. To do this simply run:: | |
43 |
|
71 | |||
44 |
|
|
72 | paster upgrade-db production.ini | |
45 |
|
73 | |||
46 | This will upgrade the schema and update some of the defaults in the database, |
|
74 | This will upgrade the schema and update some of the defaults in the database, | |
47 | and will always recheck the settings of the application, if there are no new |
|
75 | and will always recheck the settings of the application, if there are no new | |
48 | options that need to be set. |
|
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 | .. note:: |
|
91 | .. note:: | |
51 | If you're using Celery, make sure you restart all instances of it after |
|
92 | If you're using Celery, make sure you restart all instances of it after | |
52 | upgrade. |
|
93 | upgrade. | |
@@ -55,4 +96,4 b' options that need to be set.' | |||||
55 | .. _python: http://www.python.org/ |
|
96 | .. _python: http://www.python.org/ | |
56 | .. _mercurial: http://mercurial.selenic.com/ |
|
97 | .. _mercurial: http://mercurial.selenic.com/ | |
57 | .. _celery: http://celeryproject.org/ |
|
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 | import sys |
|
26 | import sys | |
27 | import platform |
|
27 | import platform | |
28 |
|
28 | |||
29 |
VERSION = (1, 4, |
|
29 | VERSION = (1, 4, 1) | |
30 |
|
30 | |||
31 | try: |
|
31 | try: | |
32 | from rhodecode.lib import get_current_revision |
|
32 | from rhodecode.lib import get_current_revision | |
@@ -38,7 +38,7 b' except ImportError:' | |||||
38 |
|
38 | |||
39 | __version__ = ('.'.join((str(each) for each in VERSION[:3])) + |
|
39 | __version__ = ('.'.join((str(each) for each in VERSION[:3])) + | |
40 | '.'.join(VERSION[3:])) |
|
40 | '.'.join(VERSION[3:])) | |
41 |
__dbversion__ = |
|
41 | __dbversion__ = 7 # defines current db version for migrations | |
42 | __platform__ = platform.system() |
|
42 | __platform__ = platform.system() | |
43 | __license__ = 'GPLv3' |
|
43 | __license__ = 'GPLv3' | |
44 | __py_version__ = sys.version_info |
|
44 | __py_version__ = sys.version_info |
@@ -34,7 +34,7 b' def make_map(config):' | |||||
34 |
|
34 | |||
35 | try: |
|
35 | try: | |
36 | by_id = repo_name.split('_') |
|
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 | repo_name = Repository.get(by_id[1]).repo_name |
|
38 | repo_name = Repository.get(by_id[1]).repo_name | |
39 | match_dict['repo_name'] = repo_name |
|
39 | match_dict['repo_name'] = repo_name | |
40 | except: |
|
40 | except: |
@@ -45,6 +45,7 b' from rhodecode.model.forms import ReposG' | |||||
45 | from rhodecode.model.meta import Session |
|
45 | from rhodecode.model.meta import Session | |
46 | from rhodecode.model.repo import RepoModel |
|
46 | from rhodecode.model.repo import RepoModel | |
47 | from webob.exc import HTTPInternalServerError, HTTPNotFound |
|
47 | from webob.exc import HTTPInternalServerError, HTTPNotFound | |
|
48 | from rhodecode.lib.utils2 import str2bool | |||
48 |
|
49 | |||
49 | log = logging.getLogger(__name__) |
|
50 | log = logging.getLogger(__name__) | |
50 |
|
51 | |||
@@ -162,7 +163,7 b' class ReposGroupsController(BaseControll' | |||||
162 | Session().commit() |
|
163 | Session().commit() | |
163 | h.flash(_('updated repos group %s') \ |
|
164 | h.flash(_('updated repos group %s') \ | |
164 | % form_result['group_name'], category='success') |
|
165 | % form_result['group_name'], category='success') | |
165 | #TODO: in futureaction_logger(, '', '', '', self.sa) |
|
166 | #TODO: in future action_logger(, '', '', '', self.sa) | |
166 | except formencode.Invalid, errors: |
|
167 | except formencode.Invalid, errors: | |
167 |
|
168 | |||
168 | return htmlfill.render( |
|
169 | return htmlfill.render( | |
@@ -227,10 +228,11 b' class ReposGroupsController(BaseControll' | |||||
227 |
|
228 | |||
228 | :param group_name: |
|
229 | :param group_name: | |
229 | """ |
|
230 | """ | |
230 |
|
||||
231 | try: |
|
231 | try: | |
232 | ReposGroupModel().revoke_user_permission( |
|
232 | recursive = str2bool(request.POST.get('recursive', False)) | |
233 | repos_group=group_name, user=request.POST['user_id'] |
|
233 | ReposGroupModel().delete_permission( | |
|
234 | repos_group=group_name, obj=request.POST['user_id'], | |||
|
235 | obj_type='user', recursive=recursive | |||
234 | ) |
|
236 | ) | |
235 | Session().commit() |
|
237 | Session().commit() | |
236 | except Exception: |
|
238 | except Exception: | |
@@ -248,9 +250,10 b' class ReposGroupsController(BaseControll' | |||||
248 | """ |
|
250 | """ | |
249 |
|
251 | |||
250 | try: |
|
252 | try: | |
251 | ReposGroupModel().revoke_users_group_permission( |
|
253 | recursive = str2bool(request.POST.get('recursive', False)) | |
252 | repos_group=group_name, |
|
254 | ReposGroupModel().delete_permission( | |
253 | group_name=request.POST['users_group_id'] |
|
255 | repos_group=group_name, obj=request.POST['users_group_id'], | |
|
256 | obj_type='users_group', recursive=recursive | |||
254 | ) |
|
257 | ) | |
255 | Session().commit() |
|
258 | Session().commit() | |
256 | except Exception: |
|
259 | except Exception: |
@@ -51,6 +51,7 b' from rhodecode.model.user import UserMod' | |||||
51 | from rhodecode.model.db import User |
|
51 | from rhodecode.model.db import User | |
52 | from rhodecode.model.notification import EmailNotificationModel |
|
52 | from rhodecode.model.notification import EmailNotificationModel | |
53 | from rhodecode.model.meta import Session |
|
53 | from rhodecode.model.meta import Session | |
|
54 | from rhodecode.lib.utils2 import str2bool | |||
54 |
|
55 | |||
55 | log = logging.getLogger(__name__) |
|
56 | log = logging.getLogger(__name__) | |
56 |
|
57 | |||
@@ -471,6 +472,9 b' class SettingsController(BaseController)' | |||||
471 | if k == '/': |
|
472 | if k == '/': | |
472 | k = 'root_path' |
|
473 | k = 'root_path' | |
473 |
|
474 | |||
|
475 | if k == 'push_ssl': | |||
|
476 | v = str2bool(v) | |||
|
477 | ||||
474 | if k.find('.') != -1: |
|
478 | if k.find('.') != -1: | |
475 | k = k.replace('.', '_') |
|
479 | k = k.replace('.', '_') | |
476 |
|
480 | |||
@@ -478,5 +482,4 b' class SettingsController(BaseController)' | |||||
478 | v = each.ui_active |
|
482 | v = each.ui_active | |
479 |
|
483 | |||
480 | settings[each.ui_section + '_' + k] = v |
|
484 | settings[each.ui_section + '_' + k] = v | |
481 |
|
||||
482 | return settings |
|
485 | return settings |
@@ -376,9 +376,13 b' class ChangesetController(BaseRepoContro' | |||||
376 | def comment(self, repo_name, revision): |
|
376 | def comment(self, repo_name, revision): | |
377 | status = request.POST.get('changeset_status') |
|
377 | status = request.POST.get('changeset_status') | |
378 | change_status = request.POST.get('change_changeset_status') |
|
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 | comm = ChangesetCommentsModel().create( |
|
384 | comm = ChangesetCommentsModel().create( | |
381 |
text= |
|
385 | text=text, | |
382 | repo=c.rhodecode_db_repo.repo_id, |
|
386 | repo=c.rhodecode_db_repo.repo_id, | |
383 | user=c.rhodecode_user.user_id, |
|
387 | user=c.rhodecode_user.user_id, | |
384 | revision=revision, |
|
388 | revision=revision, | |
@@ -391,7 +395,7 b' class ChangesetController(BaseRepoContro' | |||||
391 | # get status if set ! |
|
395 | # get status if set ! | |
392 | if status and change_status: |
|
396 | if status and change_status: | |
393 | # if latest status was from pull request and it's closed |
|
397 | # if latest status was from pull request and it's closed | |
394 |
# disallow changing status ! |
|
398 | # disallow changing status ! | |
395 | # dont_allow_on_closed_pull_request = True ! |
|
399 | # dont_allow_on_closed_pull_request = True ! | |
396 |
|
400 | |||
397 | try: |
|
401 | try: |
@@ -249,8 +249,7 b' class PullrequestsController(BaseRepoCon' | |||||
249 | org_repo, org_ref, other_repo, other_ref |
|
249 | org_repo, org_ref, other_repo, other_ref | |
250 | ) |
|
250 | ) | |
251 |
|
251 | |||
252 |
c.statuses = |
|
252 | c.statuses = org_repo.statuses([x.raw_id for x in c.cs_ranges]) | |
253 | c.cs_ranges]) |
|
|||
254 | # defines that we need hidden inputs with changesets |
|
253 | # defines that we need hidden inputs with changesets | |
255 | c.as_form = request.GET.get('as_form', False) |
|
254 | c.as_form = request.GET.get('as_form', False) | |
256 |
|
255 | |||
@@ -277,6 +276,7 b' class PullrequestsController(BaseRepoCon' | |||||
277 | c.users_array = repo_model.get_users_js() |
|
276 | c.users_array = repo_model.get_users_js() | |
278 | c.users_groups_array = repo_model.get_users_groups_js() |
|
277 | c.users_groups_array = repo_model.get_users_groups_js() | |
279 | c.pull_request = PullRequest.get_or_404(pull_request_id) |
|
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 | cc_model = ChangesetCommentsModel() |
|
281 | cc_model = ChangesetCommentsModel() | |
282 | cs_model = ChangesetStatusModel() |
|
282 | cs_model = ChangesetStatusModel() | |
@@ -322,12 +322,20 b' class PullrequestsController(BaseRepoCon' | |||||
322 | c.comments = cc_model.get_comments(c.rhodecode_db_repo.repo_id, |
|
322 | c.comments = cc_model.get_comments(c.rhodecode_db_repo.repo_id, | |
323 | pull_request=pull_request_id) |
|
323 | pull_request=pull_request_id) | |
324 |
|
324 | |||
325 | # changeset(pull-request) status |
|
325 | try: | |
326 | c.current_changeset_status = cs_model.calculate_status( |
|
326 | cur_status = c.statuses[c.pull_request.revisions[0]][0] | |
327 | c.pull_request_reviewers |
|
327 | except: | |
328 | ) |
|
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 | c.changeset_statuses = ChangesetStatus.STATUSES |
|
337 | c.changeset_statuses = ChangesetStatus.STATUSES | |
330 | c.target_repo = c.pull_request.org_repo.repo_name |
|
338 | ||
331 | return render('/pullrequests/pullrequest_show.html') |
|
339 | return render('/pullrequests/pullrequest_show.html') | |
332 |
|
340 | |||
333 | @NotAnonymous() |
|
341 | @NotAnonymous() | |
@@ -339,9 +347,12 b' class PullrequestsController(BaseRepoCon' | |||||
339 |
|
347 | |||
340 | status = request.POST.get('changeset_status') |
|
348 | status = request.POST.get('changeset_status') | |
341 | change_status = request.POST.get('change_changeset_status') |
|
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 | comm = ChangesetCommentsModel().create( |
|
354 | comm = ChangesetCommentsModel().create( | |
344 |
text= |
|
355 | text=text, | |
345 | repo=c.rhodecode_db_repo.repo_id, |
|
356 | repo=c.rhodecode_db_repo.repo_id, | |
346 | user=c.rhodecode_user.user_id, |
|
357 | user=c.rhodecode_user.user_id, | |
347 | pull_request=pull_request_id, |
|
358 | pull_request=pull_request_id, |
@@ -400,9 +400,19 b' def create_repo_fork(form_data, cur_user' | |||||
400 | log.info('creating fork of %s as %s', source_repo_path, |
|
400 | log.info('creating fork of %s as %s', source_repo_path, | |
401 | destination_fork_path) |
|
401 | destination_fork_path) | |
402 | backend = get_backend(repo_type) |
|
402 | backend = get_backend(repo_type) | |
403 | backend(safe_str(destination_fork_path), create=True, |
|
403 | ||
404 | src_url=safe_str(source_repo_path), |
|
404 | if repo_type == 'git': | |
405 | update_after_clone=update_after_clone) |
|
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 | log_create_repository(fork_repo.get_dict(), created_by=cur_user.username) |
|
416 | log_create_repository(fork_repo.get_dict(), created_by=cur_user.username) | |
407 |
|
417 | |||
408 | action_logger(cur_user, 'user_forked_repo:%s' % fork_name, |
|
418 | action_logger(cur_user, 'user_forked_repo:%s' % fork_name, |
@@ -589,6 +589,3 b' else:' | |||||
589 | self.__cond.wait(timeout) |
|
589 | self.__cond.wait(timeout) | |
590 | finally: |
|
590 | finally: | |
591 | self.__cond.release() |
|
591 | self.__cond.release() | |
592 |
|
||||
593 |
|
||||
594 |
|
@@ -247,7 +247,22 b' class DbManage(object):' | |||||
247 | Session().add(hggit) |
|
247 | Session().add(hggit) | |
248 |
|
248 | |||
249 | notify('re-check default permissions') |
|
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 | upgrade_steps = [0] + range(curr_version + 1, __dbversion__ + 1) |
|
267 | upgrade_steps = [0] + range(curr_version + 1, __dbversion__ + 1) | |
253 |
|
268 | |||
@@ -470,6 +485,28 b' class DbManage(object):' | |||||
470 | log.debug('missing default permission for group %s adding' % g) |
|
485 | log.debug('missing default permission for group %s adding' % g) | |
471 | ReposGroupModel()._create_default_perms(g) |
|
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 | def config_prompt(self, test_repo_path='', retries=3, defaults={}): |
|
510 | def config_prompt(self, test_repo_path='', retries=3, defaults={}): | |
474 | _path = defaults.get('repos_location') |
|
511 | _path = defaults.get('repos_location') | |
475 | if retries == 3: |
|
512 | if retries == 3: | |
@@ -506,7 +543,15 b' class DbManage(object):' | |||||
506 | retries -= 1 |
|
543 | retries -= 1 | |
507 | return self.config_prompt(test_repo_path, retries) |
|
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 | def create_settings(self, path): |
|
556 | def create_settings(self, path): | |
512 |
|
557 | |||
@@ -597,8 +642,7 b' class DbManage(object):' | |||||
597 |
|
642 | |||
598 | default_user = User.get_by_username('default') |
|
643 | default_user = User.get_by_username('default') | |
599 |
|
644 | |||
600 | for def_perm in ['hg.register.manual_activate', 'hg.create.repository', |
|
645 | for def_perm in User.DEFAULT_PERMISSIONS: | |
601 | 'hg.fork.repository', 'repository.read']: |
|
|||
602 |
|
646 | |||
603 | perm = self.sa.query(Permission)\ |
|
647 | perm = self.sa.query(Permission)\ | |
604 | .filter(Permission.permission_name == def_perm)\ |
|
648 | .filter(Permission.permission_name == def_perm)\ |
@@ -1317,4 +1317,4 b' class PullRequest(Base, BaseModel):' | |||||
1317 | org_repo_id = Column('org_repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False) |
|
1317 | org_repo_id = Column('org_repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False) | |
1318 | org_ref = Column('org_ref', Unicode(256), nullable=False) |
|
1318 | org_ref = Column('org_ref', Unicode(256), nullable=False) | |
1319 | other_repo_id = Column('other_repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False) |
|
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 | tbl = ChangesetStatus.__table__ |
|
49 | tbl = ChangesetStatus.__table__ | |
50 | tbl.create() |
|
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 | Base = declarative_base() |
|
53 | Base = declarative_base() | |
54 | Base.metadata.clear() |
|
54 | Base.metadata.clear() | |
55 | Base.metadata = MetaData() |
|
55 | Base.metadata = MetaData() |
@@ -610,7 +610,7 b' def differ(org_repo, org_ref, other_repo' | |||||
610 | other_repo.ui.setconfig('hooks', k, None) |
|
610 | other_repo.ui.setconfig('hooks', k, None) | |
611 |
|
611 | |||
612 | unbundle = other_repo.getbundle('incoming', common=common, |
|
612 | unbundle = other_repo.getbundle('incoming', common=common, | |
613 |
heads= |
|
613 | heads=None) | |
614 |
|
614 | |||
615 | buf = BytesIO() |
|
615 | buf = BytesIO() | |
616 | while True: |
|
616 | while True: |
@@ -92,7 +92,7 b' try:' | |||||
92 | return _obj_dump(obj) |
|
92 | return _obj_dump(obj) | |
93 | except NotImplementedError: |
|
93 | except NotImplementedError: | |
94 | pass |
|
94 | pass | |
95 | return json.JSONEncoder.default(self, obj) |
|
95 | raise TypeError("%r is not JSON serializable" % (obj,)) | |
96 | # monkey-patch JSON encoder to use extended version |
|
96 | # monkey-patch JSON encoder to use extended version | |
97 | json.dumps = functools.partial(json.dumps, cls=ExtendedEncoder) |
|
97 | json.dumps = functools.partial(json.dumps, cls=ExtendedEncoder) | |
98 | json.dump = functools.partial(json.dump, cls=ExtendedEncoder) |
|
98 | json.dump = functools.partial(json.dump, cls=ExtendedEncoder) |
@@ -34,10 +34,9 b' from rhodecode.lib import helpers as h' | |||||
34 | from rhodecode.lib.utils import action_logger |
|
34 | from rhodecode.lib.utils import action_logger | |
35 | from rhodecode.lib.vcs.backends.base import EmptyChangeset |
|
35 | from rhodecode.lib.vcs.backends.base import EmptyChangeset | |
36 | from rhodecode.lib.compat import json |
|
36 | from rhodecode.lib.compat import json | |
37 | from rhodecode.model.db import Repository, User |
|
37 | from rhodecode.lib.exceptions import HTTPLockedRC | |
38 | from rhodecode.lib.utils2 import safe_str |
|
38 | from rhodecode.lib.utils2 import safe_str | |
39 | from rhodecode.lib.exceptions import HTTPLockedRC |
|
39 | from rhodecode.model.db import Repository, User | |
40 |
|
||||
41 |
|
40 | |||
42 | def _get_scm_size(alias, root_path): |
|
41 | def _get_scm_size(alias, root_path): | |
43 |
|
42 | |||
@@ -330,7 +329,12 b' def handle_git_receive(repo_path, revs, ' | |||||
330 | # fix if it's not a bare repo |
|
329 | # fix if it's not a bare repo | |
331 | if repo_path.endswith('.git'): |
|
330 | if repo_path.endswith('.git'): | |
332 | repo_path = repo_path[:-4] |
|
331 | repo_path = repo_path[:-4] | |
|
332 | ||||
333 | repo = Repository.get_by_full_path(repo_path) |
|
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 | _hooks = dict(baseui.configitems('hooks')) or {} |
|
338 | _hooks = dict(baseui.configitems('hooks')) or {} | |
335 |
|
339 | |||
336 | extras = json.loads(env['RHODECODE_EXTRAS']) |
|
340 | extras = json.loads(env['RHODECODE_EXTRAS']) |
@@ -206,7 +206,7 b' def get_repos(path, recursive=False):' | |||||
206 | def is_valid_repo(repo_name, base_path, scm=None): |
|
206 | def is_valid_repo(repo_name, base_path, scm=None): | |
207 | """ |
|
207 | """ | |
208 | Returns True if given path is a valid repository False otherwise. |
|
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 | from scm parameter |
|
210 | from scm parameter | |
211 |
|
211 | |||
212 | :param repo_name: |
|
212 | :param repo_name: | |
@@ -413,6 +413,11 b' def repo2db_mapper(initial_repo_list, re' | |||||
413 | raise Exception('Missing administrative account !') |
|
413 | raise Exception('Missing administrative account !') | |
414 | added = [] |
|
414 | added = [] | |
415 |
|
415 | |||
|
416 | # # clear cache keys | |||
|
417 | # log.debug("Clearing cache keys now...") | |||
|
418 | # CacheInvalidation.clear_cache() | |||
|
419 | # sa.commit() | |||
|
420 | ||||
416 | for name, repo in initial_repo_list.items(): |
|
421 | for name, repo in initial_repo_list.items(): | |
417 | group = map_groups(name) |
|
422 | group = map_groups(name) | |
418 | db_repo = rm.get_by_repo_name(name) |
|
423 | db_repo = rm.get_by_repo_name(name) | |
@@ -438,6 +443,11 b' def repo2db_mapper(initial_repo_list, re' | |||||
438 | elif install_git_hook: |
|
443 | elif install_git_hook: | |
439 | if db_repo.repo_type == 'git': |
|
444 | if db_repo.repo_type == 'git': | |
440 | ScmModel().install_git_hook(db_repo.scm_instance) |
|
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 | sa.commit() |
|
451 | sa.commit() | |
442 | removed = [] |
|
452 | removed = [] | |
443 | if remove_obsolete: |
|
453 | if remove_obsolete: | |
@@ -455,10 +465,6 b' def repo2db_mapper(initial_repo_list, re' | |||||
455 | log.error(traceback.format_exc()) |
|
465 | log.error(traceback.format_exc()) | |
456 | sa.rollback() |
|
466 | sa.rollback() | |
457 |
|
467 | |||
458 | # clear cache keys |
|
|||
459 | log.debug("Clearing cache keys now...") |
|
|||
460 | CacheInvalidation.clear_cache() |
|
|||
461 | sa.commit() |
|
|||
462 | return added, removed |
|
468 | return added, removed | |
463 |
|
469 | |||
464 |
|
470 |
@@ -178,7 +178,7 b' class GitRepository(BaseRepository):' | |||||
178 | raise urllib2.URLError("[%s] %s" % (url, e)) |
|
178 | raise urllib2.URLError("[%s] %s" % (url, e)) | |
179 |
|
179 | |||
180 | def _get_repo(self, create, src_url=None, update_after_clone=False, |
|
180 | def _get_repo(self, create, src_url=None, update_after_clone=False, | |
181 | bare=False): |
|
181 | bare=False): | |
182 | if create and os.path.exists(self.path): |
|
182 | if create and os.path.exists(self.path): | |
183 | raise RepositoryError("Location already exist") |
|
183 | raise RepositoryError("Location already exist") | |
184 | if src_url and not create: |
|
184 | if src_url and not create: |
@@ -14,4 +14,5 b' from mercurial.node import hex' | |||||
14 | from mercurial.encoding import tolocal |
|
14 | from mercurial.encoding import tolocal | |
15 | from mercurial import discovery |
|
15 | from mercurial import discovery | |
16 | from mercurial import localrepo |
|
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 | def calculate_status(self, statuses_by_reviewers): |
|
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 | :param statuses_by_reviewers: |
|
69 | :param statuses_by_reviewers: | |
70 | """ |
|
70 | """ |
@@ -123,18 +123,20 b' class ChangesetCommentsModel(BaseModel):' | |||||
123 | recipients = ChangesetComment.get_users(revision=revision) |
|
123 | recipients = ChangesetComment.get_users(revision=revision) | |
124 | # add changeset author if it's in rhodecode system |
|
124 | # add changeset author if it's in rhodecode system | |
125 | recipients += [User.get_by_email(author_email)] |
|
125 | recipients += [User.get_by_email(author_email)] | |
|
126 | email_kwargs = { | |||
|
127 | 'status_change': status_change, | |||
|
128 | } | |||
126 | #pull request |
|
129 | #pull request | |
127 | elif pull_request: |
|
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 | subj = safe_unicode( |
|
137 | subj = safe_unicode( | |
129 | h.link_to('Re pull request: %(desc)s %(line)s' % \ |
|
138 | h.link_to('Re pull request: %(desc)s %(line)s' % \ | |
130 | {'desc': desc, 'line': line}, |
|
139 | {'desc': desc, 'line': line}, _url) | |
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 | ) |
|
|||
138 | ) |
|
140 | ) | |
139 |
|
141 | |||
140 | notification_type = Notification.TYPE_PULL_REQUEST_COMMENT |
|
142 | notification_type = Notification.TYPE_PULL_REQUEST_COMMENT | |
@@ -144,22 +146,36 b' class ChangesetCommentsModel(BaseModel):' | |||||
144 | # add pull request author |
|
146 | # add pull request author | |
145 | recipients += [pull_request.author] |
|
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 | # create notification objects, and emails |
|
162 | # create notification objects, and emails | |
148 | NotificationModel().create( |
|
163 | NotificationModel().create( | |
149 | created_by=user, subject=subj, body=body, |
|
164 | created_by=user, subject=subj, body=body, | |
150 | recipients=recipients, type_=notification_type, |
|
165 | recipients=recipients, type_=notification_type, | |
151 | email_kwargs={'status_change': status_change} |
|
166 | email_kwargs=email_kwargs | |
152 | ) |
|
167 | ) | |
153 |
|
168 | |||
154 | mention_recipients = set(self._extract_mentions(body))\ |
|
169 | mention_recipients = set(self._extract_mentions(body))\ | |
155 | .difference(recipients) |
|
170 | .difference(recipients) | |
156 | if mention_recipients: |
|
171 | if mention_recipients: | |
|
172 | email_kwargs.update({'pr_mention': True}) | |||
157 | subj = _('[Mention]') + ' ' + subj |
|
173 | subj = _('[Mention]') + ' ' + subj | |
158 | NotificationModel().create( |
|
174 | NotificationModel().create( | |
159 | created_by=user, subject=subj, body=body, |
|
175 | created_by=user, subject=subj, body=body, | |
160 | recipients=mention_recipients, |
|
176 | recipients=mention_recipients, | |
161 | type_=notification_type, |
|
177 | type_=notification_type, | |
162 | email_kwargs={'status_change': status_change} |
|
178 | email_kwargs=email_kwargs | |
163 | ) |
|
179 | ) | |
164 |
|
180 | |||
165 | return comment |
|
181 | return comment |
@@ -278,6 +278,10 b' class RhodeCodeUi(Base, BaseModel):' | |||||
278 |
|
278 | |||
279 | Session().add(new_ui) |
|
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 | class User(Base, BaseModel): |
|
286 | class User(Base, BaseModel): | |
283 | __tablename__ = 'users' |
|
287 | __tablename__ = 'users' | |
@@ -289,7 +293,10 b' class User(Base, BaseModel):' | |||||
289 | 'mysql_charset': 'utf8'} |
|
293 | 'mysql_charset': 'utf8'} | |
290 | ) |
|
294 | ) | |
291 | DEFAULT_USER = 'default' |
|
295 | DEFAULT_USER = 'default' | |
292 |
|
296 | DEFAULT_PERMISSIONS = [ | ||
|
297 | 'hg.register.manual_activate', 'hg.create.repository', | |||
|
298 | 'hg.fork.repository', 'repository.read' | |||
|
299 | ] | |||
293 | user_id = Column("user_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) |
|
300 | user_id = Column("user_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) | |
294 | username = Column("username", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None) |
|
301 | username = Column("username", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None) | |
295 | password = Column("password", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None) |
|
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 | enable_downloads = Column("downloads", Boolean(), nullable=True, unique=None, default=True) |
|
609 | enable_downloads = Column("downloads", Boolean(), nullable=True, unique=None, default=True) | |
603 | description = Column("description", String(10000, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None) |
|
610 | description = Column("description", String(10000, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None) | |
604 | created_on = Column('created_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now) |
|
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 | landing_rev = Column("landing_revision", String(255, convert_unicode=False, assert_unicode=None), nullable=False, unique=False, default=None) |
|
613 | landing_rev = Column("landing_revision", String(255, convert_unicode=False, assert_unicode=None), nullable=False, unique=False, default=None) | |
606 | enable_locking = Column("enable_locking", Boolean(), nullable=False, unique=None, default=False) |
|
614 | enable_locking = Column("enable_locking", Boolean(), nullable=False, unique=None, default=False) | |
607 | _locked = Column("locked", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=False, default=None) |
|
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 | p += self.repo_name.split(Repository.url_sep()) |
|
750 | p += self.repo_name.split(Repository.url_sep()) | |
743 | return os.path.join(*p) |
|
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 | def get_new_name(self, repo_name): |
|
763 | def get_new_name(self, repo_name): | |
746 | """ |
|
764 | """ | |
747 | returns new full repository name based on assigned group and new new |
|
765 | returns new full repository name based on assigned group and new new | |
@@ -1398,6 +1416,13 b' class CacheInvalidation(Base, BaseModel)' | |||||
1398 | return u"<%s('%s:%s')>" % (self.__class__.__name__, |
|
1416 | return u"<%s('%s:%s')>" % (self.__class__.__name__, | |
1399 | self.cache_id, self.cache_key) |
|
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 | @classmethod |
|
1426 | @classmethod | |
1402 | def clear_cache(cls): |
|
1427 | def clear_cache(cls): | |
1403 | cls.query().delete() |
|
1428 | cls.query().delete() | |
@@ -1421,13 +1446,14 b' class CacheInvalidation(Base, BaseModel)' | |||||
1421 | return cls.query().filter(cls.cache_key == key).scalar() |
|
1446 | return cls.query().filter(cls.cache_key == key).scalar() | |
1422 |
|
1447 | |||
1423 | @classmethod |
|
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 | inv_obj = Session().query(cls).filter(cls.cache_key == key).scalar() |
|
1450 | inv_obj = Session().query(cls).filter(cls.cache_key == key).scalar() | |
1426 | if not inv_obj: |
|
1451 | if not inv_obj: | |
1427 | try: |
|
1452 | try: | |
1428 | inv_obj = CacheInvalidation(key, org_key) |
|
1453 | inv_obj = CacheInvalidation(key, org_key) | |
1429 | Session().add(inv_obj) |
|
1454 | Session().add(inv_obj) | |
1430 |
|
|
1455 | if commit: | |
|
1456 | Session().commit() | |||
1431 | except Exception: |
|
1457 | except Exception: | |
1432 | log.error(traceback.format_exc()) |
|
1458 | log.error(traceback.format_exc()) | |
1433 | Session().rollback() |
|
1459 | Session().rollback() |
@@ -128,6 +128,7 b' def ReposGroupForm(edit=False, old_data=' | |||||
128 | testValueList=True, |
|
128 | testValueList=True, | |
129 | if_missing=None, not_empty=False) |
|
129 | if_missing=None, not_empty=False) | |
130 | enable_locking = v.StringBoolean(if_missing=False) |
|
130 | enable_locking = v.StringBoolean(if_missing=False) | |
|
131 | recursive = v.StringBoolean(if_missing=False) | |||
131 | chained_validators = [v.ValidReposGroup(edit, old_data), |
|
132 | chained_validators = [v.ValidReposGroup(edit, old_data), | |
132 | v.ValidPerms('group')] |
|
133 | v.ValidPerms('group')] | |
133 |
|
134 | |||
@@ -340,4 +341,4 b' def PullRequestForm():' | |||||
340 | pullrequest_title = v.UnicodeString(strip=True, required=True, min=3) |
|
341 | pullrequest_title = v.UnicodeString(strip=True, required=True, min=3) | |
341 | pullrequest_desc = v.UnicodeString(strip=True, required=False) |
|
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 | TYPE_PASSWORD_RESET = 'passoword_link' |
|
245 | TYPE_PASSWORD_RESET = 'passoword_link' | |
246 | TYPE_REGISTRATION = Notification.TYPE_REGISTRATION |
|
246 | TYPE_REGISTRATION = Notification.TYPE_REGISTRATION | |
247 | TYPE_PULL_REQUEST = Notification.TYPE_PULL_REQUEST |
|
247 | TYPE_PULL_REQUEST = Notification.TYPE_PULL_REQUEST | |
|
248 | TYPE_PULL_REQUEST_COMMENT = Notification.TYPE_PULL_REQUEST_COMMENT | |||
248 | TYPE_DEFAULT = 'default' |
|
249 | TYPE_DEFAULT = 'default' | |
249 |
|
250 | |||
250 | def __init__(self): |
|
251 | def __init__(self): | |
@@ -255,7 +256,9 b' class EmailNotificationModel(BaseModel):' | |||||
255 | self.TYPE_CHANGESET_COMMENT: 'email_templates/changeset_comment.html', |
|
256 | self.TYPE_CHANGESET_COMMENT: 'email_templates/changeset_comment.html', | |
256 | self.TYPE_PASSWORD_RESET: 'email_templates/password_reset.html', |
|
257 | self.TYPE_PASSWORD_RESET: 'email_templates/password_reset.html', | |
257 | self.TYPE_REGISTRATION: 'email_templates/registration.html', |
|
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 | def get_email_tmpl(self, type_, **kwargs): |
|
264 | def get_email_tmpl(self, type_, **kwargs): |
@@ -77,7 +77,7 b' class PermissionModel(BaseModel):' | |||||
77 | form_result['perm_user_name']).scalar() |
|
77 | form_result['perm_user_name']).scalar() | |
78 | u2p = self.sa.query(UserToPerm).filter(UserToPerm.user == |
|
78 | u2p = self.sa.query(UserToPerm).filter(UserToPerm.user == | |
79 | perm_user).all() |
|
79 | perm_user).all() | |
80 |
if len(u2p) != |
|
80 | if len(u2p) != len(User.DEFAULT_PERMISSIONS): | |
81 | raise Exception('Defined: %s should be 4 permissions for default' |
|
81 | raise Exception('Defined: %s should be 4 permissions for default' | |
82 | ' user. This should not happen please verify' |
|
82 | ' user. This should not happen please verify' | |
83 | ' your database' % len(u2p)) |
|
83 | ' your database' % len(u2p)) |
@@ -36,7 +36,8 b' from rhodecode.model.db import PullReque' | |||||
36 | from rhodecode.model.notification import NotificationModel |
|
36 | from rhodecode.model.notification import NotificationModel | |
37 | from rhodecode.lib.utils2 import safe_unicode |
|
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 | log = logging.getLogger(__name__) |
|
42 | log = logging.getLogger(__name__) | |
42 |
|
43 | |||
@@ -79,22 +80,30 b' class PullRequestModel(BaseModel):' | |||||
79 | #notification to reviewers |
|
80 | #notification to reviewers | |
80 | notif = NotificationModel() |
|
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 | subject = safe_unicode( |
|
87 | subject = safe_unicode( | |
83 | h.link_to( |
|
88 | h.link_to( | |
84 | _('%(user)s wants you to review pull request #%(pr_id)s') % \ |
|
89 | _('%(user)s wants you to review pull request #%(pr_id)s') % \ | |
85 | {'user': created_by_user.username, |
|
90 | {'user': created_by_user.username, | |
86 | 'pr_id': new.pull_request_id}, |
|
91 | 'pr_id': new.pull_request_id}, | |
87 | h.url('pullrequest_show', repo_name=other_repo.repo_name, |
|
92 | pr_url | |
88 | pull_request_id=new.pull_request_id, |
|
|||
89 | qualified=True, |
|
|||
90 | ) |
|
|||
91 | ) |
|
93 | ) | |
92 | ) |
|
94 | ) | |
93 | body = description |
|
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 | notif.create(created_by=created_by_user, subject=subject, body=body, |
|
104 | notif.create(created_by=created_by_user, subject=subject, body=body, | |
95 | recipients=reviewers, |
|
105 | recipients=reviewers, | |
96 | type_=Notification.TYPE_PULL_REQUEST,) |
|
106 | type_=Notification.TYPE_PULL_REQUEST, email_kwargs=kwargs) | |
97 |
|
||||
98 | return new |
|
107 | return new | |
99 |
|
108 | |||
100 | def update_reviewers(self, pull_request, reviewers_ids): |
|
109 | def update_reviewers(self, pull_request, reviewers_ids): | |
@@ -156,7 +165,10 b' class PullRequestModel(BaseModel):' | |||||
156 | #case two independent repos |
|
165 | #case two independent repos | |
157 | common, incoming, rheads = discovery_data |
|
166 | common, incoming, rheads = discovery_data | |
158 | if org_repo != other_repo and incoming: |
|
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 | for cs in reversed(map(binascii.hexlify, revs)): |
|
173 | for cs in reversed(map(binascii.hexlify, revs)): | |
162 | changesets.append(org_repo.get_changeset(cs)) |
|
174 | changesets.append(org_repo.get_changeset(cs)) | |
@@ -205,6 +217,7 b' class PullRequestModel(BaseModel):' | |||||
205 | log.debug('Doing discovery for %s@%s vs %s@%s' % ( |
|
217 | log.debug('Doing discovery for %s@%s vs %s@%s' % ( | |
206 | org_repo, org_ref, other_repo, other_ref) |
|
218 | org_repo, org_ref, other_repo, other_ref) | |
207 | ) |
|
219 | ) | |
|
220 | ||||
208 | #log.debug('Filter heads are %s[%s]' % ('', org_ref[1])) |
|
221 | #log.debug('Filter heads are %s[%s]' % ('', org_ref[1])) | |
209 | org_peer = localrepo.locallegacypeer(_org_repo.local()) |
|
222 | org_peer = localrepo.locallegacypeer(_org_repo.local()) | |
210 | tmp = discovery.findcommonincoming( |
|
223 | tmp = discovery.findcommonincoming( | |
@@ -212,7 +225,7 b' class PullRequestModel(BaseModel):' | |||||
212 | remote=org_peer, # org_repo source for incoming |
|
225 | remote=org_peer, # org_repo source for incoming | |
213 | heads=[_other_repo[other_rev].node(), |
|
226 | heads=[_other_repo[other_rev].node(), | |
214 | _org_repo[org_rev].node()], |
|
227 | _org_repo[org_rev].node()], | |
215 |
force= |
|
228 | force=True | |
216 | ) |
|
229 | ) | |
217 | return tmp |
|
230 | return tmp | |
218 |
|
231 |
@@ -368,6 +368,7 b' class RepoModel(BaseModel):' | |||||
368 | obj.user = user |
|
368 | obj.user = user | |
369 | obj.permission = permission |
|
369 | obj.permission = permission | |
370 | self.sa.add(obj) |
|
370 | self.sa.add(obj) | |
|
371 | log.debug('Granted perm %s to %s on %s' % (perm, user, repo)) | |||
371 |
|
372 | |||
372 | def revoke_user_permission(self, repo, user): |
|
373 | def revoke_user_permission(self, repo, user): | |
373 | """ |
|
374 | """ | |
@@ -383,8 +384,10 b' class RepoModel(BaseModel):' | |||||
383 | obj = self.sa.query(UserRepoToPerm)\ |
|
384 | obj = self.sa.query(UserRepoToPerm)\ | |
384 | .filter(UserRepoToPerm.repository == repo)\ |
|
385 | .filter(UserRepoToPerm.repository == repo)\ | |
385 | .filter(UserRepoToPerm.user == user)\ |
|
386 | .filter(UserRepoToPerm.user == user)\ | |
386 |
. |
|
387 | .scalar() | |
387 | self.sa.delete(obj) |
|
388 | if obj: | |
|
389 | self.sa.delete(obj) | |||
|
390 | log.debug('Revoked perm on %s on %s' % (repo, user)) | |||
388 |
|
391 | |||
389 | def grant_users_group_permission(self, repo, group_name, perm): |
|
392 | def grant_users_group_permission(self, repo, group_name, perm): | |
390 | """ |
|
393 | """ | |
@@ -414,6 +417,7 b' class RepoModel(BaseModel):' | |||||
414 | obj.users_group = group_name |
|
417 | obj.users_group = group_name | |
415 | obj.permission = permission |
|
418 | obj.permission = permission | |
416 | self.sa.add(obj) |
|
419 | self.sa.add(obj) | |
|
420 | log.debug('Granted perm %s to %s on %s' % (perm, group_name, repo)) | |||
417 |
|
421 | |||
418 | def revoke_users_group_permission(self, repo, group_name): |
|
422 | def revoke_users_group_permission(self, repo, group_name): | |
419 | """ |
|
423 | """ | |
@@ -429,8 +433,10 b' class RepoModel(BaseModel):' | |||||
429 | obj = self.sa.query(UsersGroupRepoToPerm)\ |
|
433 | obj = self.sa.query(UsersGroupRepoToPerm)\ | |
430 | .filter(UsersGroupRepoToPerm.repository == repo)\ |
|
434 | .filter(UsersGroupRepoToPerm.repository == repo)\ | |
431 | .filter(UsersGroupRepoToPerm.users_group == group_name)\ |
|
435 | .filter(UsersGroupRepoToPerm.users_group == group_name)\ | |
432 |
. |
|
436 | .scalar() | |
433 | self.sa.delete(obj) |
|
437 | if obj: | |
|
438 | self.sa.delete(obj) | |||
|
439 | log.debug('Revoked perm to %s on %s' % (repo, group_name)) | |||
434 |
|
440 | |||
435 | def delete_stats(self, repo_name): |
|
441 | def delete_stats(self, repo_name): | |
436 | """ |
|
442 | """ |
@@ -32,7 +32,7 b' from rhodecode.lib.utils2 import LazyPro' | |||||
32 |
|
32 | |||
33 | from rhodecode.model import BaseModel |
|
33 | from rhodecode.model import BaseModel | |
34 | from rhodecode.model.db import RepoGroup, RhodeCodeUi, UserRepoGroupToPerm, \ |
|
34 | from rhodecode.model.db import RepoGroup, RhodeCodeUi, UserRepoGroupToPerm, \ | |
35 | User, Permission, UsersGroupRepoGroupToPerm, UsersGroup |
|
35 | User, Permission, UsersGroupRepoGroupToPerm, UsersGroup, Repository | |
36 |
|
36 | |||
37 | log = logging.getLogger(__name__) |
|
37 | log = logging.getLogger(__name__) | |
38 |
|
38 | |||
@@ -115,11 +115,12 b' class ReposGroupModel(BaseModel):' | |||||
115 | 'existing dir %s' % new_path) |
|
115 | 'existing dir %s' % new_path) | |
116 | shutil.move(old_path, new_path) |
|
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 | Deletes a group from a filesystem |
|
120 | Deletes a group from a filesystem | |
121 |
|
121 | |||
122 | :param group: instance of group from database |
|
122 | :param group: instance of group from database | |
|
123 | :param force_delete: use shutil rmtree to remove all objects | |||
123 | """ |
|
124 | """ | |
124 | paths = group.full_path.split(RepoGroup.url_sep()) |
|
125 | paths = group.full_path.split(RepoGroup.url_sep()) | |
125 | paths = os.sep.join(paths) |
|
126 | paths = os.sep.join(paths) | |
@@ -127,7 +128,10 b' class ReposGroupModel(BaseModel):' | |||||
127 | rm_path = os.path.join(self.repos_path, paths) |
|
128 | rm_path = os.path.join(self.repos_path, paths) | |
128 | if os.path.isdir(rm_path): |
|
129 | if os.path.isdir(rm_path): | |
129 | # delete only if that path really exists |
|
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 | def create(self, group_name, group_description, parent=None, just_db=False): |
|
136 | def create(self, group_name, group_description, parent=None, just_db=False): | |
133 | try: |
|
137 | try: | |
@@ -150,32 +154,79 b' class ReposGroupModel(BaseModel):' | |||||
150 | log.error(traceback.format_exc()) |
|
154 | log.error(traceback.format_exc()) | |
151 | raise |
|
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 | def update(self, repos_group_id, form_data): |
|
220 | def update(self, repos_group_id, form_data): | |
154 |
|
221 | |||
155 | try: |
|
222 | try: | |
156 | repos_group = RepoGroup.get(repos_group_id) |
|
223 | repos_group = RepoGroup.get(repos_group_id) | |
157 |
|
224 | recursive = form_data['recursive'] | ||
158 | # update permissions |
|
225 | # iterate over all members(if in recursive mode) of this groups and | |
159 | for member, perm, member_type in form_data['perms_updates']: |
|
226 | # set the permissions ! | |
160 | if member_type == 'user': |
|
227 | # this can be potentially heavy operation | |
161 | # this updates also current one if found |
|
228 | self._update_permissions(repos_group, form_data['perms_new'], | |
162 | ReposGroupModel().grant_user_permission( |
|
229 | form_data['perms_updates'], recursive) | |
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 | ) |
|
|||
179 |
|
230 | |||
180 | old_path = repos_group.full_path |
|
231 | old_path = repos_group.full_path | |
181 |
|
232 | |||
@@ -191,7 +242,6 b' class ReposGroupModel(BaseModel):' | |||||
191 |
|
242 | |||
192 | # iterate over all members of this groups and set the locking ! |
|
243 | # iterate over all members of this groups and set the locking ! | |
193 | # this can be potentially heavy operation |
|
244 | # this can be potentially heavy operation | |
194 |
|
||||
195 | for obj in repos_group.recursive_groups_and_repos(): |
|
245 | for obj in repos_group.recursive_groups_and_repos(): | |
196 | #set the value from it's parent |
|
246 | #set the value from it's parent | |
197 | obj.enable_locking = repos_group.enable_locking |
|
247 | obj.enable_locking = repos_group.enable_locking | |
@@ -210,15 +260,54 b' class ReposGroupModel(BaseModel):' | |||||
210 | log.error(traceback.format_exc()) |
|
260 | log.error(traceback.format_exc()) | |
211 | raise |
|
261 | raise | |
212 |
|
262 | |||
213 | def delete(self, repos_group): |
|
263 | def delete(self, repos_group, force_delete=False): | |
214 | repos_group = self._get_repos_group(repos_group) |
|
264 | repos_group = self._get_repos_group(repos_group) | |
215 | try: |
|
265 | try: | |
216 | self.sa.delete(repos_group) |
|
266 | self.sa.delete(repos_group) | |
217 | self.__delete_group(repos_group) |
|
267 | self.__delete_group(repos_group, force_delete) | |
218 | except: |
|
268 | except: | |
219 | log.exception('Error removing repos_group %s' % repos_group) |
|
269 | log.exception('Error removing repos_group %s' % repos_group) | |
220 | raise |
|
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 | def grant_user_permission(self, repos_group, user, perm): |
|
311 | def grant_user_permission(self, repos_group, user, perm): | |
223 | """ |
|
312 | """ | |
224 | Grant permission for user on given repositories group, or update |
|
313 | Grant permission for user on given repositories group, or update | |
@@ -246,6 +335,7 b' class ReposGroupModel(BaseModel):' | |||||
246 | obj.user = user |
|
335 | obj.user = user | |
247 | obj.permission = permission |
|
336 | obj.permission = permission | |
248 | self.sa.add(obj) |
|
337 | self.sa.add(obj) | |
|
338 | log.debug('Granted perm %s to %s on %s' % (perm, user, repos_group)) | |||
249 |
|
339 | |||
250 | def revoke_user_permission(self, repos_group, user): |
|
340 | def revoke_user_permission(self, repos_group, user): | |
251 | """ |
|
341 | """ | |
@@ -262,8 +352,10 b' class ReposGroupModel(BaseModel):' | |||||
262 | obj = self.sa.query(UserRepoGroupToPerm)\ |
|
352 | obj = self.sa.query(UserRepoGroupToPerm)\ | |
263 | .filter(UserRepoGroupToPerm.user == user)\ |
|
353 | .filter(UserRepoGroupToPerm.user == user)\ | |
264 | .filter(UserRepoGroupToPerm.group == repos_group)\ |
|
354 | .filter(UserRepoGroupToPerm.group == repos_group)\ | |
265 |
. |
|
355 | .scalar() | |
266 | self.sa.delete(obj) |
|
356 | if obj: | |
|
357 | self.sa.delete(obj) | |||
|
358 | log.debug('Revoked perm on %s on %s' % (repos_group, user)) | |||
267 |
|
359 | |||
268 | def grant_users_group_permission(self, repos_group, group_name, perm): |
|
360 | def grant_users_group_permission(self, repos_group, group_name, perm): | |
269 | """ |
|
361 | """ | |
@@ -294,6 +386,7 b' class ReposGroupModel(BaseModel):' | |||||
294 | obj.users_group = group_name |
|
386 | obj.users_group = group_name | |
295 | obj.permission = permission |
|
387 | obj.permission = permission | |
296 | self.sa.add(obj) |
|
388 | self.sa.add(obj) | |
|
389 | log.debug('Granted perm %s to %s on %s' % (perm, group_name, repos_group)) | |||
297 |
|
390 | |||
298 | def revoke_users_group_permission(self, repos_group, group_name): |
|
391 | def revoke_users_group_permission(self, repos_group, group_name): | |
299 | """ |
|
392 | """ | |
@@ -310,5 +403,7 b' class ReposGroupModel(BaseModel):' | |||||
310 | obj = self.sa.query(UsersGroupRepoGroupToPerm)\ |
|
403 | obj = self.sa.query(UsersGroupRepoGroupToPerm)\ | |
311 | .filter(UsersGroupRepoGroupToPerm.group == repos_group)\ |
|
404 | .filter(UsersGroupRepoGroupToPerm.group == repos_group)\ | |
312 | .filter(UsersGroupRepoGroupToPerm.users_group == group_name)\ |
|
405 | .filter(UsersGroupRepoGroupToPerm.users_group == group_name)\ | |
313 |
. |
|
406 | .scalar() | |
314 | self.sa.delete(obj) |
|
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 | rg_k = perm.UserRepoGroupToPerm.group.group_name |
|
564 | rg_k = perm.UserRepoGroupToPerm.group.group_name | |
565 | p = perm.Permission.permission_name |
|
565 | p = perm.Permission.permission_name | |
566 | cur_perm = user.permissions[GK][rg_k] |
|
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 | user.permissions[GK][rg_k] = p |
|
568 | user.permissions[GK][rg_k] = p | |
569 |
|
569 | |||
570 | # REPO GROUP + USER GROUP |
|
570 | # REPO GROUP + USER GROUP | |
@@ -588,7 +588,7 b' class UserModel(BaseModel):' | |||||
588 | cur_perm = user.permissions[GK][g_k] |
|
588 | cur_perm = user.permissions[GK][g_k] | |
589 | # overwrite permission only if it's greater than permission |
|
589 | # overwrite permission only if it's greater than permission | |
590 | # given from other sources |
|
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 | user.permissions[GK][g_k] = p |
|
592 | user.permissions[GK][g_k] = p | |
593 |
|
593 | |||
594 | return user |
|
594 | return user |
@@ -499,9 +499,9 b" def ValidPerms(type_='repo'):" | |||||
499 | # fill new permissions in order of how they were added |
|
499 | # fill new permissions in order of how they were added | |
500 | for k in sorted(map(int, new_perms_group.keys())): |
|
500 | for k in sorted(map(int, new_perms_group.keys())): | |
501 | perm_dict = new_perms_group[str(k)] |
|
501 | perm_dict = new_perms_group[str(k)] | |
502 |
new_member = perm_dict |
|
502 | new_member = perm_dict.get('name') | |
503 |
new_perm = perm_dict |
|
503 | new_perm = perm_dict.get('perm') | |
504 |
new_type = perm_dict |
|
504 | new_type = perm_dict.get('type') | |
505 | if new_member and new_perm and new_type: |
|
505 | if new_member and new_perm and new_type: | |
506 | perms_new.add((new_member, new_perm, new_type)) |
|
506 | perms_new.add((new_member, new_perm, new_type)) | |
507 |
|
507 |
@@ -115,7 +115,7 b'' | |||||
115 | ${h.checkbox('enable_locking',value="True")} |
|
115 | ${h.checkbox('enable_locking',value="True")} | |
116 | <span class="help-block">${_('Enable lock-by-pulling on repository.')}</span> |
|
116 | <span class="help-block">${_('Enable lock-by-pulling on repository.')}</span> | |
117 | </div> |
|
117 | </div> | |
118 |
</div> |
|
118 | </div> | |
119 | <div class="field"> |
|
119 | <div class="field"> | |
120 | <div class="label"> |
|
120 | <div class="label"> | |
121 | <label for="user">${_('Owner')}:</label> |
|
121 | <label for="user">${_('Owner')}:</label> | |
@@ -188,6 +188,20 b'' | |||||
188 | <div class="form"> |
|
188 | <div class="form"> | |
189 | <div class="fields"> |
|
189 | <div class="fields"> | |
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')+"');")} |
|
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 | </div> |
|
205 | </div> | |
192 | </div> |
|
206 | </div> | |
193 | ${h.end_form()} |
|
207 | ${h.end_form()} | |
@@ -195,20 +209,20 b'' | |||||
195 | <h3>${_('Public journal')}</h3> |
|
209 | <h3>${_('Public journal')}</h3> | |
196 | ${h.form(url('repo_public_journal', repo_name=c.repo_info.repo_name),method='put')} |
|
210 | ${h.form(url('repo_public_journal', repo_name=c.repo_info.repo_name),method='put')} | |
197 | <div class="form"> |
|
211 | <div class="form"> | |
198 |
|
|
212 | ${h.hidden('auth_token',str(h.get_token()))} | |
199 |
|
|
213 | <div class="field"> | |
200 |
|
|
214 | %if c.in_public_journal: | |
201 |
|
|
215 | ${h.submit('set_public_%s' % c.repo_info.repo_name,_('Remove from public journal'),class_="ui-btn")} | |
202 |
|
|
216 | %else: | |
203 |
|
|
217 | ${h.submit('set_public_%s' % c.repo_info.repo_name,_('Add to public journal'),class_="ui-btn")} | |
204 |
|
|
218 | %endif | |
205 |
|
|
219 | </div> | |
206 |
|
|
220 | <div class="field" style="border:none;color:#888"> | |
207 |
|
|
221 | <ul> | |
208 |
|
|
222 | <li>${_('All actions made on this repository will be accessible to everyone in public journal')} | |
209 |
|
|
223 | </li> | |
210 |
|
|
224 | </ul> | |
211 |
|
|
225 | </div> | |
212 | </div> |
|
226 | </div> | |
213 | ${h.end_form()} |
|
227 | ${h.end_form()} | |
214 |
|
228 | |||
@@ -229,7 +243,7 b'' | |||||
229 | <li>${_('Force locking on repository. Works only when anonymous access is disabled')} |
|
243 | <li>${_('Force locking on repository. Works only when anonymous access is disabled')} | |
230 | </li> |
|
244 | </li> | |
231 | </ul> |
|
245 | </ul> | |
232 |
</div> |
|
246 | </div> | |
233 | </div> |
|
247 | </div> | |
234 | ${h.end_form()} |
|
248 | ${h.end_form()} | |
235 |
|
249 | |||
@@ -245,9 +259,9 b'' | |||||
245 | <li>${_('''Manually set this repository as a fork of another from the list''')}</li> |
|
259 | <li>${_('''Manually set this repository as a fork of another from the list''')}</li> | |
246 | </ul> |
|
260 | </ul> | |
247 | </div> |
|
261 | </div> | |
248 |
</div> |
|
262 | </div> | |
249 | ${h.end_form()} |
|
263 | ${h.end_form()} | |
250 |
|
264 | |||
251 | <h3>${_('Delete')}</h3> |
|
265 | <h3>${_('Delete')}</h3> | |
252 | ${h.form(url('repo', repo_name=c.repo_info.repo_name),method='delete')} |
|
266 | ${h.form(url('repo', repo_name=c.repo_info.repo_name),method='delete')} | |
253 | <div class="form"> |
|
267 | <div class="form"> | |
@@ -262,7 +276,7 b'' | |||||
262 | </ul> |
|
276 | </ul> | |
263 | </div> |
|
277 | </div> | |
264 | </div> |
|
278 | </div> | |
265 |
${h.end_form()} |
|
279 | ${h.end_form()} | |
266 | </div> |
|
280 | </div> | |
267 |
|
281 | |||
268 | </%def> |
|
282 | </%def> |
@@ -74,8 +74,8 b'' | |||||
74 | </div> \ |
|
74 | </div> \ | |
75 | </td> \ |
|
75 | </td> \ | |
76 | <td></td>'""") |
|
76 | <td></td>'""") | |
77 |
%> |
|
77 | %> | |
78 |
## ADD HERE DYNAMICALLY NEW INPUTS FROM THE '_tmpl' |
|
78 | ## ADD HERE DYNAMICALLY NEW INPUTS FROM THE '_tmpl' | |
79 | <tr class="new_members last_new_member" id="add_perm_input"></tr> |
|
79 | <tr class="new_members last_new_member" id="add_perm_input"></tr> | |
80 | <tr> |
|
80 | <tr> | |
81 | <td colspan="6"> |
|
81 | <td colspan="6"> |
@@ -58,8 +58,8 b'' | |||||
58 | </div> \ |
|
58 | </div> \ | |
59 | </td> \ |
|
59 | </td> \ | |
60 | <td></td>'""") |
|
60 | <td></td>'""") | |
61 |
%> |
|
61 | %> | |
62 |
## ADD HERE DYNAMICALLY NEW INPUTS FROM THE '_tmpl' |
|
62 | ## ADD HERE DYNAMICALLY NEW INPUTS FROM THE '_tmpl' | |
63 | <tr class="new_members last_new_member" id="add_perm_input"></tr> |
|
63 | <tr class="new_members last_new_member" id="add_perm_input"></tr> | |
64 | <tr> |
|
64 | <tr> | |
65 | <td colspan="6"> |
|
65 | <td colspan="6"> | |
@@ -68,6 +68,12 b'' | |||||
68 | </span> |
|
68 | </span> | |
69 | </td> |
|
69 | </td> | |
70 | </tr> |
|
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 | </table> |
|
77 | </table> | |
72 | <script type="text/javascript"> |
|
78 | <script type="text/javascript"> | |
73 | function ajaxActionUser(user_id, field_id) { |
|
79 | function ajaxActionUser(user_id, field_id) { | |
@@ -81,7 +87,8 b' function ajaxActionUser(user_id, field_i' | |||||
81 | alert("${_('Failed to remove user')}"); |
|
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 | var request = YAHOO.util.Connect.asyncRequest('POST', sUrl, callback, postData); |
|
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 | alert("${_('Failed to remove users group')}"); |
|
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 | var request = YAHOO.util.Connect.asyncRequest('POST', sUrl, callback, postData); |
|
108 | var request = YAHOO.util.Connect.asyncRequest('POST', sUrl, callback, postData); | |
101 | }; |
|
109 | }; | |
102 |
|
110 |
@@ -5,7 +5,8 b'' | |||||
5 | </%def> |
|
5 | </%def> | |
6 |
|
6 | |||
7 | <%def name="breadcrumbs()"> |
|
7 | <%def name="breadcrumbs()"> | |
8 |
<span class="groups_breadcrumbs"> |
|
8 | <span class="groups_breadcrumbs"> | |
|
9 | ${h.link_to(_(u'Home'),h.url('/'))} | |||
9 | %if c.group.parent_group: |
|
10 | %if c.group.parent_group: | |
10 | » ${h.link_to(c.group.parent_group.name,h.url('repos_group_home',group_name=c.group.parent_group.group_name))} |
|
11 | » ${h.link_to(c.group.parent_group.name,h.url('repos_group_home',group_name=c.group.parent_group.group_name))} | |
11 | %endif |
|
12 | %endif |
@@ -69,7 +69,7 b'' | |||||
69 | ${h.checkbox('enable_locking',value="True")} |
|
69 | ${h.checkbox('enable_locking',value="True")} | |
70 | <span class="help-block">${_('Enable lock-by-pulling on group. This option will be applied to all other groups and repositories inside')}</span> |
|
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 | </div> |
|
71 | </div> | |
72 |
</div> |
|
72 | </div> | |
73 | <div class="buttons"> |
|
73 | <div class="buttons"> | |
74 | ${h.submit('save',_('Save'),class_="ui-btn large")} |
|
74 | ${h.submit('save',_('Save'),class_="ui-btn large")} | |
75 | ${h.reset('reset',_('Reset'),class_="ui-btn large")} |
|
75 | ${h.reset('reset',_('Reset'),class_="ui-btn large")} |
@@ -154,7 +154,7 b'' | |||||
154 | <li>[stale] <span class="metatag" tag="stale">stale</span></li> |
|
154 | <li>[stale] <span class="metatag" tag="stale">stale</span></li> | |
155 | <li>[dead] <span class="metatag" tag="dead">dead</span></li> |
|
155 | <li>[dead] <span class="metatag" tag="dead">dead</span></li> | |
156 | <li>[lang => lang] <span class="metatag" tag="lang" >lang</span></li> |
|
156 | <li>[lang => lang] <span class="metatag" tag="lang" >lang</span></li> | |
157 |
<li>[license => License] <span class="metatag" tag="license"><a href="http://www.opensource.org/licenses/License" >License</a></span></li> |
|
157 | <li>[license => License] <span class="metatag" tag="license"><a href="http://www.opensource.org/licenses/License" >License</a></span></li> | |
158 | <li>[requires => Repo] <span class="metatag" tag="requires" >requires => <a href="#" >Repo</a></span></li> |
|
158 | <li>[requires => Repo] <span class="metatag" tag="requires" >requires => <a href="#" >Repo</a></span></li> | |
159 | <li>[recommends => Repo] <span class="metatag" tag="recommends" >recommends => <a href="#" >Repo</a></span></li> |
|
159 | <li>[recommends => Repo] <span class="metatag" tag="recommends" >recommends => <a href="#" >Repo</a></span></li> | |
160 | <li>[see => URI] <span class="metatag" tag="see">see => <a href="#">URI</a> </span></li> |
|
160 | <li>[see => URI] <span class="metatag" tag="see">see => <a href="#">URI</a> </span></li> | |
@@ -186,7 +186,7 b'' | |||||
186 | </div> |
|
186 | </div> | |
187 | <div class="checkboxes"> |
|
187 | <div class="checkboxes"> | |
188 | <div class="checkbox"> |
|
188 | <div class="checkbox"> | |
189 |
${h.checkbox('web_push_ssl', |
|
189 | ${h.checkbox('web_push_ssl', 'True')} | |
190 | <label for="web_push_ssl">${_('require ssl for vcs operations')}</label> |
|
190 | <label for="web_push_ssl">${_('require ssl for vcs operations')}</label> | |
191 | </div> |
|
191 | </div> | |
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> |
|
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 | ## ${h.checkbox('extensions_hggit','True')} |
|
237 | ## ${h.checkbox('extensions_hggit','True')} | |
238 | ## <label for="extensions_hggit">${_('hg-git extensions')}</label> |
|
238 | ## <label for="extensions_hggit">${_('hg-git extensions')}</label> | |
239 | ##</div> |
|
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 | </div> |
|
241 | </div> | |
242 |
</div> |
|
242 | </div> | |
243 | <div class="field"> |
|
243 | <div class="field"> | |
244 | <div class="label"> |
|
244 | <div class="label"> | |
245 | <label for="paths_root_path">${_('Repositories location')}:</label> |
|
245 | <label for="paths_root_path">${_('Repositories location')}:</label> |
@@ -152,7 +152,7 b'' | |||||
152 | <span class="help-block">${h.literal(_('Select to inherit permissions from %s settings. ' |
|
152 | <span class="help-block">${h.literal(_('Select to inherit permissions from %s settings. ' | |
153 | 'With this selected below options does not have any action') % h.link_to('default', url('edit_permission', id='default')))}</span> |
|
153 | 'With this selected below options does not have any action') % h.link_to('default', url('edit_permission', id='default')))}</span> | |
154 | </div> |
|
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 | <div class="field"> |
|
156 | <div class="field"> | |
157 | <div class="label label-checkbox"> |
|
157 | <div class="label label-checkbox"> | |
158 | <label for="create_repo_perm">${_('Create repositories')}:</label> |
|
158 | <label for="create_repo_perm">${_('Create repositories')}:</label> | |
@@ -169,7 +169,7 b'' | |||||
169 | ${h.checkbox('fork_repo_perm',value=True)} |
|
169 | ${h.checkbox('fork_repo_perm',value=True)} | |
170 | </div> |
|
170 | </div> | |
171 | </div> |
|
171 | </div> | |
172 |
</div> |
|
172 | </div> | |
173 | <div class="buttons"> |
|
173 | <div class="buttons"> | |
174 | ${h.submit('save',_('Save'),class_="ui-btn large")} |
|
174 | ${h.submit('save',_('Save'),class_="ui-btn large")} | |
175 | ${h.reset('reset',_('Reset'),class_="ui-btn large")} |
|
175 | ${h.reset('reset',_('Reset'),class_="ui-btn large")} |
@@ -112,7 +112,7 b'' | |||||
112 | </div> |
|
112 | </div> | |
113 | <span class="help-block">${h.literal(_('Select to inherit permissions from %s settings. ' |
|
113 | <span class="help-block">${h.literal(_('Select to inherit permissions from %s settings. ' | |
114 | 'With this selected below options does not have any action') % h.link_to('default', url('edit_permission', id='default')))}</span> |
|
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 | <div id="inherit_overlay" style="${'opacity:0.3' if c.users_group.inherit_default_permissions else ''}" > |
|
116 | <div id="inherit_overlay" style="${'opacity:0.3' if c.users_group.inherit_default_permissions else ''}" > | |
117 | <div class="field"> |
|
117 | <div class="field"> | |
118 | <div class="label label-checkbox"> |
|
118 | <div class="label label-checkbox"> | |
@@ -130,7 +130,7 b'' | |||||
130 | ${h.checkbox('fork_repo_perm',value=True)} |
|
130 | ${h.checkbox('fork_repo_perm',value=True)} | |
131 | </div> |
|
131 | </div> | |
132 | </div> |
|
132 | </div> | |
133 |
</div> |
|
133 | </div> | |
134 | <div class="buttons"> |
|
134 | <div class="buttons"> | |
135 | ${h.submit('save',_('Save'),class_="ui-btn large")} |
|
135 | ${h.submit('save',_('Save'),class_="ui-btn large")} | |
136 | ${h.reset('reset',_('Reset'),class_="ui-btn large")} |
|
136 | ${h.reset('reset',_('Reset'),class_="ui-btn large")} |
@@ -90,7 +90,7 b'' | |||||
90 | f.setAttribute('class','follow'); |
|
90 | f.setAttribute('class','follow'); | |
91 | f.setAttribute('title',_TM['Start following this repository']); |
|
91 | f.setAttribute('title',_TM['Start following this repository']); | |
92 | if(f_cnt){ |
|
92 | if(f_cnt){ | |
93 |
var cnt = Number(f_cnt.innerHTML) |
|
93 | var cnt = Number(f_cnt.innerHTML)-1; | |
94 | f_cnt.innerHTML = cnt; |
|
94 | f_cnt.innerHTML = cnt; | |
95 | } |
|
95 | } | |
96 | } |
|
96 | } |
@@ -47,38 +47,38 b' var url_base = \'${h.url("files_nodelist_' | |||||
47 |
|
47 | |||
48 | var ypjax_links = function(){ |
|
48 | var ypjax_links = function(){ | |
49 | YUE.on(YUQ('.ypjax-link'), 'click',function(e){ |
|
49 | YUE.on(YUQ('.ypjax-link'), 'click',function(e){ | |
50 |
|
50 | |||
51 | //don't do ypjax on middle click |
|
51 | //don't do ypjax on middle click | |
52 |
if(e.which == 2 || !History.enabled){ |
|
52 | if(e.which == 2 || !History.enabled){ | |
53 | return true; |
|
53 | return true; | |
54 | } |
|
54 | } | |
55 |
|
55 | |||
56 | var el = e.currentTarget; |
|
56 | var el = e.currentTarget; | |
57 | var url = el.href; |
|
57 | var url = el.href; | |
58 |
|
58 | |||
59 | var _base_url = '${h.url("files_home",repo_name=c.repo_name,revision='',f_path='')}'; |
|
59 | var _base_url = '${h.url("files_home",repo_name=c.repo_name,revision='',f_path='')}'; | |
60 | _base_url = _base_url.replace('//','/') |
|
60 | _base_url = _base_url.replace('//','/') | |
61 |
|
61 | |||
62 | //extract rev and the f_path from url. |
|
62 | //extract rev and the f_path from url. | |
63 | parts = url.split(_base_url) |
|
63 | parts = url.split(_base_url) | |
64 | if(parts.length != 2){ |
|
64 | if(parts.length != 2){ | |
65 | return false; |
|
65 | return false; | |
66 | } |
|
66 | } | |
67 |
|
67 | |||
68 | var parts2 = parts[1].split('/'); |
|
68 | var parts2 = parts[1].split('/'); | |
69 | var rev = parts2.shift(); // pop the first element which is the revision |
|
69 | var rev = parts2.shift(); // pop the first element which is the revision | |
70 | var f_path = parts2.join('/'); |
|
70 | var f_path = parts2.join('/'); | |
71 |
|
71 | |||
72 | var title = "${_('%s files') % c.repo_name}" + " - " + f_path; |
|
72 | var title = "${_('%s files') % c.repo_name}" + " - " + f_path; | |
73 |
|
73 | |||
74 | var _node_list_url = node_list_url.replace('__REV__',rev); |
|
74 | var _node_list_url = node_list_url.replace('__REV__',rev); | |
75 | var _url_base = url_base.replace('__REV__',rev).replace('__FPATH__', f_path); |
|
75 | var _url_base = url_base.replace('__REV__',rev).replace('__FPATH__', f_path); | |
76 |
|
76 | |||
77 | // Change our States and save some data for handling events |
|
77 | // Change our States and save some data for handling events | |
78 | var data = {url:url,title:title, url_base:_url_base, |
|
78 | var data = {url:url,title:title, url_base:_url_base, | |
79 | node_list_url:_node_list_url}; |
|
79 | node_list_url:_node_list_url}; | |
80 |
History.pushState(data, title, url); |
|
80 | History.pushState(data, title, url); | |
81 |
|
81 | |||
82 | //now we're sure that we can do ypjax things |
|
82 | //now we're sure that we can do ypjax things | |
83 | YUE.preventDefault(e) |
|
83 | YUE.preventDefault(e) | |
84 | return false; |
|
84 | return false; | |
@@ -92,10 +92,10 b' var callbacks = function(State){' | |||||
92 | // Inform Google Analytics of the change |
|
92 | // Inform Google Analytics of the change | |
93 | if ( typeof window.pageTracker !== 'undefined' ) { |
|
93 | if ( typeof window.pageTracker !== 'undefined' ) { | |
94 | window.pageTracker._trackPageview(State.url); |
|
94 | window.pageTracker._trackPageview(State.url); | |
95 |
} |
|
95 | } | |
96 | } |
|
96 | } | |
97 |
|
97 | |||
98 |
YUE.onDOMReady(function(){ |
|
98 | YUE.onDOMReady(function(){ | |
99 | ypjax_links(); |
|
99 | ypjax_links(); | |
100 | var container = 'files_data'; |
|
100 | var container = 'files_data'; | |
101 | //Bind to StateChange Event |
|
101 | //Bind to StateChange Event | |
@@ -124,8 +124,8 b' YUE.onDOMReady(function(){' | |||||
124 | } |
|
124 | } | |
125 | }); |
|
125 | }); | |
126 | } |
|
126 | } | |
127 |
}); |
|
127 | }); | |
128 |
|
128 | |||
129 | // init the search filter |
|
129 | // init the search filter | |
130 | var _State = { |
|
130 | var _State = { | |
131 | url: "${h.url.current()}", |
|
131 | url: "${h.url.current()}", |
@@ -9,7 +9,7 b'' | |||||
9 | <%include file='files_browser.html'/> |
|
9 | <%include file='files_browser.html'/> | |
10 | %else: |
|
10 | %else: | |
11 | <%include file='files_source.html'/> |
|
11 | <%include file='files_source.html'/> | |
12 |
%endif |
|
12 | %endif | |
13 | %else: |
|
13 | %else: | |
14 | <h2> |
|
14 | <h2> | |
15 | <a href="#" onClick="javascript:parent.history.back();" target="main">${_('Go back')}</a> |
|
15 | <a href="#" onClick="javascript:parent.history.back();" target="main">${_('Go back')}</a> |
@@ -20,10 +20,10 b'' | |||||
20 | ${self.breadcrumbs()} |
|
20 | ${self.breadcrumbs()} | |
21 | </div> |
|
21 | </div> | |
22 | %if c.pull_request.is_closed(): |
|
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 | %endif |
|
24 | %endif | |
25 | <h3>${_('Title')}: ${c.pull_request.title}</h3> |
|
25 | <h3>${_('Title')}: ${c.pull_request.title}</h3> | |
26 |
|
26 | |||
27 | <div class="form"> |
|
27 | <div class="form"> | |
28 | <div id="summary" class="fields"> |
|
28 | <div id="summary" class="fields"> | |
29 | <div class="field"> |
|
29 | <div class="field"> | |
@@ -46,9 +46,9 b'' | |||||
46 | <div class="input"> |
|
46 | <div class="input"> | |
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> |
|
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 | </div> |
|
48 | </div> | |
49 |
</div> |
|
49 | </div> | |
50 | </div> |
|
50 | </div> | |
51 |
</div> |
|
51 | </div> | |
52 | <div style="white-space:pre-wrap;padding:3px 3px 5px 20px">${h.literal(c.pull_request.description)}</div> |
|
52 | <div style="white-space:pre-wrap;padding:3px 3px 5px 20px">${h.literal(c.pull_request.description)}</div> | |
53 | <div style="padding:4px 4px 10px 20px"> |
|
53 | <div style="padding:4px 4px 10px 20px"> | |
54 | <div>${_('Created on')}: ${h.fmt_date(c.pull_request.created_on)}</div> |
|
54 | <div>${_('Created on')}: ${h.fmt_date(c.pull_request.created_on)}</div> |
@@ -7,7 +7,7 b'' | |||||
7 | <%def name="breadcrumbs_links()"> |
|
7 | <%def name="breadcrumbs_links()"> | |
8 | ${h.link_to(_(u'Home'),h.url('/'))} |
|
8 | ${h.link_to(_(u'Home'),h.url('/'))} | |
9 | » |
|
9 | » | |
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 | » | |
12 | ${_('summary')} |
|
12 | ${_('summary')} | |
13 | </%def> |
|
13 | </%def> | |
@@ -108,7 +108,7 b'' | |||||
108 | <div class="input ${summary(c.show_stats)} desc">${h.urlify_text(h.desc_stylize(c.dbrepo.description))}</div> |
|
108 | <div class="input ${summary(c.show_stats)} desc">${h.urlify_text(h.desc_stylize(c.dbrepo.description))}</div> | |
109 | %else: |
|
109 | %else: | |
110 | <div class="input ${summary(c.show_stats)} desc">${h.urlify_text(c.dbrepo.description)}</div> |
|
110 | <div class="input ${summary(c.show_stats)} desc">${h.urlify_text(c.dbrepo.description)}</div> | |
111 |
%endif |
|
111 | %endif | |
112 | </div> |
|
112 | </div> | |
113 |
|
113 | |||
114 | <div class="field"> |
|
114 | <div class="field"> |
@@ -30,17 +30,17 b' class TestCompareController(TestControll' | |||||
30 | response.mustcontain('''<a href="/%s/changeset/c5ddebc06eaaba3010c2d66ea6ec9d074eb0f678">r112:c5ddebc06eaa</a>''' % HG_REPO) |
|
30 | response.mustcontain('''<a href="/%s/changeset/c5ddebc06eaaba3010c2d66ea6ec9d074eb0f678">r112:c5ddebc06eaa</a>''' % HG_REPO) | |
31 |
|
31 | |||
32 | ## files diff |
|
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, |
|
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, |
|
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, |
|
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, |
|
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, |
|
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, |
|
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, |
|
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, |
|
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, |
|
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, |
|
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, |
|
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 | def test_index_branch(self): |
|
45 | def test_index_branch(self): | |
46 | self.log_user() |
|
46 | self.log_user() | |
@@ -183,7 +183,111 b' class TestCompareController(TestControll' | |||||
183 | ## files |
|
183 | ## files | |
184 | response.mustcontain("""<a href="/%s/compare/branch@%s...branch@%s#C--826e8142e6ba">file1</a>""" % (r2_name, rev1, rev2)) |
|
184 | response.mustcontain("""<a href="/%s/compare/branch@%s...branch@%s#C--826e8142e6ba">file1</a>""" % (r2_name, rev1, rev2)) | |
185 |
|
185 | |||
186 |
|
||||
187 | finally: |
|
186 | finally: | |
188 | RepoModel().delete(r1_id) |
|
187 | RepoModel().delete(r1_id) | |
189 | RepoModel().delete(r2_id) |
|
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 | from rhodecode.tests import * |
|
1 | from rhodecode.tests import * | |
2 | from rhodecode.model.db import Repository |
|
2 | from rhodecode.model.db import Repository | |
3 | from rhodecode.lib.utils import invalidate_cache |
|
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 | class TestSummaryController(TestController): |
|
9 | class TestSummaryController(TestController): | |
@@ -82,6 +85,20 b' class TestSummaryController(TestControll' | |||||
82 | """title="public repository" alt="public """ |
|
85 | """title="public repository" alt="public """ | |
83 | """repository" src="/images/icons/lock_open.png"/>""") |
|
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 | def test_index_by_id_git(self): |
|
102 | def test_index_by_id_git(self): | |
86 | self.log_user() |
|
103 | self.log_user() | |
87 | ID = Repository.get_by_repo_name(GIT_REPO).repo_id |
|
104 | ID = Repository.get_by_repo_name(GIT_REPO).repo_id |
@@ -1,7 +1,7 b'' | |||||
1 | import os |
|
1 | import os | |
2 | import unittest |
|
2 | import unittest | |
3 | from rhodecode.tests import * |
|
3 | from rhodecode.tests import * | |
4 |
|
4 | from rhodecode.tests.models.common import _make_group | ||
5 | from rhodecode.model.repos_group import ReposGroupModel |
|
5 | from rhodecode.model.repos_group import ReposGroupModel | |
6 | from rhodecode.model.repo import RepoModel |
|
6 | from rhodecode.model.repo import RepoModel | |
7 | from rhodecode.model.db import RepoGroup, User, UsersGroupRepoGroupToPerm |
|
7 | from rhodecode.model.db import RepoGroup, User, UsersGroupRepoGroupToPerm | |
@@ -12,16 +12,6 b' from rhodecode.model.users_group import ' | |||||
12 | from rhodecode.lib.auth import AuthUser |
|
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 | class TestPermissions(unittest.TestCase): |
|
16 | class TestPermissions(unittest.TestCase): | |
27 | def __init__(self, methodName='runTest'): |
|
17 | def __init__(self, methodName='runTest'): | |
@@ -435,4 +425,3 b' class TestPermissions(unittest.TestCase)' | |||||
435 | set(['hg.create.repository', 'hg.fork.repository', |
|
425 | set(['hg.create.repository', 'hg.fork.repository', | |
436 | 'hg.register.manual_activate', |
|
426 | 'hg.register.manual_activate', | |
437 | 'repository.read'])) |
|
427 | 'repository.read'])) | |
438 |
|
@@ -4,7 +4,7 b' from rhodecode.tests import *' | |||||
4 |
|
4 | |||
5 | from rhodecode.model.repos_group import ReposGroupModel |
|
5 | from rhodecode.model.repos_group import ReposGroupModel | |
6 | from rhodecode.model.repo import RepoModel |
|
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 | from rhodecode.model.meta import Session |
|
8 | from rhodecode.model.meta import Session | |
9 | from sqlalchemy.exc import IntegrityError |
|
9 | from sqlalchemy.exc import IntegrityError | |
10 |
|
10 | |||
@@ -15,7 +15,8 b" def _make_group(path, desc='desc', paren" | |||||
15 | gr = RepoGroup.get_by_group_name(path) |
|
15 | gr = RepoGroup.get_by_group_name(path) | |
16 | if gr and skip_if_exists: |
|
16 | if gr and skip_if_exists: | |
17 | return gr |
|
17 | return gr | |
18 |
|
18 | if isinstance(parent_id, RepoGroup): | ||
|
19 | parent_id = parent_id.group_id | |||
19 | gr = ReposGroupModel().create(path, desc, parent_id) |
|
20 | gr = ReposGroupModel().create(path, desc, parent_id) | |
20 | return gr |
|
21 | return gr | |
21 |
|
22 | |||
@@ -54,7 +55,8 b' class TestReposGroups(unittest.TestCase)' | |||||
54 | group_parent_id=parent_id, |
|
55 | group_parent_id=parent_id, | |
55 | perms_updates=[], |
|
56 | perms_updates=[], | |
56 | perms_new=[], |
|
57 | perms_new=[], | |
57 | enable_locking=False |
|
58 | enable_locking=False, | |
|
59 | recursive=False | |||
58 | ) |
|
60 | ) | |
59 | gr = ReposGroupModel().update(id_, form_data) |
|
61 | gr = ReposGroupModel().update(id_, form_data) | |
60 | return gr |
|
62 | return gr | |
@@ -132,7 +134,8 b' class TestReposGroups(unittest.TestCase)' | |||||
132 | repo_type='hg', |
|
134 | repo_type='hg', | |
133 | clone_uri=None, |
|
135 | clone_uri=None, | |
134 | landing_rev='tip', |
|
136 | landing_rev='tip', | |
135 |
enable_locking=False |
|
137 | enable_locking=False, | |
|
138 | recursive=False) | |||
136 | cur_user = User.get_by_username(TEST_USER_ADMIN_LOGIN) |
|
139 | cur_user = User.get_by_username(TEST_USER_ADMIN_LOGIN) | |
137 | r = RepoModel().create(form_data, cur_user) |
|
140 | r = RepoModel().create(form_data, cur_user) | |
138 |
|
141 |
@@ -3,10 +3,14 b" psql -U postgres -h localhost -c 'create" | |||||
3 | paster setup-rhodecode rc.ini -q --user=marcink --password=qweqwe --email=marcin@python-blog.com --repos=/home/marcink/repos |
|
3 | paster setup-rhodecode rc.ini -q --user=marcink --password=qweqwe --email=marcin@python-blog.com --repos=/home/marcink/repos | |
4 | API_KEY=`psql -R " " -A -U postgres -h localhost -c "select api_key from users where admin=TRUE" -d rhodecode | awk '{print $2}'` |
|
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 | echo "run those after running server" |
|
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" |
|
6 | paster serve rc.ini --pid-file=rc.pid --daemon | |
7 | echo "rhodecode-api --apikey=$API_KEY --apihost=http://127.0.0.1:5001 create_user username:demo2 password:qweqwe email:demo2@rhodecode.org" |
|
7 | sleep 3 | |
8 |
ec |
|
8 | rhodecode-api --apikey=$API_KEY --apihost=http://127.0.0.1:5001 create_user username:demo1 password:qweqwe email:demo1@rhodecode.org | |
9 |
ec |
|
9 | rhodecode-api --apikey=$API_KEY --apihost=http://127.0.0.1:5001 create_user username:demo2 password:qweqwe email:demo2@rhodecode.org | |
10 |
ec |
|
10 | rhodecode-api --apikey=$API_KEY --apihost=http://127.0.0.1:5001 create_user username:demo3 password:qweqwe email:demo3@rhodecode.org | |
11 |
ec |
|
11 | rhodecode-api --apikey=$API_KEY --apihost=http://127.0.0.1:5001 create_users_group group_name:demo12 | |
12 |
|
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