def _graph(self, repo, collection, repo_size, size, p): """ Generates a DAG graph for mercurial :param repo: repo instance :param size: number of commits to show :param p: page number """ if not collection: c.jsdata = json.dumps([]) return data = [] revs = [x.revision for x in collection] if repo.alias == 'git': for _ in revs: vtx = [0, 1] edges = [[0, 0, 1]] data.append(['', vtx, edges]) elif repo.alias == 'hg': dag = graphmod.dagwalker(repo._repo, revs) c.dag = graphmod.colored(dag, repo._repo) for (id, type, ctx, vtx, edges) in c.dag: if type != graphmod.CHANGESET: continue data.append(['', vtx, edges]) c.jsdata = json.dumps(data)
def show(self, group_name, format='html'): """GET /repos_groups/group_name: Show a specific item""" # url('repos_group', group_name=GROUP_NAME) c.group = c.repos_group = ReposGroupModel()._get_repo_group(group_name) c.group_repos = c.group.repositories.all() #overwrite our cached list with current filter gr_filter = c.group_repos c.repo_cnt = 0 groups = RepoGroup.query().order_by(RepoGroup.group_name)\ .filter(RepoGroup.group_parent_id == c.group.group_id).all() c.groups = self.scm_model.get_repos_groups(groups) c.repos_list = Repository.query()\ .filter(Repository.group_id == c.group.group_id)\ .order_by(func.lower(Repository.repo_name))\ .all() repos_data = RepoModel().get_repos_as_dict(repos_list=c.repos_list, admin=False) #json used to render the grid c.data = json.dumps(repos_data) return render('admin/repos_groups/repos_groups.html')
def jsonrpc_error(message, code=None): """ Generate a Response object with a JSON-RPC error body """ from pylons.controllers.util import Response resp = Response(body=json.dumps(dict(result=None, error=message)), status=code, content_type="application/json") return resp
def index(self, format='html'): """GET /users: All items in the collection""" # url('users') c.users_list = User.query().order_by(User.username)\ .filter(User.username != User.DEFAULT_USER)\ .all() users_data = [] total_records = len(c.users_list) _tmpl_lookup = rhodecode.CONFIG['pylons.app_globals'].mako_lookup template = _tmpl_lookup.get_template('data_table/_dt_elements.html') grav_tmpl = lambda user_email, size: (template.get_def( "user_gravatar").render(user_email, size, _=_, h=h, c=c)) user_lnk = lambda user_id, username: (template.get_def( "user_name").render(user_id, username, _=_, h=h, c=c)) user_actions = lambda user_id, username: (template.get_def( "user_actions").render(user_id, username, _=_, h=h, c=c)) for user in c.users_list: users_data.append({ "gravatar": grav_tmpl(user.email, 24), "raw_username": user.username, "username": user_lnk(user.user_id, user.username), "firstname": user.name, "lastname": user.lastname, "last_login": h.fmt_date(user.last_login), "last_login_raw": datetime_to_time(user.last_login), "active": h.boolicon(user.active), "admin": h.boolicon(user.admin), "ldap": h.boolicon(bool(user.ldap_dn)), "action": user_actions(user.user_id, user.username), }) c.data = json.dumps({ "totalRecords": total_records, "startIndex": 0, "sort": None, "dir": "asc", "records": users_data }) return render('admin/users/users.html')
def jsonrpc_error(message, code=None): """ Generate a Response object with a JSON-RPC error body """ from pylons.controllers.util import Response resp = Response(body=json.dumps(dict(id=None, result=None, error=message)), status=code, content_type='application/json') return resp
def get_users_groups_js(self): users_groups = self.sa.query(UsersGroup)\ .filter(UsersGroup.users_group_active == True).all() return json.dumps([{ 'id': gr.users_group_id, 'grname': gr.users_group_name, 'grmembers': len(gr.members), } for gr in users_groups])
def get_users_js(self): users = self.sa.query(User).filter(User.active == True).all() return json.dumps([{ 'id': u.user_id, 'fname': u.name, 'lname': u.lastname, 'nname': u.username, 'gravatar_lnk': h.gravatar_url(u.email, 14) } for u in users])
def get_users_groups_js(self): users_groups = self.sa.query(UsersGroup).filter(UsersGroup.users_group_active == True).all() return json.dumps( [ {"id": gr.users_group_id, "grname": gr.users_group_name, "grmembers": len(gr.members)} for gr in users_groups ] )
def _load_my_repos_data(self): repos_list = Session().query(Repository)\ .filter(Repository.user_id == self.rhodecode_user.user_id)\ .order_by(func.lower(Repository.repo_name)).all() repos_data = RepoModel().get_repos_as_dict(repos_list=repos_list, admin=True) #json used to render the grid return json.dumps(repos_data)
def get_users_groups_js(self): users_groups = self.sa.query(UserGroup)\ .filter(UserGroup.users_group_active == True).all() users_groups = UserGroupList( users_groups, perm_set=['usergroup.read', 'usergroup.write', 'usergroup.admin']) return json.dumps([{ 'id': gr.users_group_id, 'grname': gr.users_group_name, 'grmembers': len(gr.members), } for gr in users_groups])
def get_users_groups_js(self): users_groups = self.sa.query(UserGroup)\ .filter(UserGroup.users_group_active == True).all() return json.dumps([ { 'id': gr.users_group_id, 'grname': gr.users_group_name, 'grmembers': len(gr.members), } for gr in users_groups] )
def get_users_js(self): users = self.sa.query(User).filter(User.active == True).all() return json.dumps([ { 'id': u.user_id, 'fname': u.name, 'lname': u.lastname, 'nname': u.username, 'gravatar_lnk': h.gravatar_url(u.email, 14) } for u in users] )
def _graph(self, repo, collection, repo_size, size, p): """ Generates a DAG graph for mercurial :param repo: repo instance :param size: number of commits to show :param p: page number """ if not collection: c.jsdata = json.dumps([]) return data = [] revs = [x.revision for x in collection] dag = _dagwalker(repo, revs, repo.alias) dag = _colored(dag) for (id, type, ctx, vtx, edges) in dag: data.append(['', vtx, edges]) c.jsdata = json.dumps(data)
def get_users_groups_js(self): users_groups = self.sa.query(UserGroup)\ .filter(UserGroup.users_group_active == True).all() users_groups = UserGroupList(users_groups, perm_set=['usergroup.read', 'usergroup.write', 'usergroup.admin']) return json.dumps([ { 'id': gr.users_group_id, 'grname': gr.users_group_name, 'grmembers': len(gr.members), } for gr in users_groups] )
def _graph(self, repo, repo_size, size, p): """ Generates a DAG graph for mercurial :param repo: repo instance :param size: number of commits to show :param p: page number """ if not repo.revisions: c.jsdata = json.dumps([]) return revcount = min(repo_size, size) offset = 1 if p == 1 else ((p - 1) * revcount + 1) try: rev_end = repo.revisions.index(repo.revisions[(-1 * offset)]) except IndexError: rev_end = repo.revisions.index(repo.revisions[-1]) rev_start = max(0, rev_end - revcount) data = [] rev_end += 1 if repo.alias == 'git': for _ in xrange(rev_start, rev_end): vtx = [0, 1] edges = [[0, 0, 1]] data.append(['', vtx, edges]) elif repo.alias == 'hg': revs = list(reversed(xrange(rev_start, rev_end))) c.dag = graphmod.colored(graphmod.dagwalker(repo._repo, revs)) for (id, type, ctx, vtx, edges) in c.dag: if type != graphmod.CHANGESET: continue data.append(['', vtx, edges]) c.jsdata = json.dumps(data)
def _graph(self, repo, revs_int, repo_size, size, p): """ Generates a DAG graph for repo :param repo: :param revs_int: :param repo_size: :param size: :param p: """ if not revs_int: c.jsdata = json.dumps([]) return data = [] revs = revs_int dag = _dagwalker(repo, revs, repo.alias) dag = _colored(dag) for (_id, _type, ctx, vtx, edges) in dag: data.append(['', vtx, edges]) c.jsdata = json.dumps(data)
def get_users_js(self): users = self.sa.query(User).filter(User.active == True).all() return json.dumps( [ { "id": u.user_id, "fname": u.name, "lname": u.lastname, "nname": u.username, "gravatar_lnk": h.gravatar_url(u.email, 14), } for u in users ] )
def index(self, format='html'): """GET /users: All items in the collection""" # url('users') c.users_list = User.query().order_by(User.username)\ .filter(User.username != User.DEFAULT_USER)\ .all() users_data = [] total_records = len(c.users_list) _tmpl_lookup = rhodecode.CONFIG['pylons.app_globals'].mako_lookup template = _tmpl_lookup.get_template('data_table/_dt_elements.html') grav_tmpl = lambda user_email, size: ( template.get_def("user_gravatar") .render(user_email, size, _=_, h=h, c=c)) user_lnk = lambda user_id, username: ( template.get_def("user_name") .render(user_id, username, _=_, h=h, c=c)) user_actions = lambda user_id, username: ( template.get_def("user_actions") .render(user_id, username, _=_, h=h, c=c)) for user in c.users_list: users_data.append({ "gravatar": grav_tmpl(user. email, 24), "raw_username": user.username, "username": user_lnk(user.user_id, user.username), "firstname": user.name, "lastname": user.lastname, "last_login": h.fmt_date(user.last_login), "last_login_raw": datetime_to_time(user.last_login), "active": h.boolicon(user.active), "admin": h.boolicon(user.admin), "ldap": h.boolicon(bool(user.ldap_dn)), "action": user_actions(user.user_id, user.username), }) c.data = json.dumps({ "totalRecords": total_records, "startIndex": 0, "sort": None, "dir": "asc", "records": users_data }) return render('admin/users/users.html')
def _build_data(apikey, method, **kw): """ Builds API data with given random ID :param random_id: :type random_id: """ random_id = random.randrange(1, 9999) return random_id, json.dumps({ "id": random_id, "api_key": apikey, "method": method, "args": kw })
def index(self): c.groups = self.scm_model.get_repos_groups() c.group = None c.repos_list = Repository.query()\ .filter(Repository.group_id == None)\ .order_by(func.lower(Repository.repo_name))\ .all() repos_data = RepoModel().get_repos_as_dict(repos_list=c.repos_list, admin=False) #json used to render the grid c.data = json.dumps(repos_data) return render('/index.html')
def index(self, format='html'): """GET /repos: All items in the collection""" # url('repos') c.repos_list = Repository.query()\ .order_by(func.lower(Repository.repo_name))\ .all() repos_data = RepoModel().get_repos_as_dict(repos_list=c.repos_list, admin=True, super_user_actions=True) #json used to render the grid c.data = json.dumps(repos_data) return render('admin/repos/repos.html')
def index(self, format='html'): """GET /repos: All items in the collection""" # url('repos') c.repos_list = Repository.query()\ .order_by(func.lower(Repository.repo_name))\ .all() repos_data = [] total_records = len(c.repos_list) _tmpl_lookup = rhodecode.CONFIG['pylons.app_globals'].mako_lookup template = _tmpl_lookup.get_template('data_table/_dt_elements.html') quick_menu = lambda repo_name: (template.get_def("quick_menu") .render(repo_name, _=_, h=h, c=c)) repo_lnk = lambda name, rtype, private, fork_of: ( template.get_def("repo_name") .render(name, rtype, private, fork_of, short_name=False, admin=True, _=_, h=h, c=c)) repo_actions = lambda repo_name: (template.get_def("repo_actions") .render(repo_name, _=_, h=h, c=c)) for repo in c.repos_list: repos_data.append({ "menu": quick_menu(repo.repo_name), "raw_name": repo.repo_name.lower(), "name": repo_lnk(repo.repo_name, repo.repo_type, repo.private, repo.fork), "desc": repo.description, "owner": repo.user.username, "action": repo_actions(repo.repo_name), }) c.data = json.dumps({ "totalRecords": total_records, "startIndex": 0, "sort": "name", "dir": "asc", "records": repos_data }) return render('admin/repos/repos.html')
def jsonify(func, *args, **kwargs): """Action decorator that formats output for JSON Given a function that will return content, this decorator will turn the result into JSON, with a content-type of 'application/json' and output it. """ from pylons.decorators.util import get_pylons from rhodecode.lib.compat import json pylons = get_pylons(args) pylons.response.headers['Content-Type'] = 'application/json; charset=utf-8' data = func(*args, **kwargs) if isinstance(data, (list, tuple)): msg = "JSON responses with Array envelopes are susceptible to " \ "cross-site data leak attacks, see " \ "http://wiki.pylonshq.com/display/pylonsfaq/Warnings" warnings.warn(msg, Warning, 2) log.warning(msg) log.debug("Returning JSON wrapped action output") return json.dumps(data, encoding='utf-8')
def backend(self, request, environ): """ WSGI Response producer for HTTP POST Git Smart HTTP requests. Reads commands and data from HTTP POST's body. returns an iterator obj with contents of git command's response to stdout """ git_command = self._get_fixedpath(request.path_info) if git_command not in self.commands: log.debug('command %s not allowed' % git_command) return exc.HTTPMethodNotAllowed() if 'CONTENT_LENGTH' in environ: inputstream = FileWrapper(environ['wsgi.input'], request.content_length) else: inputstream = environ['wsgi.input'] try: gitenv = os.environ from rhodecode.lib.compat import json gitenv['RHODECODE_EXTRAS'] = json.dumps(self.extras) # forget all configs gitenv['GIT_CONFIG_NOGLOBAL'] = '1' opts = dict( env=gitenv, cwd=os.getcwd() ) cmd = r'git %s --stateless-rpc "%s"' % (git_command[4:], self.content_path), log.debug('handling cmd %s' % cmd) out = subprocessio.SubprocessIOChunker( cmd, inputstream=inputstream, **opts ) except EnvironmentError, e: log.error(traceback.format_exc()) raise exc.HTTPExpectationFailed()
def rhodecode_api_post(self, method, args): """Send a generic API post to Rhodecode. This will generate the UUID for validation check after the response is returned. Handle errors and get the result back. """ uid = str(uuid.uuid1()) data = self.get_api_data(uid, method, args) data = json.dumps(data) headers = {'content-type': 'text/plain'} req = urllib2.Request(self.url, data, headers) response = urllib2.urlopen(req) response = json.load(response) if uid != response["id"]: raise InvalidResponseIDError("UUID does not match.") if response["error"] is not None: raise RhodecodeResponseError(response["error"]) return response["result"]
def index(self, repo_name): c.dbrepo = dbrepo = c.rhodecode_db_repo c.following = self.scm_model.is_following_repo( repo_name, self.rhodecode_user.user_id) def url_generator(**kw): return url('shortlog_home', repo_name=repo_name, size=10, **kw) c.repo_changesets = RepoPage(c.rhodecode_repo, page=1, items_per_page=10, url=url_generator) if self.rhodecode_user.username == 'default': # for default(anonymous) user we don't need to pass credentials username = '' password = '' else: username = str(self.rhodecode_user.username) password = '******' parsed_url = urlparse(url.current(qualified=True)) default_clone_uri = '{scheme}://{user}{pass}{netloc}{path}' uri_tmpl = config.get('clone_uri', default_clone_uri) uri_tmpl = uri_tmpl.replace('{', '%(').replace('}', ')s') decoded_path = safe_unicode(urllib.unquote(parsed_url.path)) uri_dict = { 'user': username, 'pass': password, 'scheme': parsed_url.scheme, 'netloc': parsed_url.netloc, 'path': decoded_path } uri = uri_tmpl % uri_dict # generate another clone url by id uri_dict.update({ 'path': decoded_path.replace(repo_name, '_%s' % c.dbrepo.repo_id) }) uri_id = uri_tmpl % uri_dict c.clone_repo_url = uri c.clone_repo_url_id = uri_id c.repo_tags = OrderedDict() for name, hash_ in c.rhodecode_repo.tags.items()[:10]: try: c.repo_tags[name] = c.rhodecode_repo.get_changeset(hash_) except ChangesetError: c.repo_tags[name] = EmptyChangeset(hash_) c.repo_branches = OrderedDict() for name, hash_ in c.rhodecode_repo.branches.items()[:10]: try: c.repo_branches[name] = c.rhodecode_repo.get_changeset(hash_) except ChangesetError: c.repo_branches[name] = EmptyChangeset(hash_) td = date.today() + timedelta(days=1) td_1m = td - timedelta(days=calendar.mdays[td.month]) td_1y = td - timedelta(days=365) ts_min_m = mktime(td_1m.timetuple()) ts_min_y = mktime(td_1y.timetuple()) ts_max_y = mktime(td.timetuple()) if dbrepo.enable_statistics: c.show_stats = True c.no_data_msg = _('No data loaded yet') run_task(get_commits_stats, c.dbrepo.repo_name, ts_min_y, ts_max_y) else: c.show_stats = False c.no_data_msg = _('Statistics are disabled for this repository') c.ts_min = ts_min_m c.ts_max = ts_max_y stats = self.sa.query(Statistics)\ .filter(Statistics.repository == dbrepo)\ .scalar() c.stats_percentage = 0 if stats and stats.languages: c.no_data = False is dbrepo.enable_statistics lang_stats_d = json.loads(stats.languages) c.commit_data = stats.commit_activity c.overview_data = stats.commit_activity_combined lang_stats = ((x, { "count": y, "desc": LANGUAGES_EXTENSIONS_MAP.get(x) }) for x, y in lang_stats_d.items()) c.trending_languages = json.dumps( sorted(lang_stats, reverse=True, key=lambda k: k[1])[:10]) last_rev = stats.stat_on_revision + 1 c.repo_last_rev = c.rhodecode_repo.count()\ if c.rhodecode_repo.revisions else 0 if last_rev == 0 or c.repo_last_rev == 0: pass else: c.stats_percentage = '%.2f' % ((float( (last_rev)) / c.repo_last_rev) * 100) else: c.commit_data = json.dumps({}) c.overview_data = json.dumps([[ts_min_y, 0], [ts_max_y, 10]]) c.trending_languages = json.dumps({}) c.no_data = True c.enable_downloads = dbrepo.enable_downloads if c.enable_downloads: c.download_options = self._get_download_links(c.rhodecode_repo) c.readme_data, c.readme_file = self.__get_readme_data( c.rhodecode_db_repo.repo_name, c.rhodecode_repo) return render('summary/summary.html')
self._error = str(e) except Exception, e: log.error('Encountered unhandled exception: %s' \ % traceback.format_exc()) json_exc = JSONRPCError('Internal server error') self._error = str(json_exc) if self._error is not None: raw_response = None response = dict(id=self._req_id, result=raw_response, error=self._error) try: return json.dumps(response) except TypeError, e: log.error('API FAILED. Error encoding response: %s' % e) return json.dumps( dict(id=self._req_id, result=None, error="Error encoding response")) def _find_method(self): """ Return method named by `self._req_method` in controller if able """ log.debug('Trying to find JSON-RPC method: %s' % self._req_method) if self._req_method.startswith('_'): raise AttributeError("Method not allowed")
def index(self): # Return a rendered template p = safe_int(request.GET.get('page', 1), 1) c.user = User.get(self.rhodecode_user.user_id) c.following = self.sa.query(UserFollowing)\ .filter(UserFollowing.user_id == self.rhodecode_user.user_id)\ .options(joinedload(UserFollowing.follows_repository))\ .all() journal = self._get_journal_data(c.following) def url_generator(**kw): return url.current(filter=c.search_term, **kw) c.journal_pager = Page(journal, page=p, items_per_page=20, url=url_generator) c.journal_day_aggreagate = self._get_daily_aggregate(c.journal_pager) c.journal_data = render('journal/journal_data.html') if request.environ.get('HTTP_X_PARTIAL_XHR'): return c.journal_data repos_list = Session().query(Repository)\ .filter(Repository.user_id == self.rhodecode_user.user_id)\ .order_by(func.lower(Repository.repo_name)).all() repos_data = RepoModel().get_repos_as_dict(repos_list=repos_list, admin=True) #json used to render the grid c.data = json.dumps(repos_data) watched_repos_data = [] ## watched repos _render = RepoModel._render_datatable def quick_menu(repo_name): return _render('quick_menu', repo_name) def repo_lnk(name, rtype, private, fork_of): return _render('repo_name', name, rtype, private, fork_of, short_name=False, admin=False) def last_rev(repo_name, cs_cache): return _render('revision', repo_name, cs_cache.get('revision'), cs_cache.get('raw_id'), cs_cache.get('author'), cs_cache.get('message')) def desc(desc): from pylons import tmpl_context as c if c.visual.stylify_metatags: return h.urlify_text(h.desc_stylize(h.truncate(desc, 60))) else: return h.urlify_text(h.truncate(desc, 60)) def repo_actions(repo_name): return _render('repo_actions', repo_name) def owner_actions(user_id, username): return _render('user_name', user_id, username) def toogle_follow(repo_id): return _render('toggle_follow', repo_id) for entry in c.following: repo = entry.follows_repository cs_cache = repo.changeset_cache row = { "menu": quick_menu(repo.repo_name), "raw_name": repo.repo_name.lower(), "name": repo_lnk(repo.repo_name, repo.repo_type, repo.private, repo.fork), "last_changeset": last_rev(repo.repo_name, cs_cache), "raw_tip": cs_cache.get('revision'), "action": toogle_follow(repo.repo_id) } watched_repos_data.append(row) c.watched_data = json.dumps({ "totalRecords": len(c.following), "startIndex": 0, "sort": "name", "dir": "asc", "records": watched_repos_data }) return render('journal/journal.html')
def _handle_request(self, environ, start_response): if not is_git(environ): return self.application(environ, start_response) if not self._check_ssl(environ, start_response): return HTTPNotAcceptable('SSL REQUIRED !')(environ, start_response) ipaddr = self._get_ip_addr(environ) username = None self._git_first_op = False # skip passing error to error controller environ['pylons.status_code_redirect'] = True #====================================================================== # EXTRACT REPOSITORY NAME FROM ENV #====================================================================== try: repo_name = self.__get_repository(environ) log.debug('Extracted repo name is %s' % repo_name) except: return HTTPInternalServerError()(environ, start_response) # quick check if that dir exists... if is_valid_repo(repo_name, self.basepath, 'git') is False: return HTTPNotFound()(environ, start_response) #====================================================================== # GET ACTION PULL or PUSH #====================================================================== action = self.__get_action(environ) #====================================================================== # CHECK ANONYMOUS PERMISSION #====================================================================== if action in ['pull', 'push']: anonymous_user = self.__get_user('default') username = anonymous_user.username anonymous_perm = self._check_permission(action, anonymous_user, repo_name) if anonymous_perm is not True or anonymous_user.active is False: if anonymous_perm is not True: log.debug('Not enough credentials to access this ' 'repository as anonymous user') if anonymous_user.active is False: log.debug('Anonymous access is disabled, running ' 'authentication') #============================================================== # DEFAULT PERM FAILED OR ANONYMOUS ACCESS IS DISABLED SO WE # NEED TO AUTHENTICATE AND ASK FOR AUTH USER PERMISSIONS #============================================================== # Attempting to retrieve username from the container username = get_container_username(environ, self.config) # If not authenticated by the container, running basic auth if not username: self.authenticate.realm = \ safe_str(self.config['rhodecode_realm']) result = self.authenticate(environ) if isinstance(result, str): AUTH_TYPE.update(environ, 'basic') REMOTE_USER.update(environ, result) username = result else: return result.wsgi_application(environ, start_response) #============================================================== # CHECK PERMISSIONS FOR THIS REQUEST USING GIVEN USERNAME #============================================================== try: user = self.__get_user(username) if user is None or not user.active: return HTTPForbidden()(environ, start_response) username = user.username except: log.error(traceback.format_exc()) return HTTPInternalServerError()(environ, start_response) #check permissions for this repository perm = self._check_permission(action, user, repo_name) if perm is not True: return HTTPForbidden()(environ, start_response) # extras are injected into UI object and later available # in hooks executed by rhodecode from rhodecode import CONFIG extras = { 'ip': ipaddr, 'username': username, 'action': action, 'repository': repo_name, 'scm': 'git', 'config': CONFIG['__file__'], 'make_lock': None, 'locked_by': [None, None] } #=================================================================== # GIT REQUEST HANDLING #=================================================================== repo_path = os.path.join(safe_str(self.basepath), safe_str(repo_name)) log.debug('Repository path is %s' % repo_path) # CHECK LOCKING only if it's not ANONYMOUS USER if username != User.DEFAULT_USER: log.debug('Checking locking on repository') (make_lock, locked, locked_by) = self._check_locking_state( environ=environ, action=action, repo=repo_name, user_id=user.user_id ) # store the make_lock for later evaluation in hooks extras.update({'make_lock': make_lock, 'locked_by': locked_by}) # set the environ variables for this request os.environ['RC_SCM_DATA'] = json.dumps(extras) fix_PATH() log.debug('HOOKS extras is %s' % extras) baseui = make_ui('db') self.__inject_extras(repo_path, baseui, extras) try: # invalidate cache on push if action == 'push': self._invalidate_cache(repo_name) self._handle_githooks(repo_name, action, baseui, environ) log.info('%s action on GIT repo "%s"' % (action, repo_name)) app = self.__make_app(repo_name, repo_path, extras) return app(environ, start_response) except HTTPLockedRC, e: log.debug('Repositry LOCKED ret code 423!') return e(environ, start_response)
def index(self, repo_name): e = request.environ c.dbrepo = dbrepo = c.rhodecode_db_repo c.following = self.scm_model.is_following_repo(repo_name, self.rhodecode_user.user_id) def url_generator(**kw): return url('shortlog_home', repo_name=repo_name, size=10, **kw) c.repo_changesets = RepoPage(c.rhodecode_repo, page=1, items_per_page=10, url=url_generator) if self.rhodecode_user.username == 'default': #for default(anonymous) user we don't need to pass credentials username = '' password = '' else: username = str(self.rhodecode_user.username) password = '******' if e.get('wsgi.url_scheme') == 'https': split_s = 'https://' else: split_s = 'http://' qualified_uri = [split_s] + [url.current(qualified=True)\ .split(split_s)[-1]] uri = u'%(proto)s%(user)s%(pass)s%(rest)s' \ % {'user': username, 'pass': password, 'proto': qualified_uri[0], 'rest': qualified_uri[1]} c.clone_repo_url = uri c.repo_tags = OrderedDict() for name, hash in c.rhodecode_repo.tags.items()[:10]: try: c.repo_tags[name] = c.rhodecode_repo.get_changeset(hash) except ChangesetError: c.repo_tags[name] = EmptyChangeset(hash) c.repo_branches = OrderedDict() for name, hash in c.rhodecode_repo.branches.items()[:10]: try: c.repo_branches[name] = c.rhodecode_repo.get_changeset(hash) except ChangesetError: c.repo_branches[name] = EmptyChangeset(hash) td = date.today() + timedelta(days=1) td_1m = td - timedelta(days=calendar.mdays[td.month]) td_1y = td - timedelta(days=365) ts_min_m = mktime(td_1m.timetuple()) ts_min_y = mktime(td_1y.timetuple()) ts_max_y = mktime(td.timetuple()) if dbrepo.enable_statistics: c.show_stats = True c.no_data_msg = _('No data loaded yet') run_task(get_commits_stats, c.dbrepo.repo_name, ts_min_y, ts_max_y) else: c.show_stats = False c.no_data_msg = _('Statistics are disabled for this repository') c.ts_min = ts_min_m c.ts_max = ts_max_y stats = self.sa.query(Statistics)\ .filter(Statistics.repository == dbrepo)\ .scalar() c.stats_percentage = 0 if stats and stats.languages: c.no_data = False is dbrepo.enable_statistics lang_stats_d = json.loads(stats.languages) c.commit_data = stats.commit_activity c.overview_data = stats.commit_activity_combined lang_stats = ((x, {"count": y, "desc": LANGUAGES_EXTENSIONS_MAP.get(x)}) for x, y in lang_stats_d.items()) c.trending_languages = json.dumps( sorted(lang_stats, reverse=True, key=lambda k: k[1])[:10] ) last_rev = stats.stat_on_revision + 1 c.repo_last_rev = c.rhodecode_repo.count()\ if c.rhodecode_repo.revisions else 0 if last_rev == 0 or c.repo_last_rev == 0: pass else: c.stats_percentage = '%.2f' % ((float((last_rev)) / c.repo_last_rev) * 100) else: c.commit_data = json.dumps({}) c.overview_data = json.dumps([[ts_min_y, 0], [ts_max_y, 10]]) c.trending_languages = json.dumps({}) c.no_data = True c.enable_downloads = dbrepo.enable_downloads if c.enable_downloads: c.download_options = self._get_download_links(c.rhodecode_repo) return render('summary/summary.html')
def _build_data(apikey, method, **kw): """ Builds API data with given random ID :param random_id: :type random_id: """ random_id = random.randrange(1, 9999) return random_id, json.dumps({ "id": random_id, "api_key": apikey, "method": method, "args": kw }) jsonify = lambda obj: json.loads(json.dumps(obj)) def crash(*args, **kwargs): raise Exception('Total Crash !') def api_call(test_obj, params): response = test_obj.app.post(API_URL, content_type='application/json', params=params) return response TEST_USERS_GROUP = 'test_users_group'
if isinstance(raw_response, HTTPError): self._error = str(raw_response) except JSONRPCError, e: self._error = str(e) except Exception, e: log.error("Encountered unhandled exception: %s" % traceback.format_exc()) json_exc = JSONRPCError("Internal server error") self._error = str(json_exc) if self._error is not None: raw_response = None response = dict(result=raw_response, error=self._error) try: return json.dumps(response) except TypeError, e: log.debug("Error encoding response: %s", e) return json.dumps(dict(result=None, error="Error encoding response")) def _find_method(self): """ Return method named by `self._req_method` in controller if able """ log.debug("Trying to find JSON-RPC method: %s", self._req_method) if self._req_method.startswith("_"): raise AttributeError("Method not allowed") try: func = getattr(self, self._req_method, None) except UnicodeEncodeError:
class PullrequestsController(BaseRepoController): @LoginRequired() @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', 'repository.admin') def __before__(self): super(PullrequestsController, self).__before__() repo_model = RepoModel() c.users_array = repo_model.get_users_js() c.users_groups_array = repo_model.get_users_groups_js() def _get_repo_refs(self, repo, rev=None, branch_rev=None): """return a structure with repo's interesting changesets, suitable for the selectors in pullrequest.html""" # list named branches that has been merged to this named branch - it should probably merge back peers = [] if branch_rev: # not restricting to merge() would also get branch point and be better # (especially because it would get the branch point) ... but is currently too expensive revs = ["sort(parents(branch(id('%s')) and merge()) - branch(id('%s')))" % (branch_rev, branch_rev)] otherbranches = {} for i in scmutil.revrange(repo._repo, revs): cs = repo.get_changeset(i) otherbranches[cs.branch] = cs.raw_id for branch, node in otherbranches.iteritems(): selected = 'branch:%s:%s' % (branch, node) peers.append((selected, branch)) selected = None branches = [] for branch, branchrev in repo.branches.iteritems(): n = 'branch:%s:%s' % (branch, branchrev) branches.append((n, branch)) if rev == branchrev: selected = n bookmarks = [] for bookmark, bookmarkrev in repo.bookmarks.iteritems(): n = 'book:%s:%s' % (bookmark, bookmarkrev) bookmarks.append((n, bookmark)) if rev == bookmarkrev: selected = n tags = [] for tag, tagrev in repo.tags.iteritems(): n = 'tag:%s:%s' % (tag, tagrev) tags.append((n, tag)) if rev == tagrev and tag != 'tip': # tip is not a real tag - and its branch is better selected = n # prio 1: rev was selected as existing entry above # prio 2: create special entry for rev; rev _must_ be used specials = [] if rev and selected is None: selected = 'rev:%s:%s' % (rev, rev) specials = [(selected, '%s: %s' % (_("Changeset"), rev[:12]))] # prio 3: most recent peer branch if peers and not selected: selected = peers[0][0][0] # prio 4: tip revision if not selected: selected = 'tag:tip:%s' % repo.tags['tip'] groups = [(specials, _("Special")), (peers, _("Peer branches")), (bookmarks, _("Bookmarks")), (branches, _("Branches")), (tags, _("Tags")), ] return [g for g in groups if g[0]], selected def _get_is_allowed_change_status(self, pull_request): owner = self.rhodecode_user.user_id == pull_request.user_id reviewer = self.rhodecode_user.user_id in [x.user_id for x in pull_request.reviewers] return (self.rhodecode_user.admin or owner or reviewer) def show_all(self, repo_name): c.pull_requests = PullRequestModel().get_all(repo_name) c.repo_name = repo_name p = safe_int(request.GET.get('page', 1), 1) c.pullrequests_pager = Page(c.pull_requests, page=p, items_per_page=10) c.pullrequest_data = render('/pullrequests/pullrequest_data.html') if request.environ.get('HTTP_X_PARTIAL_XHR'): return c.pullrequest_data return render('/pullrequests/pullrequest_show_all.html') @NotAnonymous() def index(self): org_repo = c.rhodecode_db_repo if org_repo.scm_instance.alias != 'hg': log.error('Review not available for GIT REPOS') raise HTTPNotFound try: org_repo.scm_instance.get_changeset() except EmptyRepositoryError, e: h.flash(h.literal(_('There are no changesets yet')), category='warning') redirect(url('summary_home', repo_name=org_repo.repo_name)) org_rev = request.GET.get('rev_end') # rev_start is not directly useful - its parent could however be used # as default for other and thus give a simple compare view #other_rev = request.POST.get('rev_start') c.org_repos = [] c.org_repos.append((org_repo.repo_name, org_repo.repo_name)) c.default_org_repo = org_repo.repo_name c.org_refs, c.default_org_ref = self._get_repo_refs(org_repo.scm_instance, org_rev) c.other_repos = [] other_repos_info = {} def add_other_repo(repo, branch_rev=None): if repo.repo_name in other_repos_info: # shouldn't happen return c.other_repos.append((repo.repo_name, repo.repo_name)) other_refs, selected_other_ref = self._get_repo_refs(repo.scm_instance, branch_rev=branch_rev) other_repos_info[repo.repo_name] = { 'user': dict(user_id=repo.user.user_id, username=repo.user.username, firstname=repo.user.firstname, lastname=repo.user.lastname, gravatar_link=h.gravatar_url(repo.user.email, 14)), 'description': repo.description.split('\n', 1)[0], 'revs': h.select('other_ref', selected_other_ref, other_refs, class_='refs') } # add org repo to other so we can open pull request against peer branches on itself add_other_repo(org_repo, branch_rev=org_rev) c.default_other_repo = org_repo.repo_name # gather forks and add to this list ... even though it is rare to # request forks to pull from their parent for fork in org_repo.forks: add_other_repo(fork) # add parents of this fork also, but only if it's not empty if org_repo.parent and org_repo.parent.scm_instance.revisions: add_other_repo(org_repo.parent) c.default_other_repo = org_repo.parent.repo_name c.default_other_repo_info = other_repos_info[c.default_other_repo] c.other_repos_info = json.dumps(other_repos_info) return render('/pullrequests/pullrequest.html')
def lock(self, apiuser, repoid, locked=Optional(None), userid=Optional(OAttr('apiuser'))): """ Set locking state on particular repository by given user, if this command is runned by non-admin account userid is set to user who is calling this method :param apiuser: :param repoid: :param userid: :param locked: """ repo = get_repo_or_error(repoid) if HasPermissionAnyApi('hg.admin')(user=apiuser): pass elif HasRepoPermissionAnyApi('repository.admin', 'repository.write')(user=apiuser, repo_name=repo.repo_name): #make sure normal user does not pass someone else userid, #he is not allowed to do that if not isinstance(userid, Optional) and userid != apiuser.user_id: raise JSONRPCError( 'userid is not the same as your user' ) else: raise JSONRPCError('repository `%s` does not exist' % (repoid)) if isinstance(userid, Optional): userid = apiuser.user_id user = get_user_or_error(userid) if isinstance(locked, Optional): lockobj = Repository.getlock(repo) if lockobj[0] is None: return ('Repo `%s` not locked. Locked=`False`.' % (repo.repo_name)) else: userid, time_ = lockobj user = get_user_or_error(userid) return ('Repo `%s` locked by `%s`. Locked=`True`. ' 'Locked since: `%s`' % (repo.repo_name, user.username, json.dumps(time_to_datetime(time_)))) else: locked = str2bool(locked) try: if locked: Repository.lock(repo, user.user_id) else: Repository.unlock(repo) return ('User `%s` set lock state for repo `%s` to `%s`' % (user.username, repo.repo_name, locked)) except Exception: log.error(traceback.format_exc()) raise JSONRPCError( 'Error occurred locking repository `%s`' % repo.repo_name )
def get_commits_stats(repo_name, ts_min_y, ts_max_y): log = get_logger(get_commits_stats) DBS = get_session() lockkey = __get_lockkey('get_commits_stats', repo_name, ts_min_y, ts_max_y) lockkey_path = config['here'] log.info('running task with lockkey %s' % lockkey) try: lock = l = DaemonLock(file_=jn(lockkey_path, lockkey)) # for js data compatibility cleans the key for person from ' akc = lambda k: person(k).replace('"', "") co_day_auth_aggr = {} commits_by_day_aggregate = {} repo = Repository.get_by_repo_name(repo_name) if repo is None: return True repo = repo.scm_instance repo_size = repo.count() # return if repo have no revisions if repo_size < 1: lock.release() return True skip_date_limit = True parse_limit = int(config['app_conf'].get('commit_parse_limit')) last_rev = None last_cs = None timegetter = itemgetter('time') dbrepo = DBS.query(Repository)\ .filter(Repository.repo_name == repo_name).scalar() cur_stats = DBS.query(Statistics)\ .filter(Statistics.repository == dbrepo).scalar() if cur_stats is not None: last_rev = cur_stats.stat_on_revision if last_rev == repo.get_changeset().revision and repo_size > 1: # pass silently without any work if we're not on first revision or # current state of parsing revision(from db marker) is the # last revision lock.release() return True if cur_stats: commits_by_day_aggregate = OrderedDict(json.loads( cur_stats.commit_activity_combined)) co_day_auth_aggr = json.loads(cur_stats.commit_activity) log.debug('starting parsing %s' % parse_limit) lmktime = mktime last_rev = last_rev + 1 if last_rev >= 0 else 0 log.debug('Getting revisions from %s to %s' % ( last_rev, last_rev + parse_limit) ) for cs in repo[last_rev:last_rev + parse_limit]: log.debug('parsing %s' % cs) last_cs = cs # remember last parsed changeset k = lmktime([cs.date.timetuple()[0], cs.date.timetuple()[1], cs.date.timetuple()[2], 0, 0, 0, 0, 0, 0]) if akc(cs.author) in co_day_auth_aggr: try: l = [timegetter(x) for x in co_day_auth_aggr[akc(cs.author)]['data']] time_pos = l.index(k) except ValueError: time_pos = False if time_pos >= 0 and time_pos is not False: datadict = \ co_day_auth_aggr[akc(cs.author)]['data'][time_pos] datadict["commits"] += 1 datadict["added"] += len(cs.added) datadict["changed"] += len(cs.changed) datadict["removed"] += len(cs.removed) else: if k >= ts_min_y and k <= ts_max_y or skip_date_limit: datadict = {"time": k, "commits": 1, "added": len(cs.added), "changed": len(cs.changed), "removed": len(cs.removed), } co_day_auth_aggr[akc(cs.author)]['data']\ .append(datadict) else: if k >= ts_min_y and k <= ts_max_y or skip_date_limit: co_day_auth_aggr[akc(cs.author)] = { "label": akc(cs.author), "data": [{"time":k, "commits":1, "added":len(cs.added), "changed":len(cs.changed), "removed":len(cs.removed), }], "schema": ["commits"], } #gather all data by day if k in commits_by_day_aggregate: commits_by_day_aggregate[k] += 1 else: commits_by_day_aggregate[k] = 1 overview_data = sorted(commits_by_day_aggregate.items(), key=itemgetter(0)) if not co_day_auth_aggr: co_day_auth_aggr[akc(repo.contact)] = { "label": akc(repo.contact), "data": [0, 1], "schema": ["commits"], } stats = cur_stats if cur_stats else Statistics() stats.commit_activity = json.dumps(co_day_auth_aggr) stats.commit_activity_combined = json.dumps(overview_data) log.debug('last revison %s' % last_rev) leftovers = len(repo.revisions[last_rev:]) log.debug('revisions to parse %s' % leftovers) if last_rev == 0 or leftovers < parse_limit: log.debug('getting code trending stats') stats.languages = json.dumps(__get_codes_stats(repo_name)) try: stats.repository = dbrepo stats.stat_on_revision = last_cs.revision if last_cs else 0 DBS.add(stats) DBS.commit() except: log.error(traceback.format_exc()) DBS.rollback() lock.release() return False # final release lock.release() # execute another task if celery is enabled if len(repo.revisions) > 1 and CELERY_ON: run_task(get_commits_stats, repo_name, ts_min_y, ts_max_y) return True except LockHeld: log.info('LockHeld') return 'Task with key %s already running' % lockkey
except JSONRPCError, e: self._error = str(e) except Exception, e: log.error('Encountered unhandled exception: %s' \ % traceback.format_exc()) json_exc = JSONRPCError('Internal server error') self._error = str(json_exc) if self._error is not None: raw_response = None response = dict(id=self._req_id, result=raw_response, error=self._error) try: return json.dumps(response) except TypeError, e: log.error('API FAILED. Error encoding response: %s' % e) return json.dumps( dict( id=self._req_id, result=None, error="Error encoding response" ) ) def _find_method(self): """ Return method named by `self._req_method` in controller if able """ log.debug('Trying to find JSON-RPC method: %s' % self._req_method)
def create(self, description, owner, gist_mapping, gist_type=Gist.GIST_PUBLIC, lifetime=-1): """ :param description: description of the gist :param owner: user who created this gist :param gist_mapping: mapping {filename:{'content':content},...} :param gist_type: type of gist private/public :param lifetime: in minutes, -1 == forever """ gist_id = safe_unicode(unique_id(20)) lifetime = safe_int(lifetime, -1) gist_expires = time.time() + (lifetime * 60) if lifetime != -1 else -1 log.debug('set GIST expiration date to: %s' % (time_to_datetime(gist_expires) if gist_expires != -1 else 'forever')) #create the Database version gist = Gist() gist.gist_description = description gist.gist_access_id = gist_id gist.gist_owner = owner.user_id gist.gist_expires = gist_expires gist.gist_type = safe_unicode(gist_type) self.sa.add(gist) self.sa.flush() if gist_type == Gist.GIST_PUBLIC: # use DB ID for easy to use GIST ID gist_id = safe_unicode(gist.gist_id) gist.gist_access_id = gist_id self.sa.add(gist) gist_repo_path = os.path.join(GIST_STORE_LOC, gist_id) log.debug('Creating new %s GIST repo in %s' % (gist_type, gist_repo_path)) repo = RepoModel()._create_repo(repo_name=gist_repo_path, alias='hg', parent=None) processed_mapping = {} for filename in gist_mapping: if filename != os.path.basename(filename): raise Exception('Filename cannot be inside a directory') content = gist_mapping[filename]['content'] #TODO: expand support for setting explicit lexers # if lexer is None: # try: # lexer = pygments.lexers.guess_lexer_for_filename(filename,content) # except pygments.util.ClassNotFound: # lexer = 'text' processed_mapping[filename] = {'content': content} # now create single multifile commit message = 'added file' message += 's: ' if len(processed_mapping) > 1 else ': ' message += ', '.join([x for x in processed_mapping]) #fake RhodeCode Repository object fake_repo = AttributeDict(dict( repo_name=gist_repo_path, scm_instance_no_cache=lambda: repo, )) ScmModel().create_nodes( user=owner.user_id, repo=fake_repo, message=message, nodes=processed_mapping, trigger_push_hook=False ) # store metadata inside the gist, this can be later used for imports # or gist identification metadata = { 'gist_db_id': gist.gist_id, 'gist_access_id': gist.gist_access_id, 'gist_owner_id': owner.user_id, 'gist_type': gist.gist_type, 'gist_exipres': gist.gist_expires } with open(os.path.join(repo.path, '.hg', GIST_METADATA_FILE), 'wb') as f: f.write(json.dumps(metadata)) return gist
def _set_extras(extras): os.environ['RC_SCM_DATA'] = json.dumps(extras)
def get_commits_stats(repo_name, ts_min_y, ts_max_y, recurse_limit=100): log = get_logger(get_commits_stats) DBS = get_session() lockkey = __get_lockkey('get_commits_stats', repo_name, ts_min_y, ts_max_y) lockkey_path = config['app_conf']['cache_dir'] log.info('running task with lockkey %s' % lockkey) try: lock = l = DaemonLock(file_=jn(lockkey_path, lockkey)) # for js data compatibility cleans the key for person from ' akc = lambda k: person(k).replace('"', "") co_day_auth_aggr = {} commits_by_day_aggregate = {} repo = Repository.get_by_repo_name(repo_name) if repo is None: return True repo = repo.scm_instance repo_size = repo.count() # return if repo have no revisions if repo_size < 1: lock.release() return True skip_date_limit = True parse_limit = int(config['app_conf'].get('commit_parse_limit')) last_rev = None last_cs = None timegetter = itemgetter('time') dbrepo = DBS.query(Repository)\ .filter(Repository.repo_name == repo_name).scalar() cur_stats = DBS.query(Statistics)\ .filter(Statistics.repository == dbrepo).scalar() if cur_stats is not None: last_rev = cur_stats.stat_on_revision if last_rev == repo.get_changeset().revision and repo_size > 1: # pass silently without any work if we're not on first revision or # current state of parsing revision(from db marker) is the # last revision lock.release() return True if cur_stats: commits_by_day_aggregate = OrderedDict( json.loads(cur_stats.commit_activity_combined)) co_day_auth_aggr = json.loads(cur_stats.commit_activity) log.debug('starting parsing %s' % parse_limit) lmktime = mktime last_rev = last_rev + 1 if last_rev >= 0 else 0 log.debug('Getting revisions from %s to %s' % (last_rev, last_rev + parse_limit)) for cs in repo[last_rev:last_rev + parse_limit]: log.debug('parsing %s' % cs) last_cs = cs # remember last parsed changeset k = lmktime([ cs.date.timetuple()[0], cs.date.timetuple()[1], cs.date.timetuple()[2], 0, 0, 0, 0, 0, 0 ]) if akc(cs.author) in co_day_auth_aggr: try: l = [ timegetter(x) for x in co_day_auth_aggr[akc(cs.author)]['data'] ] time_pos = l.index(k) except ValueError: time_pos = None if time_pos >= 0 and time_pos is not None: datadict = \ co_day_auth_aggr[akc(cs.author)]['data'][time_pos] datadict["commits"] += 1 datadict["added"] += len(cs.added) datadict["changed"] += len(cs.changed) datadict["removed"] += len(cs.removed) else: if k >= ts_min_y and k <= ts_max_y or skip_date_limit: datadict = { "time": k, "commits": 1, "added": len(cs.added), "changed": len(cs.changed), "removed": len(cs.removed), } co_day_auth_aggr[akc(cs.author)]['data']\ .append(datadict) else: if k >= ts_min_y and k <= ts_max_y or skip_date_limit: co_day_auth_aggr[akc(cs.author)] = { "label": akc(cs.author), "data": [{ "time": k, "commits": 1, "added": len(cs.added), "changed": len(cs.changed), "removed": len(cs.removed), }], "schema": ["commits"], } #gather all data by day if k in commits_by_day_aggregate: commits_by_day_aggregate[k] += 1 else: commits_by_day_aggregate[k] = 1 overview_data = sorted(commits_by_day_aggregate.items(), key=itemgetter(0)) if not co_day_auth_aggr: co_day_auth_aggr[akc(repo.contact)] = { "label": akc(repo.contact), "data": [0, 1], "schema": ["commits"], } stats = cur_stats if cur_stats else Statistics() stats.commit_activity = json.dumps(co_day_auth_aggr) stats.commit_activity_combined = json.dumps(overview_data) log.debug('last revison %s' % last_rev) leftovers = len(repo.revisions[last_rev:]) log.debug('revisions to parse %s' % leftovers) if last_rev == 0 or leftovers < parse_limit: log.debug('getting code trending stats') stats.languages = json.dumps(__get_codes_stats(repo_name)) try: stats.repository = dbrepo stats.stat_on_revision = last_cs.revision if last_cs else 0 DBS.add(stats) DBS.commit() except: log.error(traceback.format_exc()) DBS.rollback() lock.release() return False # final release lock.release() # execute another task if celery is enabled if len(repo.revisions) > 1 and CELERY_ON and recurse_limit > 0: recurse_limit -= 1 run_task(get_commits_stats, repo_name, ts_min_y, ts_max_y, recurse_limit) if recurse_limit <= 0: log.debug('Breaking recursive mode due to reach of recurse limit') return True except LockHeld: log.info('LockHeld') return 'Task with key %s already running' % lockkey
def _handle_request(self, environ, start_response): if not is_git(environ): return self.application(environ, start_response) if not self._check_ssl(environ, start_response): return HTTPNotAcceptable('SSL REQUIRED !')(environ, start_response) ip_addr = self._get_ip_addr(environ) username = None self._git_first_op = False # skip passing error to error controller environ['pylons.status_code_redirect'] = True #====================================================================== # EXTRACT REPOSITORY NAME FROM ENV #====================================================================== try: repo_name = self.__get_repository(environ) log.debug('Extracted repo name is %s' % repo_name) except Exception: return HTTPInternalServerError()(environ, start_response) # quick check if that dir exists... if not is_valid_repo(repo_name, self.basepath, 'git'): return HTTPNotFound()(environ, start_response) #====================================================================== # GET ACTION PULL or PUSH #====================================================================== action = self.__get_action(environ) #====================================================================== # CHECK ANONYMOUS PERMISSION #====================================================================== if action in ['pull', 'push']: anonymous_user = self.__get_user('default') username = anonymous_user.username anonymous_perm = self._check_permission(action, anonymous_user, repo_name, ip_addr) if not anonymous_perm or not anonymous_user.active: if not anonymous_perm: log.debug('Not enough credentials to access this ' 'repository as anonymous user') if not anonymous_user.active: log.debug('Anonymous access is disabled, running ' 'authentication') #============================================================== # DEFAULT PERM FAILED OR ANONYMOUS ACCESS IS DISABLED SO WE # NEED TO AUTHENTICATE AND ASK FOR AUTH USER PERMISSIONS #============================================================== # Attempting to retrieve username from the container username = get_container_username(environ, self.config) # If not authenticated by the container, running basic auth if not username: self.authenticate.realm = \ safe_str(self.config['rhodecode_realm']) result = self.authenticate(environ) if isinstance(result, str): AUTH_TYPE.update(environ, 'basic') REMOTE_USER.update(environ, result) username = result else: return result.wsgi_application(environ, start_response) #============================================================== # CHECK PERMISSIONS FOR THIS REQUEST USING GIVEN USERNAME #============================================================== try: user = self.__get_user(username) if user is None or not user.active: return HTTPForbidden()(environ, start_response) username = user.username except Exception: log.error(traceback.format_exc()) return HTTPInternalServerError()(environ, start_response) #check permissions for this repository perm = self._check_permission(action, user, repo_name, ip_addr) if not perm: return HTTPForbidden()(environ, start_response) # extras are injected into UI object and later available # in hooks executed by rhodecode from rhodecode import CONFIG server_url = get_server_url(environ) extras = { 'ip': ip_addr, 'username': username, 'action': action, 'repository': repo_name, 'scm': 'git', 'config': CONFIG['__file__'], 'server_url': server_url, 'make_lock': None, 'locked_by': [None, None] } #=================================================================== # GIT REQUEST HANDLING #=================================================================== str_repo_name = safe_str(repo_name) repo_path = os.path.join(safe_str(self.basepath), str_repo_name) log.debug('Repository path is %s' % repo_path) # CHECK LOCKING only if it's not ANONYMOUS USER if username != User.DEFAULT_USER: log.debug('Checking locking on repository') (make_lock, locked, locked_by) = self._check_locking_state(environ=environ, action=action, repo=repo_name, user_id=user.user_id) # store the make_lock for later evaluation in hooks extras.update({'make_lock': make_lock, 'locked_by': locked_by}) # set the environ variables for this request os.environ['RC_SCM_DATA'] = json.dumps(extras) fix_PATH() log.debug('HOOKS extras is %s' % extras) baseui = make_ui('db') self.__inject_extras(repo_path, baseui, extras) try: self._handle_githooks(repo_name, action, baseui, environ) log.info('%s action on GIT repo "%s" by "%s" from %s' % (action, str_repo_name, safe_str(username), ip_addr)) app = self.__make_app(repo_name, repo_path, extras) return app(environ, start_response) except HTTPLockedRC, e: _code = CONFIG.get('lock_ret_code') log.debug('Repository LOCKED ret code %s!' % (_code)) return e(environ, start_response)
class PullrequestsController(BaseRepoController): def __before__(self): super(PullrequestsController, self).__before__() repo_model = RepoModel() c.users_array = repo_model.get_users_js() c.users_groups_array = repo_model.get_users_groups_js() def _get_repo_refs(self, repo, rev=None, branch=None, branch_rev=None): """return a structure with repo's interesting changesets, suitable for the selectors in pullrequest.html rev: a revision that must be in the list somehow and selected by default branch: a branch that must be in the list and selected by default - even if closed branch_rev: a revision of which peers should be preferred and available.""" # list named branches that has been merged to this named branch - it should probably merge back peers = [] if rev: rev = safe_str(rev) if branch: branch = safe_str(branch) if branch_rev: branch_rev = safe_str(branch_rev) # not restricting to merge() would also get branch point and be better # (especially because it would get the branch point) ... but is currently too expensive otherbranches = {} for i in repo._repo.revs( "sort(parents(branch(id(%s)) and merge()) - branch(id(%s)))", branch_rev, branch_rev): cs = repo.get_changeset(i) otherbranches[cs.branch] = cs.raw_id for abranch, node in otherbranches.iteritems(): selected = 'branch:%s:%s' % (abranch, node) peers.append((selected, abranch)) selected = None branches = [] for abranch, branchrev in repo.branches.iteritems(): n = 'branch:%s:%s' % (abranch, branchrev) branches.append((n, abranch)) if rev == branchrev: selected = n if branch == abranch: selected = n branch = None if branch: # branch not in list - it is probably closed revs = repo._repo.revs('max(branch(%s))', branch) if revs: cs = repo.get_changeset(revs[0]) selected = 'branch:%s:%s' % (branch, cs.raw_id) branches.append((selected, branch)) bookmarks = [] for bookmark, bookmarkrev in repo.bookmarks.iteritems(): n = 'book:%s:%s' % (bookmark, bookmarkrev) bookmarks.append((n, bookmark)) if rev == bookmarkrev: selected = n tags = [] for tag, tagrev in repo.tags.iteritems(): n = 'tag:%s:%s' % (tag, tagrev) tags.append((n, tag)) if rev == tagrev and tag != 'tip': # tip is not a real tag - and its branch is better selected = n # prio 1: rev was selected as existing entry above # prio 2: create special entry for rev; rev _must_ be used specials = [] if rev and selected is None: selected = 'rev:%s:%s' % (rev, rev) specials = [(selected, '%s: %s' % (_("Changeset"), rev[:12]))] # prio 3: most recent peer branch if peers and not selected: selected = peers[0][0][0] # prio 4: tip revision if not selected: selected = 'tag:tip:%s' % repo.tags['tip'] groups = [ (specials, _("Special")), (peers, _("Peer branches")), (bookmarks, _("Bookmarks")), (branches, _("Branches")), (tags, _("Tags")), ] return [g for g in groups if g[0]], selected def _get_is_allowed_change_status(self, pull_request): owner = self.rhodecode_user.user_id == pull_request.user_id reviewer = self.rhodecode_user.user_id in [ x.user_id for x in pull_request.reviewers ] return (self.rhodecode_user.admin or owner or reviewer) def _load_compare_data(self, pull_request, enable_comments=True): """ Load context data needed for generating compare diff :param pull_request: """ org_repo = pull_request.org_repo (org_ref_type, org_ref_name, org_ref_rev) = pull_request.org_ref.split(':') other_repo = org_repo (other_ref_type, other_ref_name, other_ref_rev) = pull_request.other_ref.split(':') # despite opening revisions for bookmarks/branches/tags, we always # convert this to rev to prevent changes after bookmark or branch change org_ref = ('rev', org_ref_rev) other_ref = ('rev', other_ref_rev) c.org_repo = org_repo c.other_repo = other_repo c.fulldiff = fulldiff = request.GET.get('fulldiff') c.cs_ranges = [ org_repo.get_changeset(x) for x in pull_request.revisions ] c.statuses = org_repo.statuses([x.raw_id for x in c.cs_ranges]) c.org_ref = org_ref[1] c.org_ref_type = org_ref[0] c.other_ref = other_ref[1] c.other_ref_type = other_ref[0] diff_limit = self.cut_off_limit if not fulldiff else None # we swap org/other ref since we run a simple diff on one repo log.debug('running diff between %s and %s in %s' % (other_ref, org_ref, org_repo.scm_instance.path)) txtdiff = org_repo.scm_instance.get_diff(rev1=safe_str(other_ref[1]), rev2=safe_str(org_ref[1])) diff_processor = diffs.DiffProcessor(txtdiff or '', format='gitdiff', diff_limit=diff_limit) _parsed = diff_processor.prepare() c.limited_diff = False if isinstance(_parsed, LimitedDiffContainer): c.limited_diff = True c.files = [] c.changes = {} c.lines_added = 0 c.lines_deleted = 0 for f in _parsed: st = f['stats'] c.lines_added += st['added'] c.lines_deleted += st['deleted'] fid = h.FID('', f['filename']) c.files.append([fid, f['operation'], f['filename'], f['stats']]) htmldiff = diff_processor.as_html(enable_comments=enable_comments, parsed_lines=[f]) c.changes[fid] = [f['operation'], f['filename'], htmldiff] @LoginRequired() @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', 'repository.admin') def show_all(self, repo_name): c.from_ = request.GET.get('from_') or '' c.closed = request.GET.get('closed') or '' c.pull_requests = PullRequestModel().get_all(repo_name, from_=c.from_, closed=c.closed) c.repo_name = repo_name p = safe_int(request.GET.get('page', 1), 1) c.pullrequests_pager = Page(c.pull_requests, page=p, items_per_page=10) c.pullrequest_data = render('/pullrequests/pullrequest_data.html') if request.environ.get('HTTP_X_PARTIAL_XHR'): return c.pullrequest_data return render('/pullrequests/pullrequest_show_all.html') @LoginRequired() @NotAnonymous() @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', 'repository.admin') def index(self): org_repo = c.rhodecode_db_repo if org_repo.scm_instance.alias != 'hg': log.error('Review not available for GIT REPOS') raise HTTPNotFound try: org_repo.scm_instance.get_changeset() except EmptyRepositoryError, e: h.flash(h.literal(_('There are no changesets yet')), category='warning') redirect(url('summary_home', repo_name=org_repo.repo_name)) org_rev = request.GET.get('rev_end') # rev_start is not directly useful - its parent could however be used # as default for other and thus give a simple compare view #other_rev = request.POST.get('rev_start') branch = request.GET.get('branch') c.org_repos = [] c.org_repos.append((org_repo.repo_name, org_repo.repo_name)) c.default_org_repo = org_repo.repo_name c.org_refs, c.default_org_ref = self._get_repo_refs( org_repo.scm_instance, rev=org_rev, branch=branch) c.other_repos = [] other_repos_info = {} def add_other_repo(repo, branch_rev=None): if repo.repo_name in other_repos_info: # shouldn't happen return c.other_repos.append((repo.repo_name, repo.repo_name)) other_refs, selected_other_ref = self._get_repo_refs( repo.scm_instance, branch_rev=branch_rev) other_repos_info[repo.repo_name] = { 'user': dict(user_id=repo.user.user_id, username=repo.user.username, firstname=repo.user.firstname, lastname=repo.user.lastname, gravatar_link=h.gravatar_url(repo.user.email, 14)), 'description': repo.description.split('\n', 1)[0], 'revs': h.select('other_ref', selected_other_ref, other_refs, class_='refs') } # add org repo to other so we can open pull request against peer branches on itself add_other_repo(org_repo, branch_rev=org_rev) c.default_other_repo = org_repo.repo_name # gather forks and add to this list ... even though it is rare to # request forks to pull from their parent for fork in org_repo.forks: add_other_repo(fork) # add parents of this fork also, but only if it's not empty if org_repo.parent and org_repo.parent.scm_instance.revisions: add_other_repo(org_repo.parent) c.default_other_repo = org_repo.parent.repo_name c.default_other_repo_info = other_repos_info[c.default_other_repo] c.other_repos_info = json.dumps(other_repos_info) return render('/pullrequests/pullrequest.html')
def _handle_request(self, environ, start_response): if not is_mercurial(environ): return self.application(environ, start_response) if not self._check_ssl(environ, start_response): return HTTPNotAcceptable("SSL REQUIRED !")(environ, start_response) ip_addr = self._get_ip_addr(environ) username = None # skip passing error to error controller environ["pylons.status_code_redirect"] = True # ====================================================================== # EXTRACT REPOSITORY NAME FROM ENV # ====================================================================== try: repo_name = environ["REPO_NAME"] = self.__get_repository(environ) log.debug("Extracted repo name is %s" % repo_name) except Exception: return HTTPInternalServerError()(environ, start_response) # quick check if that dir exists... if not is_valid_repo(repo_name, self.basepath, "hg"): return HTTPNotFound()(environ, start_response) # ====================================================================== # GET ACTION PULL or PUSH # ====================================================================== action = self.__get_action(environ) # ====================================================================== # CHECK ANONYMOUS PERMISSION # ====================================================================== if action in ["pull", "push"]: anonymous_user = self.__get_user("default") username = anonymous_user.username anonymous_perm = self._check_permission(action, anonymous_user, repo_name, ip_addr) if not anonymous_perm or not anonymous_user.active: if not anonymous_perm: log.debug("Not enough credentials to access this " "repository as anonymous user") if not anonymous_user.active: log.debug("Anonymous access is disabled, running " "authentication") # ============================================================== # DEFAULT PERM FAILED OR ANONYMOUS ACCESS IS DISABLED SO WE # NEED TO AUTHENTICATE AND ASK FOR AUTH USER PERMISSIONS # ============================================================== # Attempting to retrieve username from the container username = get_container_username(environ, self.config) # If not authenticated by the container, running basic auth if not username: self.authenticate.realm = safe_str(self.config["rhodecode_realm"]) result = self.authenticate(environ) if isinstance(result, str): AUTH_TYPE.update(environ, "basic") REMOTE_USER.update(environ, result) username = result else: return result.wsgi_application(environ, start_response) # ============================================================== # CHECK PERMISSIONS FOR THIS REQUEST USING GIVEN USERNAME # ============================================================== try: user = self.__get_user(username) if user is None or not user.active: return HTTPForbidden()(environ, start_response) username = user.username except Exception: log.error(traceback.format_exc()) return HTTPInternalServerError()(environ, start_response) # check permissions for this repository perm = self._check_permission(action, user, repo_name, ip_addr) if not perm: return HTTPForbidden()(environ, start_response) # extras are injected into mercurial UI object and later available # in hg hooks executed by rhodecode from rhodecode import CONFIG server_url = get_server_url(environ) extras = { "ip": ip_addr, "username": username, "action": action, "repository": repo_name, "scm": "hg", "config": CONFIG["__file__"], "server_url": server_url, "make_lock": None, "locked_by": [None, None], } # ====================================================================== # MERCURIAL REQUEST HANDLING # ====================================================================== str_repo_name = safe_str(repo_name) repo_path = os.path.join(safe_str(self.basepath), str_repo_name) log.debug("Repository path is %s" % repo_path) # CHECK LOCKING only if it's not ANONYMOUS USER if username != User.DEFAULT_USER: log.debug("Checking locking on repository") (make_lock, locked, locked_by) = self._check_locking_state( environ=environ, action=action, repo=repo_name, user_id=user.user_id ) # store the make_lock for later evaluation in hooks extras.update({"make_lock": make_lock, "locked_by": locked_by}) # set the environ variables for this request os.environ["RC_SCM_DATA"] = json.dumps(extras) fix_PATH() log.debug("HOOKS extras is %s" % extras) baseui = make_ui("db") self.__inject_extras(repo_path, baseui, extras) try: log.info('%s action on HG repo "%s" by "%s" from %s' % (action, str_repo_name, safe_str(username), ip_addr)) app = self.__make_app(repo_path, baseui, extras) return app(environ, start_response) except RepoError, e: if str(e).find("not found") != -1: return HTTPNotFound()(environ, start_response)
def index(self, repo_name): c.dbrepo = dbrepo = c.rhodecode_db_repo c.following = self.scm_model.is_following_repo(repo_name, self.rhodecode_user.user_id) def url_generator(**kw): return url('shortlog_home', repo_name=repo_name, size=10, **kw) c.repo_changesets = RepoPage(c.rhodecode_repo, page=1, items_per_page=10, url=url_generator) if self.rhodecode_user.username == 'default': # for default(anonymous) user we don't need to pass credentials username = '' password = '' else: username = str(self.rhodecode_user.username) password = '******' parsed_url = urlparse(url.current(qualified=True)) default_clone_uri = '{scheme}://{user}{pass}{netloc}{path}' uri_tmpl = config.get('clone_uri', default_clone_uri) uri_tmpl = uri_tmpl.replace('{', '%(').replace('}', ')s') decoded_path = safe_unicode(urllib.unquote(parsed_url.path)) uri_dict = { 'user': username, 'pass': password, 'scheme': parsed_url.scheme, 'netloc': parsed_url.netloc, 'path': decoded_path } uri = uri_tmpl % uri_dict # generate another clone url by id uri_dict.update( {'path': decoded_path.replace(repo_name, '_%s' % c.dbrepo.repo_id)} ) uri_id = uri_tmpl % uri_dict c.clone_repo_url = uri c.clone_repo_url_id = uri_id c.repo_tags = OrderedDict() for name, hash_ in c.rhodecode_repo.tags.items()[:10]: try: c.repo_tags[name] = c.rhodecode_repo.get_changeset(hash_) except ChangesetError: c.repo_tags[name] = EmptyChangeset(hash_) c.repo_branches = OrderedDict() for name, hash_ in c.rhodecode_repo.branches.items()[:10]: try: c.repo_branches[name] = c.rhodecode_repo.get_changeset(hash_) except ChangesetError: c.repo_branches[name] = EmptyChangeset(hash_) td = date.today() + timedelta(days=1) td_1m = td - timedelta(days=calendar.mdays[td.month]) td_1y = td - timedelta(days=365) ts_min_m = mktime(td_1m.timetuple()) ts_min_y = mktime(td_1y.timetuple()) ts_max_y = mktime(td.timetuple()) if dbrepo.enable_statistics: c.show_stats = True c.no_data_msg = _('No data loaded yet') run_task(get_commits_stats, c.dbrepo.repo_name, ts_min_y, ts_max_y) else: c.show_stats = False c.no_data_msg = _('Statistics are disabled for this repository') c.ts_min = ts_min_m c.ts_max = ts_max_y stats = self.sa.query(Statistics)\ .filter(Statistics.repository == dbrepo)\ .scalar() c.stats_percentage = 0 if stats and stats.languages: c.no_data = False is dbrepo.enable_statistics lang_stats_d = json.loads(stats.languages) c.commit_data = stats.commit_activity c.overview_data = stats.commit_activity_combined lang_stats = ((x, {"count": y, "desc": LANGUAGES_EXTENSIONS_MAP.get(x)}) for x, y in lang_stats_d.items()) c.trending_languages = json.dumps( sorted(lang_stats, reverse=True, key=lambda k: k[1])[:10] ) last_rev = stats.stat_on_revision + 1 c.repo_last_rev = c.rhodecode_repo.count()\ if c.rhodecode_repo.revisions else 0 if last_rev == 0 or c.repo_last_rev == 0: pass else: c.stats_percentage = '%.2f' % ((float((last_rev)) / c.repo_last_rev) * 100) else: c.commit_data = json.dumps({}) c.overview_data = json.dumps([[ts_min_y, 0], [ts_max_y, 10]]) c.trending_languages = json.dumps({}) c.no_data = True c.enable_downloads = dbrepo.enable_downloads if c.enable_downloads: c.download_options = self._get_download_links(c.rhodecode_repo) c.readme_data, c.readme_file = self.__get_readme_data( c.rhodecode_db_repo.repo_name, c.rhodecode_repo ) return render('summary/summary.html')
def jsonrpc_error(message, code=None): """Generate a Response object with a JSON-RPC error body""" return Response(body=json.dumps(dict(result=None, error=message)))