def error_handler(exception, request): # TODO: dan: replace the old pylons error controller with this from rhodecode.model.settings import SettingsModel from rhodecode.lib.utils2 import AttributeDict try: rc_config = SettingsModel().get_all_settings() except Exception: log.exception('failed to fetch settings') rc_config = {} base_response = HTTPInternalServerError() # prefer original exception for the response since it may have headers set if isinstance(exception, HTTPError): base_response = exception c = AttributeDict() c.error_message = base_response.status c.error_explanation = base_response.explanation or str(base_response) c.visual = AttributeDict() c.visual.rhodecode_support_url = ( request.registry.settings.get('rhodecode_support_url') or request.route_url('rhodecode_support')) c.redirect_time = 0 c.rhodecode_name = rc_config.get('rhodecode_title', '') if not c.rhodecode_name: c.rhodecode_name = 'Rhodecode' response = render_to_response('/errors/error_document.html', {'c': c}, request=request, response=base_response) return response
def get_commits(self, commit_ids): commits = [] if not filter(lambda v: v != '', commit_ids): return commits repo = None if self.parse_commits: repo = self.user_log.repository.scm_instance() for commit_id in commit_ids[:self.commits_top_limit]: _op, _name = _get_op(commit_id) # we want parsed commits, or new log store format is bad if self.parse_commits: try: commit = repo.get_commit(commit_id=commit_id) commits.append(commit) except CommitDoesNotExistError: log.error( 'cannot find commit id %s in this repository', commit_id) commits.append(commit_id) continue else: fake_commit = AttributeDict({ 'short_id': commit_id[:12], 'raw_id': commit_id, 'message': '', 'op': _op, 'ref_name': _name }) commits.append(fake_commit) return commits
def settings_issuetracker(self): """GET /admin/settings/issue-tracker: All items in the collection""" # url('admin_settings_issuetracker') c.active = 'issuetracker' defaults = SettingsModel().get_all_settings() entry_key = 'rhodecode_issuetracker_pat_' c.issuetracker_entries = {} for k, v in defaults.items(): if k.startswith(entry_key): uid = k[len(entry_key):] c.issuetracker_entries[uid] = None for uid in c.issuetracker_entries: c.issuetracker_entries[uid] = AttributeDict({ 'pat': defaults.get('rhodecode_issuetracker_pat_' + uid), 'url': defaults.get('rhodecode_issuetracker_url_' + uid), 'pref': defaults.get('rhodecode_issuetracker_pref_' + uid), 'desc': defaults.get('rhodecode_issuetracker_desc_' + uid), }) return render('admin/settings/settings.html')
def __before__(self): """ __before__ is called before controller methods and after __call__ """ c.rhodecode_version = __version__ c.rhodecode_instanceid = config.get('instance_id') c.rhodecode_name = config.get('rhodecode_title') c.rhodecode_bugtracker = config.get('bugtracker', 'http://bitbucket.org/marcinkuzminski/rhodecode/issues') c.use_gravatar = str2bool(config.get('use_gravatar')) c.ga_code = config.get('rhodecode_ga_code') # Visual options c.visual = AttributeDict({}) rc_config = RhodeCodeSetting.get_app_settings() ## DB stored c.visual.show_public_icon = str2bool(rc_config.get('rhodecode_show_public_icon')) c.visual.show_private_icon = str2bool(rc_config.get('rhodecode_show_private_icon')) c.visual.stylify_metatags = str2bool(rc_config.get('rhodecode_stylify_metatags')) c.visual.dashboard_items = safe_int(rc_config.get('rhodecode_dashboard_items', 100)) c.visual.repository_fields = str2bool(rc_config.get('rhodecode_repository_fields')) c.visual.show_version = str2bool(rc_config.get('rhodecode_show_version')) ## INI stored self.cut_off_limit = int(config.get('cut_off_limit')) c.visual.allow_repo_location_change = str2bool(config.get('allow_repo_location_change', True)) c.visual.allow_custom_hooks_settings = str2bool(config.get('allow_custom_hooks_settings', True)) c.repo_name = get_repo_slug(request) # can be empty c.backends = BACKENDS.keys() c.unread_notifications = NotificationModel()\ .get_unread_cnt_for_user(c.rhodecode_user.user_id) self.sa = meta.Session self.scm_model = ScmModel(self.sa)
def update(self, gist, description, owner, gist_mapping, gist_type, lifetime, gist_acl_level): gist = self._get_gist(gist) gist_repo = gist.scm_instance() lifetime = safe_int(lifetime, -1) if lifetime == 0: # preserve old value gist_expires = gist.gist_expires else: gist_expires = ( time.time() + (lifetime * 60) if lifetime != -1 else -1) # calculate operation type based on given data gist_mapping_op = {} for k, v in gist_mapping.items(): # add, mod, del if not v['org_filename'] and v['filename']: op = 'add' elif v['org_filename'] and not v['filename']: op = 'del' else: op = 'mod' v['op'] = op gist_mapping_op[k] = v gist.gist_description = description gist.gist_expires = gist_expires gist.owner = owner gist.gist_type = gist_type gist.acl_level = gist_acl_level self.sa.add(gist) self.sa.flush() message = 'updated file' message += 's: ' if len(gist_mapping) > 1 else ': ' message += ', '.join([x for x in gist_mapping]) # fake RhodeCode Repository object fake_repo = AttributeDict({ 'repo_name': gist_repo.path, 'scm_instance': lambda *args, **kwargs: gist_repo, }) self._store_metadata(gist_repo, gist.gist_id, gist.gist_access_id, owner.user_id, owner.username, gist.gist_type, gist.gist_expires, gist_acl_level) # this can throw NodeNotChangedError, if changes we're trying to commit # are not actually changes... ScmModel().update_nodes( user=owner.user_id, repo=fake_repo, message=message, nodes=gist_mapping_op, trigger_push_hook=False ) return gist
def test_get_visual_attr(pylonsapp): c = ContextObj() assert None is helpers.get_visual_attr(c, 'fakse') # emulate the c.visual behaviour c.visual = AttributeDict({}) assert None is helpers.get_visual_attr(c, 'some_var') c.visual.some_var = 'foobar' assert 'foobar' == helpers.get_visual_attr(c, 'some_var')
def _call_hook(self, hook, extras): extras = AttributeDict(extras) try: result = hook(extras) except Exception as error: log.exception('Exception when handling hook %s', hook) error_args = error.args return { 'status': 128, 'output': '', 'exception': type(error).__name__, 'exception_args': error_args, } return { 'status': result.status, 'output': result.output, }
def _rss_feed(self, repos, public=True): journal = self._get_journal_data(repos) if public: _link = url('public_journal_atom', qualified=True) _desc = '%s %s %s' % (c.rhodecode_name, _('public journal'), 'rss feed') else: _link = url('journal_atom', qualified=True) _desc = '%s %s %s' % (c.rhodecode_name, _('journal'), 'rss feed') feed = Rss201rev2Feed(title=_desc, link=_link, description=_desc, language=self.language, ttl=self.ttl) for entry in journal[:self.feed_nr]: user = entry.user if user is None: #fix deleted users user = AttributeDict({ 'short_contact': entry.username, 'email': '', 'full_contact': '' }) action, action_extra, ico = h.action_parser(entry, feed=True) title = "%s - %s %s" % (user.short_contact, action(), entry.repository.repo_name) desc = action_extra() _url = None if entry.repository is not None: _url = url('changelog_home', repo_name=entry.repository.repo_name, qualified=True) feed.add_item(title=title, pubdate=entry.action_date, link=_url or url('', qualified=True), author_email=user.email, author_name=user.full_contact, description=desc) response.content_type = feed.mime_type return feed.writeString('utf-8')
def _make_dict_for_settings(self, qs): prefix_match = self._get_keyname('pat', '', 'rhodecode_') issuetracker_entries = {} # create keys for k, v in qs.items(): if k.startswith(prefix_match): uid = k[len(prefix_match):] issuetracker_entries[uid] = None # populate for uid in issuetracker_entries: issuetracker_entries[uid] = AttributeDict({ 'pat': qs.get(self._get_keyname('pat', uid, 'rhodecode_')), 'url': qs.get(self._get_keyname('url', uid, 'rhodecode_')), 'pref': qs.get(self._get_keyname('pref', uid, 'rhodecode_')), 'desc': qs.get(self._get_keyname('desc', uid, 'rhodecode_')), }) return issuetracker_entries
def create_registration(self, form_data): from rhodecode.model.notification import NotificationModel from rhodecode.model.notification import EmailNotificationModel try: form_data['admin'] = False form_data['extern_name'] = 'rhodecode' form_data['extern_type'] = 'rhodecode' new_user = self.create(form_data) self.sa.add(new_user) self.sa.flush() user_data = new_user.get_dict() kwargs = { # use SQLALCHEMY safe dump of user data 'user': AttributeDict(user_data), 'date': datetime.datetime.now() } notification_type = EmailNotificationModel.TYPE_REGISTRATION # pre-generate the subject for notification itself (subject, _h, _e, # we don't care about those body_plaintext) = EmailNotificationModel().render_email( notification_type, **kwargs) # create notification objects, and emails NotificationModel().create( created_by=new_user, notification_subject=subject, notification_body=body_plaintext, notification_type=notification_type, recipients=None, # all admins email_kwargs=kwargs, ) return new_user except Exception: log.error(traceback.format_exc()) raise
def attach_context_attributes(context): rc_config = SettingsModel().get_all_settings(cache=True) context.rhodecode_version = rhodecode.__version__ context.rhodecode_edition = config.get('rhodecode.edition') # unique secret + version does not leak the version but keep consistency context.rhodecode_version_hash = md5( config.get('beaker.session.secret', '') + rhodecode.__version__)[:8] # Default language set for the incoming request context.language = translation.get_lang()[0] # Visual options context.visual = AttributeDict({}) # DB store context.visual.show_public_icon = str2bool( rc_config.get('rhodecode_show_public_icon')) context.visual.show_private_icon = str2bool( rc_config.get('rhodecode_show_private_icon')) context.visual.stylify_metatags = str2bool( rc_config.get('rhodecode_stylify_metatags')) context.visual.dashboard_items = safe_int( rc_config.get('rhodecode_dashboard_items', 100)) context.visual.admin_grid_items = safe_int( rc_config.get('rhodecode_admin_grid_items', 100)) context.visual.repository_fields = str2bool( rc_config.get('rhodecode_repository_fields')) context.visual.show_version = str2bool( rc_config.get('rhodecode_show_version')) context.visual.use_gravatar = str2bool( rc_config.get('rhodecode_use_gravatar')) context.visual.gravatar_url = rc_config.get('rhodecode_gravatar_url') context.visual.default_renderer = rc_config.get( 'rhodecode_markup_renderer', 'rst') context.visual.rhodecode_support_url = \ rc_config.get('rhodecode_support_url') or url('rhodecode_support') context.pre_code = rc_config.get('rhodecode_pre_code') context.post_code = rc_config.get('rhodecode_post_code') context.rhodecode_name = rc_config.get('rhodecode_title') context.default_encodings = aslist(config.get('default_encoding'), sep=',') # if we have specified default_encoding in the request, it has more # priority if request.GET.get('default_encoding'): context.default_encodings.insert(0, request.GET.get('default_encoding')) context.clone_uri_tmpl = rc_config.get('rhodecode_clone_uri_tmpl') # INI stored context.labs_active = str2bool( config.get('labs_settings_active', 'false')) context.visual.allow_repo_location_change = str2bool( config.get('allow_repo_location_change', True)) context.visual.allow_custom_hooks_settings = str2bool( config.get('allow_custom_hooks_settings', True)) context.debug_style = str2bool(config.get('debug_style', False)) context.rhodecode_instanceid = config.get('instance_id') # AppEnlight context.appenlight_enabled = str2bool(config.get('appenlight', 'false')) context.appenlight_api_public_key = config.get( 'appenlight.api_public_key', '') context.appenlight_server_url = config.get('appenlight.server_url', '') # END CONFIG VARS # TODO: This dosn't work when called from pylons compatibility tween. # Fix this and remove it from base controller. # context.repo_name = get_repo_slug(request) # can be empty context.csrf_token = auth.get_csrf_token() context.backends = rhodecode.BACKENDS.keys() context.backends.sort() context.unread_notifications = NotificationModel().get_unread_cnt_for_user( context.rhodecode_user.user_id)
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 get_cs_links(): revs_limit = 3 # display this amount always revs_top_limit = 50 # show upto this amount of changesets hidden revs_ids = action_params.split(',') deleted = user_log.repository is None if deleted: return ','.join(revs_ids) repo_name = user_log.repository.repo_name def lnk(rev, repo_name): if isinstance(rev, BaseChangeset) or isinstance( rev, AttributeDict): lazy_cs = True if getattr(rev, 'op', None) and getattr(rev, 'ref_name', None): lazy_cs = False lbl = '?' if rev.op == 'delete_branch': lbl = '%s' % _('Deleted branch: %s') % rev.ref_name title = '' elif rev.op == 'tag': lbl = '%s' % _('Created tag: %s') % rev.ref_name title = '' _url = '#' else: lbl = '%s' % (rev.short_id[:8]) _url = url('changeset_home', repo_name=repo_name, revision=rev.raw_id) title = tooltip(rev.message) else: ## changeset cannot be found/striped/removed etc. lbl = ('%s' % rev)[:12] _url = '#' title = _('Changeset not found') if parse_cs: return link_to(lbl, _url, title=title, class_='tooltip') return link_to(lbl, _url, raw_id=rev.raw_id, repo_name=repo_name, class_='lazy-cs' if lazy_cs else '') def _get_op(rev_txt): _op = None _name = rev_txt if len(rev_txt.split('=>')) == 2: _op, _name = rev_txt.split('=>') return _op, _name revs = [] if len(filter(lambda v: v != '', revs_ids)) > 0: repo = None for rev in revs_ids[:revs_top_limit]: _op, _name = _get_op(rev) # we want parsed changesets, or new log store format is bad if parse_cs: try: if repo is None: repo = user_log.repository.scm_instance _rev = repo.get_changeset(rev) revs.append(_rev) except ChangesetDoesNotExistError: log.error('cannot find revision %s in this repo' % rev) revs.append(rev) continue else: _rev = AttributeDict({ 'short_id': rev[:12], 'raw_id': rev, 'message': '', 'op': _op, 'ref_name': _name }) revs.append(_rev) cs_links = [ " " + ', '.join([lnk(rev, repo_name) for rev in revs[:revs_limit]]) ] _op1, _name1 = _get_op(revs_ids[0]) _op2, _name2 = _get_op(revs_ids[-1]) _rev = '%s...%s' % (_name1, _name2) compare_view = ( ' <div class="compare_view tooltip" title="%s">' '<a href="%s">%s</a> </div>' % (_('Show all combined changesets %s->%s') % (revs_ids[0][:12], revs_ids[-1][:12]), url('changeset_home', repo_name=repo_name, revision=_rev), _('compare view'))) # if we have exactly one more than normally displayed # just display it, takes less space than displaying # "and 1 more revisions" if len(revs_ids) == revs_limit + 1: rev = revs[revs_limit] cs_links.append(", " + lnk(rev, repo_name)) # hidden-by-default ones if len(revs_ids) > revs_limit + 1: uniq_id = revs_ids[0] html_tmpl = ('<span> %s <a class="show_more" id="_%s" ' 'href="#more">%s</a> %s</span>') if not feed: cs_links.append(html_tmpl % (_('and'), uniq_id, _('%s more') % (len(revs_ids) - revs_limit), _('revisions'))) if not feed: html_tmpl = '<span id="%s" style="display:none">, %s </span>' else: html_tmpl = '<span id="%s"> %s </span>' morelinks = ', '.join( [lnk(rev, repo_name) for rev in revs[revs_limit:]]) if len(revs_ids) > revs_top_limit: morelinks += ', ...' cs_links.append(html_tmpl % (uniq_id, morelinks)) if len(revs) > 1: cs_links.append(compare_view) return ''.join(cs_links)
def create(self, description, owner, gist_mapping, gist_type=Gist.GIST_PUBLIC, lifetime=-1, gist_id=None, gist_acl_level=Gist.ACL_LEVEL_PRIVATE): """ Create a gist :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 :param gist_acl_level: acl level for this gist """ owner = self._get_user(owner) gist_id = safe_unicode(gist_id or unique_id(20)) lifetime = safe_int(lifetime, -1) gist_expires = time.time() + (lifetime * 60) if lifetime != -1 else -1 expiration = (time_to_datetime(gist_expires) if gist_expires != -1 else 'forever') log.debug('set GIST expiration date to: %s', expiration) # 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) gist.acl_level = gist_acl_level 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_filesystem_repo( repo_name=gist_id, repo_type='hg', repo_group=GIST_STORE_LOC, use_global_config=True) 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: # guess_lexer = pygments.lexers.guess_lexer_for_filename # lexer = guess_lexer(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({ 'repo_name': gist_repo_path, 'scm_instance': lambda *args, **kwargs: repo, }) ScmModel().create_nodes( user=owner.user_id, repo=fake_repo, message=message, nodes=processed_mapping, trigger_push_hook=False ) self._store_metadata(repo, gist.gist_id, gist.gist_access_id, owner.user_id, owner.username, gist.gist_type, gist.gist_expires, gist_acl_level) return gist