Show More
The requested changes are too big and content was truncated. Show full diff
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
@@ -0,0 +1,35 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, joinedload | |||
|
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 | from rhodecode.lib.utils2 import str2bool | |||
|
13 | ||||
|
14 | from rhodecode.model.meta import Base | |||
|
15 | from rhodecode.model import meta | |||
|
16 | from rhodecode.lib.dbmigrate.versions import _reset_base, notify | |||
|
17 | ||||
|
18 | log = logging.getLogger(__name__) | |||
|
19 | ||||
|
20 | ||||
|
21 | def upgrade(migrate_engine): | |||
|
22 | """ | |||
|
23 | Upgrade operations go here. | |||
|
24 | Don't create your own engine; bind migrate_engine to your metadata | |||
|
25 | """ | |||
|
26 | _reset_base(migrate_engine) | |||
|
27 | from rhodecode.lib.dbmigrate.schema import db_4_4_0_2 | |||
|
28 | ||||
|
29 | db_4_4_0_2.RepoReviewRule.__table__.create() | |||
|
30 | db_4_4_0_2.RepoReviewRuleUser.__table__.create() | |||
|
31 | db_4_4_0_2.RepoReviewRuleUserGroup.__table__.create() | |||
|
32 | ||||
|
33 | def downgrade(migrate_engine): | |||
|
34 | meta = MetaData() | |||
|
35 | meta.bind = migrate_engine |
@@ -51,7 +51,7 b' PYRAMID_SETTINGS = {}' | |||||
51 | EXTENSIONS = {} |
|
51 | EXTENSIONS = {} | |
52 |
|
52 | |||
53 | __version__ = ('.'.join((str(each) for each in VERSION[:3]))) |
|
53 | __version__ = ('.'.join((str(each) for each in VERSION[:3]))) | |
54 |
__dbversion__ = 5 |
|
54 | __dbversion__ = 59 # defines current db version for migrations | |
55 | __platform__ = platform.system() |
|
55 | __platform__ = platform.system() | |
56 | __license__ = 'AGPLv3, and Commercial License' |
|
56 | __license__ = 'AGPLv3, and Commercial License' | |
57 | __author__ = 'RhodeCode GmbH' |
|
57 | __author__ = 'RhodeCode GmbH' |
@@ -196,7 +196,7 b' def make_map(config):' | |||||
196 | rmap.connect('user_autocomplete_data', '/_users', controller='home', |
|
196 | rmap.connect('user_autocomplete_data', '/_users', controller='home', | |
197 | action='user_autocomplete_data', jsroute=True) |
|
197 | action='user_autocomplete_data', jsroute=True) | |
198 | rmap.connect('user_group_autocomplete_data', '/_user_groups', controller='home', |
|
198 | rmap.connect('user_group_autocomplete_data', '/_user_groups', controller='home', | |
199 | action='user_group_autocomplete_data') |
|
199 | action='user_group_autocomplete_data', jsroute=True) | |
200 |
|
200 | |||
201 | rmap.connect( |
|
201 | rmap.connect( | |
202 | 'user_profile', '/_profiles/{username}', controller='users', |
|
202 | 'user_profile', '/_profiles/{username}', controller='users', | |
@@ -699,6 +699,9 b' def make_map(config):' | |||||
699 | rmap.connect('repo_refs_changelog_data', '/{repo_name}/refs-data-changelog', |
|
699 | rmap.connect('repo_refs_changelog_data', '/{repo_name}/refs-data-changelog', | |
700 | controller='summary', action='repo_refs_changelog_data', |
|
700 | controller='summary', action='repo_refs_changelog_data', | |
701 | requirements=URL_NAME_REQUIREMENTS, jsroute=True) |
|
701 | requirements=URL_NAME_REQUIREMENTS, jsroute=True) | |
|
702 | rmap.connect('repo_default_reviewers_data', '/{repo_name}/default-reviewers', | |||
|
703 | controller='summary', action='repo_default_reviewers_data', | |||
|
704 | jsroute=True, requirements=URL_NAME_REQUIREMENTS) | |||
702 |
|
705 | |||
703 | rmap.connect('changeset_home', '/{repo_name}/changeset/{revision}', |
|
706 | rmap.connect('changeset_home', '/{repo_name}/changeset/{revision}', | |
704 | controller='changeset', revision='tip', jsroute=True, |
|
707 | controller='changeset', revision='tip', jsroute=True, | |
@@ -824,6 +827,10 b' def make_map(config):' | |||||
824 | controller='admin/repos', action='repo_delete_svn_pattern', |
|
827 | controller='admin/repos', action='repo_delete_svn_pattern', | |
825 | conditions={'method': ['DELETE'], 'function': check_repo}, |
|
828 | conditions={'method': ['DELETE'], 'function': check_repo}, | |
826 | requirements=URL_NAME_REQUIREMENTS) |
|
829 | requirements=URL_NAME_REQUIREMENTS) | |
|
830 | rmap.connect('repo_pullrequest_settings', '/{repo_name}/settings/pullrequest', | |||
|
831 | controller='admin/repos', action='repo_settings_pullrequest', | |||
|
832 | conditions={'method': ['GET', 'POST'], 'function': check_repo}, | |||
|
833 | requirements=URL_NAME_REQUIREMENTS) | |||
827 |
|
834 | |||
828 | # still working url for backward compat. |
|
835 | # still working url for backward compat. | |
829 | rmap.connect('raw_changeset_home_depraced', |
|
836 | rmap.connect('raw_changeset_home_depraced', |
@@ -286,4 +286,3 b' class HomeController(BaseController):' | |||||
286 | _user_groups = _user_groups |
|
286 | _user_groups = _user_groups | |
287 |
|
287 | |||
288 | return {'suggestions': _user_groups} |
|
288 | return {'suggestions': _user_groups} | |
289 |
|
@@ -251,6 +251,16 b' class SummaryController(BaseRepoControll' | |||||
251 | } |
|
251 | } | |
252 | return data |
|
252 | return data | |
253 |
|
253 | |||
|
254 | @LoginRequired() | |||
|
255 | @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', | |||
|
256 | 'repository.admin') | |||
|
257 | @jsonify | |||
|
258 | def repo_default_reviewers_data(self, repo_name): | |||
|
259 | return { | |||
|
260 | 'reviewers': [utils.reviewer_as_json( | |||
|
261 | user=c.rhodecode_db_repo.user, reasons=None)] | |||
|
262 | } | |||
|
263 | ||||
254 | @jsonify |
|
264 | @jsonify | |
255 | def repo_refs_changelog_data(self, repo_name): |
|
265 | def repo_refs_changelog_data(self, repo_name): | |
256 | repo = c.rhodecode_repo |
|
266 | repo = c.rhodecode_repo |
@@ -86,3 +86,21 b' def get_commit_from_ref_name(repo, ref_n' | |||||
86 | '%s "%s" does not exist' % (ref_type, ref_name)) |
|
86 | '%s "%s" does not exist' % (ref_type, ref_name)) | |
87 |
|
87 | |||
88 | return repo_scm.get_commit(commit_id) |
|
88 | return repo_scm.get_commit(commit_id) | |
|
89 | ||||
|
90 | ||||
|
91 | def reviewer_as_json(user, reasons): | |||
|
92 | """ | |||
|
93 | Returns json struct of a reviewer for frontend | |||
|
94 | ||||
|
95 | :param user: the reviewer | |||
|
96 | :param reasons: list of strings of why they are reviewers | |||
|
97 | """ | |||
|
98 | ||||
|
99 | return { | |||
|
100 | 'user_id': user.user_id, | |||
|
101 | 'reasons': reasons, | |||
|
102 | 'username': user.username, | |||
|
103 | 'firstname': user.firstname, | |||
|
104 | 'lastname': user.lastname, | |||
|
105 | 'gravatar_link': h.gravatar_url(user.email, 14), | |||
|
106 | } |
@@ -893,3 +893,44 b' def get_routes_generator_for_server_url(' | |||||
893 | environ['wsgi.url_scheme'] = 'https' |
|
893 | environ['wsgi.url_scheme'] = 'https' | |
894 |
|
894 | |||
895 | return routes.util.URLGenerator(rhodecode.CONFIG['routes.map'], environ) |
|
895 | return routes.util.URLGenerator(rhodecode.CONFIG['routes.map'], environ) | |
|
896 | ||||
|
897 | ||||
|
898 | def glob2re(pat): | |||
|
899 | """ | |||
|
900 | Translate a shell PATTERN to a regular expression. | |||
|
901 | ||||
|
902 | There is no way to quote meta-characters. | |||
|
903 | """ | |||
|
904 | ||||
|
905 | i, n = 0, len(pat) | |||
|
906 | res = '' | |||
|
907 | while i < n: | |||
|
908 | c = pat[i] | |||
|
909 | i = i+1 | |||
|
910 | if c == '*': | |||
|
911 | #res = res + '.*' | |||
|
912 | res = res + '[^/]*' | |||
|
913 | elif c == '?': | |||
|
914 | #res = res + '.' | |||
|
915 | res = res + '[^/]' | |||
|
916 | elif c == '[': | |||
|
917 | j = i | |||
|
918 | if j < n and pat[j] == '!': | |||
|
919 | j = j+1 | |||
|
920 | if j < n and pat[j] == ']': | |||
|
921 | j = j+1 | |||
|
922 | while j < n and pat[j] != ']': | |||
|
923 | j = j+1 | |||
|
924 | if j >= n: | |||
|
925 | res = res + '\\[' | |||
|
926 | else: | |||
|
927 | stuff = pat[i:j].replace('\\','\\\\') | |||
|
928 | i = j+1 | |||
|
929 | if stuff[0] == '!': | |||
|
930 | stuff = '^' + stuff[1:] | |||
|
931 | elif stuff[0] == '^': | |||
|
932 | stuff = '\\' + stuff | |||
|
933 | res = '%s[%s]' % (res, stuff) | |||
|
934 | else: | |||
|
935 | res = res + re.escape(c) | |||
|
936 | return res + '\Z(?ms)' |
@@ -22,6 +22,7 b'' | |||||
22 | Database Models for RhodeCode Enterprise |
|
22 | Database Models for RhodeCode Enterprise | |
23 | """ |
|
23 | """ | |
24 |
|
24 | |||
|
25 | import re | |||
25 | import os |
|
26 | import os | |
26 | import sys |
|
27 | import sys | |
27 | import time |
|
28 | import time | |
@@ -56,7 +57,8 b' from rhodecode.lib.vcs.backends.base imp' | |||||
56 | EmptyCommit, Reference, MergeFailureReason) |
|
57 | EmptyCommit, Reference, MergeFailureReason) | |
57 | from rhodecode.lib.utils2 import ( |
|
58 | from rhodecode.lib.utils2 import ( | |
58 | str2bool, safe_str, get_commit_safe, safe_unicode, remove_prefix, md5_safe, |
|
59 | str2bool, safe_str, get_commit_safe, safe_unicode, remove_prefix, md5_safe, | |
59 |
time_to_datetime, aslist, Optional, safe_int, get_clone_url, AttributeDict |
|
60 | time_to_datetime, aslist, Optional, safe_int, get_clone_url, AttributeDict, | |
|
61 | glob2re) | |||
60 | from rhodecode.lib.jsonalchemy import MutationObj, JsonType, JSONDict |
|
62 | from rhodecode.lib.jsonalchemy import MutationObj, JsonType, JSONDict | |
61 | from rhodecode.lib.ext_json import json |
|
63 | from rhodecode.lib.ext_json import json | |
62 | from rhodecode.lib.caching_query import FromCache |
|
64 | from rhodecode.lib.caching_query import FromCache | |
@@ -3514,3 +3516,125 b' class Integration(Base, BaseModel):' | |||||
3514 |
|
3516 | |||
3515 | def __repr__(self): |
|
3517 | def __repr__(self): | |
3516 | return '<Integration(%r, %r)>' % (self.integration_type, self.scope) |
|
3518 | return '<Integration(%r, %r)>' % (self.integration_type, self.scope) | |
|
3519 | ||||
|
3520 | ||||
|
3521 | class RepoReviewRuleUser(Base, BaseModel): | |||
|
3522 | __tablename__ = 'repo_review_rules_users' | |||
|
3523 | __table_args__ = ( | |||
|
3524 | {'extend_existing': True, 'mysql_engine': 'InnoDB', | |||
|
3525 | 'mysql_charset': 'utf8', 'sqlite_autoincrement': True,} | |||
|
3526 | ) | |||
|
3527 | repo_review_rule_user_id = Column( | |||
|
3528 | 'repo_review_rule_user_id', Integer(), primary_key=True) | |||
|
3529 | repo_review_rule_id = Column("repo_review_rule_id", | |||
|
3530 | Integer(), ForeignKey('repo_review_rules.repo_review_rule_id')) | |||
|
3531 | user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), | |||
|
3532 | nullable=False) | |||
|
3533 | user = relationship('User') | |||
|
3534 | ||||
|
3535 | ||||
|
3536 | class RepoReviewRuleUserGroup(Base, BaseModel): | |||
|
3537 | __tablename__ = 'repo_review_rules_users_groups' | |||
|
3538 | __table_args__ = ( | |||
|
3539 | {'extend_existing': True, 'mysql_engine': 'InnoDB', | |||
|
3540 | 'mysql_charset': 'utf8', 'sqlite_autoincrement': True,} | |||
|
3541 | ) | |||
|
3542 | repo_review_rule_users_group_id = Column( | |||
|
3543 | 'repo_review_rule_users_group_id', Integer(), primary_key=True) | |||
|
3544 | repo_review_rule_id = Column("repo_review_rule_id", | |||
|
3545 | Integer(), ForeignKey('repo_review_rules.repo_review_rule_id')) | |||
|
3546 | users_group_id = Column("users_group_id", Integer(), | |||
|
3547 | ForeignKey('users_groups.users_group_id'), nullable=False) | |||
|
3548 | users_group = relationship('UserGroup') | |||
|
3549 | ||||
|
3550 | ||||
|
3551 | class RepoReviewRule(Base, BaseModel): | |||
|
3552 | __tablename__ = 'repo_review_rules' | |||
|
3553 | __table_args__ = ( | |||
|
3554 | {'extend_existing': True, 'mysql_engine': 'InnoDB', | |||
|
3555 | 'mysql_charset': 'utf8', 'sqlite_autoincrement': True,} | |||
|
3556 | ) | |||
|
3557 | ||||
|
3558 | repo_review_rule_id = Column( | |||
|
3559 | 'repo_review_rule_id', Integer(), primary_key=True) | |||
|
3560 | repo_id = Column( | |||
|
3561 | "repo_id", Integer(), ForeignKey('repositories.repo_id')) | |||
|
3562 | repo = relationship('Repository', backref='review_rules') | |||
|
3563 | ||||
|
3564 | _branch_pattern = Column("branch_pattern", UnicodeText().with_variant(UnicodeText(255), 'mysql'), | |||
|
3565 | default=u'*') # glob | |||
|
3566 | _file_pattern = Column("file_pattern", UnicodeText().with_variant(UnicodeText(255), 'mysql'), | |||
|
3567 | default=u'*') # glob | |||
|
3568 | ||||
|
3569 | use_authors_for_review = Column("use_authors_for_review", Boolean(), | |||
|
3570 | nullable=False, default=False) | |||
|
3571 | rule_users = relationship('RepoReviewRuleUser') | |||
|
3572 | rule_user_groups = relationship('RepoReviewRuleUserGroup') | |||
|
3573 | ||||
|
3574 | @hybrid_property | |||
|
3575 | def branch_pattern(self): | |||
|
3576 | return self._branch_pattern or '*' | |||
|
3577 | ||||
|
3578 | def _validate_glob(self, value): | |||
|
3579 | re.compile('^' + glob2re(value) + '$') | |||
|
3580 | ||||
|
3581 | @branch_pattern.setter | |||
|
3582 | def branch_pattern(self, value): | |||
|
3583 | self._validate_glob(value) | |||
|
3584 | self._branch_pattern = value or '*' | |||
|
3585 | ||||
|
3586 | @hybrid_property | |||
|
3587 | def file_pattern(self): | |||
|
3588 | return self._file_pattern or '*' | |||
|
3589 | ||||
|
3590 | @file_pattern.setter | |||
|
3591 | def file_pattern(self, value): | |||
|
3592 | self._validate_glob(value) | |||
|
3593 | self._file_pattern = value or '*' | |||
|
3594 | ||||
|
3595 | def matches(self, branch, files_changed): | |||
|
3596 | """ | |||
|
3597 | Check if this review rule matches a branch/files in a pull request | |||
|
3598 | ||||
|
3599 | :param branch: branch name for the commit | |||
|
3600 | :param files_changed: list of file paths changed in the pull request | |||
|
3601 | """ | |||
|
3602 | ||||
|
3603 | branch = branch or '' | |||
|
3604 | files_changed = files_changed or [] | |||
|
3605 | ||||
|
3606 | branch_matches = True | |||
|
3607 | if branch: | |||
|
3608 | branch_regex = re.compile('^' + glob2re(self.branch_pattern) + '$') | |||
|
3609 | branch_matches = bool(branch_regex.search(branch)) | |||
|
3610 | ||||
|
3611 | files_matches = True | |||
|
3612 | if self.file_pattern != '*': | |||
|
3613 | files_matches = False | |||
|
3614 | file_regex = re.compile(glob2re(self.file_pattern)) | |||
|
3615 | for filename in files_changed: | |||
|
3616 | if file_regex.search(filename): | |||
|
3617 | files_matches = True | |||
|
3618 | break | |||
|
3619 | ||||
|
3620 | return branch_matches and files_matches | |||
|
3621 | ||||
|
3622 | @property | |||
|
3623 | def review_users(self): | |||
|
3624 | """ Returns the users which this rule applies to """ | |||
|
3625 | ||||
|
3626 | users = set() | |||
|
3627 | users |= set([ | |||
|
3628 | rule_user.user for rule_user in self.rule_users | |||
|
3629 | if rule_user.user.active]) | |||
|
3630 | users |= set( | |||
|
3631 | member.user | |||
|
3632 | for rule_user_group in self.rule_user_groups | |||
|
3633 | for member in rule_user_group.users_group.members | |||
|
3634 | if member.user.active | |||
|
3635 | ) | |||
|
3636 | return users | |||
|
3637 | ||||
|
3638 | def __repr__(self): | |||
|
3639 | return '<RepoReviewerRule(id=%r, repo=%r)>' % ( | |||
|
3640 | self.repo_review_rule_id, self.repo) |
@@ -1,9 +1,11 b'' | |||||
1 | import os |
|
1 | import os | |
|
2 | import re | |||
2 |
|
3 | |||
3 | import ipaddress |
|
4 | import ipaddress | |
4 | import colander |
|
5 | import colander | |
5 |
|
6 | |||
6 | from rhodecode.translation import _ |
|
7 | from rhodecode.translation import _ | |
|
8 | from rhodecode.lib.utils2 import glob2re | |||
7 |
|
9 | |||
8 |
|
10 | |||
9 | def ip_addr_validator(node, value): |
|
11 | def ip_addr_validator(node, value): | |
@@ -13,3 +15,12 b' def ip_addr_validator(node, value):' | |||||
13 | except ValueError: |
|
15 | except ValueError: | |
14 | msg = _(u'Please enter a valid IPv4 or IpV6 address') |
|
16 | msg = _(u'Please enter a valid IPv4 or IpV6 address') | |
15 | raise colander.Invalid(node, msg) |
|
17 | raise colander.Invalid(node, msg) | |
|
18 | ||||
|
19 | ||||
|
20 | def glob_validator(node, value): | |||
|
21 | try: | |||
|
22 | re.compile('^' + glob2re(value) + '$') | |||
|
23 | except Exception: | |||
|
24 | raise | |||
|
25 | msg = _(u'Invalid glob pattern') | |||
|
26 | raise colander.Invalid(node, msg) |
@@ -90,28 +90,50 b'' | |||||
90 | height: 40px; |
|
90 | height: 40px; | |
91 | } |
|
91 | } | |
92 |
|
92 | |||
93 | .deform-two-field-sequence .deform-seq-container .deform-seq-item label { |
|
93 | .deform-full-field-sequence.control-inputs { | |
|
94 | width: 100%; | |||
|
95 | } | |||
|
96 | ||||
|
97 | .deform-table-sequence { | |||
|
98 | .deform-seq-container { | |||
|
99 | .deform-seq-item { | |||
|
100 | margin: 0; | |||
|
101 | label { | |||
94 | display: none; |
|
102 | display: none; | |
95 | } |
|
103 | } | |
96 | .deform-two-field-sequence .deform-seq-container .deform-seq-item:first-child label { |
|
104 | .panel-heading { | |
97 | display: block; |
|
|||
98 | } |
|
|||
99 | .deform-two-field-sequence .deform-seq-container .deform-seq-item .panel-heading { |
|
|||
100 | display: none; |
|
105 | display: none; | |
101 | } |
|
106 | } | |
102 | .deform-two-field-sequence .deform-seq-container .deform-seq-item.form-group { |
|
107 | .deform-seq-item-group > .panel { | |
103 | margin: 0; |
|
|||
104 | } |
|
|||
105 | .deform-two-field-sequence .deform-seq-container .deform-seq-item .deform-seq-item-group .form-group { |
|
|||
106 | width: 45%; padding: 0 2px; float: left; clear: none; |
|
|||
107 | } |
|
|||
108 | .deform-two-field-sequence .deform-seq-container .deform-seq-item .deform-seq-item-group > .panel { |
|
|||
109 | padding: 0; |
|
108 | padding: 0; | |
110 | margin: 5px 0; |
|
109 | margin: 5px 0; | |
111 | border: none; |
|
110 | border: none; | |
112 | } |
|
111 | &> .panel-body { | |
113 | .deform-two-field-sequence .deform-seq-container .deform-seq-item .deform-seq-item-group > .panel > .panel-body { |
|
|||
114 | padding: 0; |
|
112 | padding: 0; | |
115 | } |
|
113 | } | |
116 |
|
114 | } | ||
|
115 | &:first-child label { | |||
|
116 | display: block; | |||
|
117 | } | |||
|
118 | } | |||
|
119 | } | |||
|
120 | } | |||
|
121 | .deform-table-2-sequence { | |||
|
122 | .deform-seq-container { | |||
|
123 | .deform-seq-item { | |||
|
124 | .form-group { | |||
|
125 | width: 45% !important; padding: 0 2px; float: left; clear: none; | |||
117 | } |
|
126 | } | |
|
127 | } | |||
|
128 | } | |||
|
129 | } | |||
|
130 | .deform-table-3-sequence { | |||
|
131 | .deform-seq-container { | |||
|
132 | .deform-seq-item { | |||
|
133 | .form-group { | |||
|
134 | width: 30% !important; padding: 0 2px; float: left; clear: none; | |||
|
135 | } | |||
|
136 | } | |||
|
137 | } | |||
|
138 | } | |||
|
139 | } |
@@ -14,6 +14,7 b' function registerRCRoutes() {' | |||||
14 | // routes registration |
|
14 | // routes registration | |
15 | pyroutes.register('home', '/', []); |
|
15 | pyroutes.register('home', '/', []); | |
16 | pyroutes.register('user_autocomplete_data', '/_users', []); |
|
16 | pyroutes.register('user_autocomplete_data', '/_users', []); | |
|
17 | pyroutes.register('user_group_autocomplete_data', '/_user_groups', []); | |||
17 | pyroutes.register('new_repo', '/_admin/create_repository', []); |
|
18 | pyroutes.register('new_repo', '/_admin/create_repository', []); | |
18 | pyroutes.register('edit_user_group_members', '/_admin/user_groups/%(user_group_id)s/edit/members', ['user_group_id']); |
|
19 | pyroutes.register('edit_user_group_members', '/_admin/user_groups/%(user_group_id)s/edit/members', ['user_group_id']); | |
19 | pyroutes.register('gists', '/_admin/gists', []); |
|
20 | pyroutes.register('gists', '/_admin/gists', []); | |
@@ -22,6 +23,7 b' function registerRCRoutes() {' | |||||
22 | pyroutes.register('repo_stats', '/%(repo_name)s/repo_stats/%(commit_id)s', ['repo_name', 'commit_id']); |
|
23 | pyroutes.register('repo_stats', '/%(repo_name)s/repo_stats/%(commit_id)s', ['repo_name', 'commit_id']); | |
23 | pyroutes.register('repo_refs_data', '/%(repo_name)s/refs-data', ['repo_name']); |
|
24 | pyroutes.register('repo_refs_data', '/%(repo_name)s/refs-data', ['repo_name']); | |
24 | pyroutes.register('repo_refs_changelog_data', '/%(repo_name)s/refs-data-changelog', ['repo_name']); |
|
25 | pyroutes.register('repo_refs_changelog_data', '/%(repo_name)s/refs-data-changelog', ['repo_name']); | |
|
26 | pyroutes.register('repo_default_reviewers_data', '/%(repo_name)s/default-reviewers', ['repo_name']); | |||
25 | pyroutes.register('changeset_home', '/%(repo_name)s/changeset/%(revision)s', ['repo_name', 'revision']); |
|
27 | pyroutes.register('changeset_home', '/%(repo_name)s/changeset/%(revision)s', ['repo_name', 'revision']); | |
26 | pyroutes.register('edit_repo', '/%(repo_name)s/settings', ['repo_name']); |
|
28 | pyroutes.register('edit_repo', '/%(repo_name)s/settings', ['repo_name']); | |
27 | pyroutes.register('edit_repo_perms', '/%(repo_name)s/settings/permissions', ['repo_name']); |
|
29 | pyroutes.register('edit_repo_perms', '/%(repo_name)s/settings/permissions', ['repo_name']); |
@@ -40,14 +40,23 b' var removeReviewMember = function(review' | |||||
40 | } |
|
40 | } | |
41 | }; |
|
41 | }; | |
42 |
|
42 | |||
43 | var addReviewMember = function(id,fname,lname,nname,gravatar_link){ |
|
43 | var addReviewMember = function(id, fname, lname, nname, gravatar_link, reasons) { | |
44 | var members = $('#review_members').get(0); |
|
44 | var members = $('#review_members').get(0); | |
|
45 | var reasons_html = ''; | |||
|
46 | if (reasons) { | |||
|
47 | for (var i = 0; i < reasons.length; i++) { | |||
|
48 | reasons_html += '<div class="reviewer_reason">- {0}</div>'.format( | |||
|
49 | reasons[i] | |||
|
50 | ); | |||
|
51 | } | |||
|
52 | } | |||
45 | var tmpl = '<li id="reviewer_{2}">'+ |
|
53 | var tmpl = '<li id="reviewer_{2}">'+ | |
46 | '<div class="reviewer_status">'+ |
|
54 | '<div class="reviewer_status">'+ | |
47 | '<div class="flag_status not_reviewed pull-left reviewer_member_status"></div>'+ |
|
55 | '<div class="flag_status not_reviewed pull-left reviewer_member_status"></div>'+ | |
48 | '</div>'+ |
|
56 | '</div>'+ | |
49 | '<img alt="gravatar" class="gravatar" src="{0}"/>'+ |
|
57 | '<img alt="gravatar" class="gravatar" src="{0}"/>'+ | |
50 | '<span class="reviewer_name user">{1}</span>'+ |
|
58 | '<span class="reviewer_name user">{1}</span>'+ | |
|
59 | reasons_html + | |||
51 | '<input type="hidden" value="{2}" name="review_members" />'+ |
|
60 | '<input type="hidden" value="{2}" name="review_members" />'+ | |
52 | '<div class="reviewer_member_remove action_button" onclick="removeReviewMember({2})">' + |
|
61 | '<div class="reviewer_member_remove action_button" onclick="removeReviewMember({2})">' + | |
53 | '<i class="icon-remove-sign"></i>'+ |
|
62 | '<i class="icon-remove-sign"></i>'+ |
@@ -71,6 +71,22 b'' | |||||
71 | <li class="${'active' if c.active=='integrations' else ''}"> |
|
71 | <li class="${'active' if c.active=='integrations' else ''}"> | |
72 | <a href="${h.route_path('repo_integrations_home', repo_name=c.repo_name)}">${_('Integrations')}</a> |
|
72 | <a href="${h.route_path('repo_integrations_home', repo_name=c.repo_name)}">${_('Integrations')}</a> | |
73 | </li> |
|
73 | </li> | |
|
74 | ## TODO: dan: replace repo navigation with navlist registry like with | |||
|
75 | ## admin menu. First must find way to allow runtime configuration | |||
|
76 | ## it to account for the c.repo_info.repo_type != 'svn' call above | |||
|
77 | <% | |||
|
78 | reviewer_settings = False | |||
|
79 | try: | |||
|
80 | import rc_reviewers | |||
|
81 | reviewer_settings = True | |||
|
82 | except ImportError: | |||
|
83 | pass | |||
|
84 | %> | |||
|
85 | %if reviewer_settings: | |||
|
86 | <li class="${'active' if c.active=='reviewers' else ''}"> | |||
|
87 | <a href="${h.route_path('repo_reviewers_home', repo_name=c.repo_name)}">${_('Reviewers')}</a> | |||
|
88 | </li> | |||
|
89 | %endif | |||
74 | </ul> |
|
90 | </ul> | |
75 | </div> |
|
91 | </div> | |
76 |
|
92 |
@@ -439,13 +439,6 b'' | |||||
439 | }; |
|
439 | }; | |
440 |
|
440 | |||
441 | var targetRepoChanged = function(repoData) { |
|
441 | var targetRepoChanged = function(repoData) { | |
442 | // reset && add the reviewer based on selected repo |
|
|||
443 | $('#review_members').html(''); |
|
|||
444 | addReviewMember( |
|
|||
445 | repoData.user.user_id, repoData.user.firstname, |
|
|||
446 | repoData.user.lastname, repoData.user.username, |
|
|||
447 | repoData.user.gravatar_link); |
|
|||
448 |
|
||||
449 | // generate new DESC of target repo displayed next to select |
|
442 | // generate new DESC of target repo displayed next to select | |
450 | $('#target_repo_desc').html( |
|
443 | $('#target_repo_desc').html( | |
451 | "<strong>${_('Destination repository')}</strong>: {0}".format(repoData['description']) |
|
444 | "<strong>${_('Destination repository')}</strong>: {0}".format(repoData['description']) | |
@@ -488,10 +481,12 b'' | |||||
488 |
|
481 | |||
489 | $sourceRef.on('change', function(e){ |
|
482 | $sourceRef.on('change', function(e){ | |
490 | loadRepoRefDiffPreview(); |
|
483 | loadRepoRefDiffPreview(); | |
|
484 | loadDefaultReviewers(); | |||
491 | }); |
|
485 | }); | |
492 |
|
486 | |||
493 | $targetRef.on('change', function(e){ |
|
487 | $targetRef.on('change', function(e){ | |
494 | loadRepoRefDiffPreview(); |
|
488 | loadRepoRefDiffPreview(); | |
|
489 | loadDefaultReviewers(); | |||
495 | }); |
|
490 | }); | |
496 |
|
491 | |||
497 | $targetRepo.on('change', function(e){ |
|
492 | $targetRepo.on('change', function(e){ | |
@@ -518,6 +513,36 b'' | |||||
518 |
|
513 | |||
519 | }); |
|
514 | }); | |
520 |
|
515 | |||
|
516 | var loadDefaultReviewers = function() { | |||
|
517 | if (loadDefaultReviewers._currentRequest) { | |||
|
518 | loadDefaultReviewers._currentRequest.abort(); | |||
|
519 | } | |||
|
520 | var url = pyroutes.url('repo_default_reviewers_data', {'repo_name': targetRepoName}); | |||
|
521 | ||||
|
522 | var sourceRepo = $sourceRepo.eq(0).val(); | |||
|
523 | var sourceRef = $sourceRef.eq(0).val().split(':'); | |||
|
524 | var targetRepo = $targetRepo.eq(0).val(); | |||
|
525 | var targetRef = $targetRef.eq(0).val().split(':'); | |||
|
526 | url += '?source_repo=' + sourceRepo; | |||
|
527 | url += '&source_ref=' + sourceRef[2]; | |||
|
528 | url += '&target_repo=' + targetRepo; | |||
|
529 | url += '&target_ref=' + targetRef[2]; | |||
|
530 | ||||
|
531 | loadDefaultReviewers._currentRequest = $.get(url) | |||
|
532 | .done(function(data) { | |||
|
533 | loadDefaultReviewers._currentRequest = null; | |||
|
534 | ||||
|
535 | // reset && add the reviewer based on selected repo | |||
|
536 | $('#review_members').html(''); | |||
|
537 | for (var i = 0; i < data.reviewers.length; i++) { | |||
|
538 | var reviewer = data.reviewers[i]; | |||
|
539 | addReviewMember( | |||
|
540 | reviewer.user_id, reviewer.firstname, | |||
|
541 | reviewer.lastname, reviewer.username, | |||
|
542 | reviewer.gravatar_link, reviewer.reasons); | |||
|
543 | } | |||
|
544 | }); | |||
|
545 | }; | |||
521 | prButtonLock(true, "${_('Please select origin and destination')}"); |
|
546 | prButtonLock(true, "${_('Please select origin and destination')}"); | |
522 |
|
547 | |||
523 | // auto-load on init, the target refs select2 |
|
548 | // auto-load on init, the target refs select2 | |
@@ -532,6 +557,7 b'' | |||||
532 | // in case we have a pre-selected value, use it now |
|
557 | // in case we have a pre-selected value, use it now | |
533 | $sourceRef.select2('val', '${c.default_source_ref}'); |
|
558 | $sourceRef.select2('val', '${c.default_source_ref}'); | |
534 | loadRepoRefDiffPreview(); |
|
559 | loadRepoRefDiffPreview(); | |
|
560 | loadDefaultReviewers(); | |||
535 | %endif |
|
561 | %endif | |
536 |
|
562 | |||
537 | ReviewerAutoComplete('user'); |
|
563 | ReviewerAutoComplete('user'); |
General Comments 0
You need to be logged in to leave comments.
Login now