def index(): """ Front page of the application. """ if ( authenticated() and flask.request.path == "/" and not flask.session.get("_requires_fpca", False) ): flask.request.from_index = True return flask.redirect(flask.url_for("ui_ns.userdash_projects")) sorting = flask.request.args.get("sorting") or None page = flask.request.args.get("page", 1) try: page = int(page) if page < 1: page = 1 except ValueError: page = 1 limit = pagure_config["ITEM_PER_PAGE"] start = limit * (page - 1) private = None if authenticated(): private = flask.g.fas_user.username repos = pagure.lib.query.search_projects( flask.g.session, fork=False, start=start, limit=limit, sort=sorting, private=private, ) num_repos = pagure.lib.query.search_projects( flask.g.session, fork=False, private=private, count=True ) total_page = int(ceil(num_repos / float(limit)) if num_repos > 0 else 1) return flask.render_template( "index.html", select="projects", namespace=None, repos=repos, repos_length=num_repos, total_page=total_page, page=page, sorting=sorting, )
def api_whoami(): """ Who am I? --------- This API endpoint will return the username associated with the provided API token. :: POST /api/0/-/whoami Sample response ^^^^^^^^^^^^^^^ :: { "username": "******" } """ if authenticated(): return flask.jsonify({"username": flask.g.fas_user.username}) else: output = { "error_code": APIERROR.EINVALIDTOK.name, "error": APIERROR.EINVALIDTOK.value, } jsonout = flask.jsonify(output) jsonout.status_code = 401 return jsonout
def view_users(username=None): """ Present the list of users. """ page = flask.request.args.get('page', 1) try: page = int(page) if page < 1: page = 1 except ValueError: page = 1 users = pagure.lib.search_user(flask.g.session, pattern=username) private = False # Condition to check non-authorized user should't be able to access private # project of other users if authenticated() and username == flask.g.fas_user.username: private = flask.g.fas_user.username if len(users) == 1: flask.flash('Only one result found, redirecting you to it') return flask.redirect( flask.url_for('ui_ns.view_user', username=users[0].username)) limit = pagure_config['ITEM_PER_PAGE'] start = limit * (page - 1) end = limit * page users_length = len(users) users = users[start:end] total_page = int(ceil(users_length / float(limit))) for user in users: repos_length = pagure.lib.search_projects(flask.g.session, username=user.user, fork=False, count=True, private=private) forks_length = pagure.lib.search_projects(flask.g.session, username=user.user, fork=True, count=True, private=private) user.repos_length = repos_length user.forks_length = forks_length return flask.render_template( 'user_list.html', users=users, users_length=users_length, total_page=total_page, page=page, select='users', )
def view_users(username=None): """ Present the list of users. """ page = flask.request.args.get("page", 1) try: page = int(page) if page < 1: page = 1 except ValueError: page = 1 users = pagure.lib.query.search_user(flask.g.session, pattern=username) private = False # Condition to check non-authorized user should't be able to access private # project of other users if authenticated() and username == flask.g.fas_user.username: private = flask.g.fas_user.username limit = pagure_config["ITEM_PER_PAGE"] start = limit * (page - 1) end = limit * page users_length = len(users) users = users[start:end] total_page = int(ceil(users_length / float(limit))) for user in users: repos_length = pagure.lib.query.search_projects( flask.g.session, username=user.user, fork=False, count=True, private=private, ) forks_length = pagure.lib.query.search_projects( flask.g.session, username=user.user, fork=True, count=True, private=private, ) user.repos_length = repos_length user.forks_length = forks_length return flask.render_template( "user_list.html", users=users, users_length=users_length, total_page=total_page, page=page, select="users", )
def check_api_acls(acls, optional=False): ''' Checks if the user provided an API token with its request and if this token allows the user to access the endpoint desired. ''' flask.g.token = None flask.g.user = None token = None token_str = None if authenticated(): return if 'Authorization' in flask.request.headers: authorization = flask.request.headers['Authorization'] if 'token' in authorization: token_str = authorization.split('token', 1)[1].strip() token_auth = False if token_str: token = pagure.lib.get_api_token(flask.g.session, token_str) if token and not token.expired: flask.g.authenticated = True if acls and set(token.acls_list).intersection(set(acls)): token_auth = True flask.g.fas_user = token.user # To get a token, in the `fas` auth user must have signed # the CLA, so just set it to True flask.g.fas_user.cla_done = True flask.g.token = token flask.g.authenticated = True elif not acls and optional: token_auth = True flask.g.fas_user = token.user # To get a token, in the `fas` auth user must have signed # the CLA, so just set it to True flask.g.fas_user.cla_done = True flask.g.token = token flask.g.authenticated = True elif optional: return if not token_auth: output = { 'error_code': APIERROR.EINVALIDTOK.name, 'error': APIERROR.EINVALIDTOK.value, } jsonout = flask.jsonify(output) jsonout.status_code = 401 return jsonout
def index(): """ Front page of the application. """ sorting = flask.request.args.get('sorting') or None page = flask.request.args.get('page', 1) try: page = int(page) if page < 1: page = 1 except ValueError: page = 1 limit = pagure_config['ITEM_PER_PAGE'] start = limit * (page - 1) repos = pagure.lib.search_projects(flask.g.session, fork=False, start=start, limit=limit, sort=sorting) num_repos = pagure.lib.search_projects(flask.g.session, fork=False, count=True) total_page = int(ceil(num_repos / float(limit)) if num_repos > 0 else 1) if authenticated() and flask.request.path == '/': return index_auth() return flask.render_template( 'index.html', select="projects", repos=repos, repos_length=num_repos, total_page=total_page, page=page, sorting=sorting, )
def api_subscribe_pull_request(repo, requestid, username=None, namespace=None): """ Subscribe to an pull-request ---------------------------- Allows someone to subscribe to or unsubscribe from the notifications related to a pull-request. :: POST /api/0/<repo>/pull-request/<request id>/subscribe POST /api/0/<namespace>/<repo>/pull-request/<request id>/subscribe :: POST /api/0/fork/<username>/<repo>/pull-request/<request id>/subscribe POST /api/0/fork/<username>/<namespace>/<repo>/pull-request/<request id>/subscribe Input ^^^^^ +--------------+----------+---------------+---------------------------+ | Key | Type | Optionality | Description | +==============+==========+===============+===========================+ | ``status`` | boolean | Mandatory | The intended subscription | | | | | status. ``true`` for | | | | | subscribing, ``false`` | | | | | for unsubscribing. | +--------------+----------+---------------+---------------------------+ Sample response ^^^^^^^^^^^^^^^ :: { "message": "User subscribed", "avatar_url": "https://image.png", "user": "******" } """ # noqa repo = get_authorized_api_project( flask.g.session, repo, user=username, namespace=namespace ) output = {} if repo is None: raise pagure.exceptions.APIError(404, error_code=APIERROR.ENOPROJECT) if not repo.settings.get("pull_requests", True): raise pagure.exceptions.APIError( 404, error_code=APIERROR.EPULLREQUESTSDISABLED ) if ( api_authenticated() and flask.g.token and flask.g.token.project and repo != flask.g.token.project ) or not authenticated(): raise pagure.exceptions.APIError(401, error_code=APIERROR.EINVALIDTOK) request = pagure.lib.query.search_pull_requests( flask.g.session, project_id=repo.id, requestid=requestid ) if not request: raise pagure.exceptions.APIError(404, error_code=APIERROR.ENOREQ) form = pagure.forms.SubscribtionForm(csrf_enabled=False) if form.validate_on_submit(): status = is_true(form.status.data) try: # Toggle subscribtion message = pagure.lib.query.set_watch_obj( flask.g.session, user=flask.g.fas_user.username, obj=request, watch_status=status, ) flask.g.session.commit() output["message"] = message user_obj = pagure.lib.query.get_user( flask.g.session, flask.g.fas_user.username ) output["avatar_url"] = pagure.lib.query.avatar_url_from_email( user_obj.default_email, size=30 ) output["user"] = flask.g.fas_user.username except SQLAlchemyError as err: # pragma: no cover flask.g.session.rollback() _log.logger.exception(err) raise pagure.exceptions.APIError(400, error_code=APIERROR.EDBERROR) jsonout = flask.jsonify(output) return jsonout
def view_user2(username): """ Front page of a specific user. """ user = _get_user(username=username) acl = flask.request.args.get("acl", "").strip().lower() or None repopage = flask.request.args.get("repopage", 1) try: repopage = int(repopage) if repopage < 1: repopage = 1 except ValueError: repopage = 1 forkpage = flask.request.args.get("forkpage", 1) try: forkpage = int(forkpage) if forkpage < 1: forkpage = 1 except ValueError: forkpage = 1 limit = pagure_config["ITEM_PER_PAGE"] repo_start = limit * (repopage - 1) fork_start = limit * (forkpage - 1) private = False if authenticated() and username == flask.g.fas_user.username: private = flask.g.fas_user.username repos = pagure.lib.query.search_projects( flask.g.session, username=username, fork=False, exclude_groups=pagure_config.get("EXCLUDE_GROUP_INDEX"), start=repo_start, limit=limit, private=private, ) if repos and acl: repos = _filter_acls(repos, acl, user) repos_length = pagure.lib.query.search_projects( flask.g.session, username=username, fork=False, exclude_groups=pagure_config.get("EXCLUDE_GROUP_INDEX"), private=private, count=True, ) forks = pagure.lib.query.search_projects( flask.g.session, username=username, fork=True, start=fork_start, limit=limit, private=private, ) forks_length = pagure.lib.query.search_projects( flask.g.session, username=username, fork=True, private=private, count=True, ) total_page_repos = int(ceil(repos_length / float(limit))) total_page_forks = int(ceil(forks_length / float(limit))) return flask.render_template( "userprofile_overview.html", username=username, user=user, repos=repos, total_page_repos=total_page_repos, forks=forks, total_page_forks=total_page_forks, repopage=repopage, forkpage=forkpage, repos_length=repos_length, forks_length=forks_length, )
def view_projects(pattern=None, namespace=None): """ Present the list of projects. """ forks = flask.request.args.get("forks") page = flask.request.args.get("page", 1) try: page = int(page) if page < 1: page = 1 except ValueError: page = 1 select = "projects" # If forks is specified, we want both forks and projects if is_true(forks): forks = None select = "projects_forks" else: forks = False private = False if authenticated(): private = flask.g.fas_user.username limit = pagure_config["ITEM_PER_PAGE"] start = limit * (page - 1) projects = pagure.lib.query.search_projects( flask.g.session, pattern=pattern, namespace=namespace, fork=forks, start=start, limit=limit, private=private, ) if len(projects) == 1: flask.flash("Only one result found, redirecting you to it") return flask.redirect( flask.url_for( "ui_ns.view_repo", repo=projects[0].name, namespace=projects[0].namespace, username=projects[0].user.username if projects[0].is_fork else None, ) ) projects_length = pagure.lib.query.search_projects( flask.g.session, pattern=pattern, namespace=namespace, fork=forks, count=True, private=private, ) total_page = int(ceil(projects_length / float(limit))) if namespace in pagure_config["ALLOWED_PREFIX"]: namespace = None return flask.render_template( "index.html", namespace=namespace, repos=projects, repos_length=projects_length, total_page=total_page, page=page, select=select, )
def view_projects(pattern=None, namespace=None): """ Present the list of projects. """ forks = flask.request.args.get('forks') page = flask.request.args.get('page', 1) try: page = int(page) if page < 1: page = 1 except ValueError: page = 1 select = 'projects' # If forks is specified, we want both forks and projects if str(forks).lower() in ['true', '1']: forks = None select = 'projects_forks' else: forks = False private = False if authenticated(): private = flask.g.fas_user.username limit = pagure_config['ITEM_PER_PAGE'] start = limit * (page - 1) projects = pagure.lib.search_projects(flask.g.session, pattern=pattern, namespace=namespace, fork=forks, start=start, limit=limit, private=private) if len(projects) == 1: flask.flash('Only one result found, redirecting you to it') return flask.redirect( flask.url_for('ui_ns.view_repo', repo=projects[0].name, namespace=projects[0].namespace, username=projects[0].user.username if projects[0].is_fork else None)) projects_length = pagure.lib.search_projects(flask.g.session, pattern=pattern, namespace=namespace, fork=forks, count=True, private=private) total_page = int(ceil(projects_length / float(limit))) return flask.render_template( 'index.html', repos=projects, repos_length=projects_length, total_page=total_page, page=page, select=select, )
def format_loc(loc, commit=None, filename=None, tree_id=None, prequest=None, index=None): """ Template filter putting the provided lines of code into a table """ if loc is None: return output = ['<div class="highlight">', '<table class="code_table">'] comments = {} if prequest and not isinstance(prequest, flask.wrappers.Request): for com in prequest.comments: if commit and unicode(com.commit_id) == unicode(commit) \ and unicode(com.filename) == unicode(filename): if com.line in comments: comments[com.line].append(com) else: comments[com.line] = [com] for key in comments: comments[key] = sorted(comments[key], key=lambda obj: obj.date_created) if not index: index = '' cnt = 1 for line in loc.split('\n'): if line == '</pre></div>': break if filename and commit: output.append( '<tr id="c-%(commit)s-%(cnt_lbl)s"><td class="cell1">' '<a id="%(cnt)s" href="#%(cnt)s" data-line-number=' '"%(cnt_lbl)s"></a></td>' '<td class="prc" data-row="%(cnt_lbl)s"' ' data-filename="%(filename)s" data-commit="%(commit)s"' ' data-tree="%(tree_id)s">' '<p>' '<span class="oi prc_img" data-glyph="comment-square" ' 'alt="Add comment" title="Add comment"></span>' '</p>' '</td>' % ({ 'cnt': '%s_%s' % (index, cnt), 'cnt_lbl': cnt, 'filename': filename.decode('UTF-8'), 'commit': commit, 'tree_id': tree_id, })) else: output.append('<tr><td class="cell1">' '<a id="%(cnt)s" href="#%(cnt)s" data-line-number=' '"%(cnt_lbl)s"></a></td>' % ({ 'cnt': '%s_%s' % (index, cnt), 'cnt_lbl': cnt, })) cnt += 1 if not line: output.append(line) continue if line.startswith('<div'): line = line.split('<pre style="line-height: 125%">')[1] if prequest and prequest.project_from: rangeline = line.partition('font-weight: bold">@@ ')[2] \ if line.partition('font-weight: bold">@@ ')[1] == \ 'font-weight: bold">@@ ' else None if rangeline: rangeline = rangeline.split(' @@</span>')[0] linenumber = rangeline.split('+')[1].split(',')[0] line = line + ' <a href="%s#_%s" target="_blank" ' % ( flask.url_for( 'ui_ns.view_file', repo=prequest.project_from.name, username=prequest.project_from.user.username if prequest.project_from.is_fork else None, namespace=prequest.project_from.namespace, identifier=prequest.branch_from, filename=filename), linenumber) line = line + 'class="open_changed_file_icon_wrap">' + \ '<span class="oi open_changed_file_icon" ' + \ 'data-glyph="eye" alt="Open changed file" ' + \ 'title="Open changed file"></span></a>' output.append('<td class="cell2"><pre>%s</pre></td>' % line) output.append('</tr>') tpl_edit = '<a href="%(edit_url)s" ' \ 'class="btn btn-secondary btn-sm" data-comment="%(commentid)s" ' \ 'data-objid="%(requestid)s">' \ '<span class="oi" data-glyph="pencil"></span>' \ '</a>' tpl_edited = '<small class="text-muted" title="%(edit_date)s"> ' \ 'Edited %(human_edit_date)s by %(user)s </small>' tpl_delete = '<button class="btn btn-secondary btn-sm" '\ 'title="Remove comment" '\ 'name="drop_comment" value="%(commentid)s" type="submit" ' \ 'onclick="return confirm(\'Do you really want to remove this' \ ' comment?\');" ><span class="oi" data-glyph="trash"></span>' \ '</button>' if cnt - 1 in comments: for comment in comments[cnt - 1]: templ_delete = '' templ_edit = '' templ_edited = '' status = str(comment.parent.status).lower() if authenticated() and ( (status in ['true', 'open'] and comment.user.user == flask.g.fas_user.username) or is_repo_committer(comment.parent.project)): templ_delete = tpl_delete % ({'commentid': comment.id}) templ_edit = tpl_edit % ({ 'edit_url': flask.url_for( 'ui_ns.pull_request_edit_comment', repo=comment.parent.project.name, requestid=comment.parent.id, commentid=comment.id, username=comment.parent.user.user if comment.parent.project.is_fork else None), 'requestid': comment.parent.id, 'commentid': comment.id, }) if comment.edited_on: templ_edited = tpl_edited % ( { 'edit_date': format_ts(comment.edited_on), 'human_edit_date': humanize_date( comment.edited_on), 'user': comment.editor.user, }) output.append( '<tr class="inline-pr-comment"><td></td>' '<td colspan="2">' '<div class="card clearfix m-x-1 ">' '<div class="card-block">' '<small><div id="comment-%(commentid)s">' '<img class="avatar circle" src="%(avatar_url)s"/>' '<a href="%(url)s" title="%(user_html)s">' '%(user)s</a> commented ' '<a class="headerlink" title="Permalink ' 'to this headline" href="#comment-%(commentid)s">' '<span title="%(date)s">%(human_date)s</span>' '</a></div></small>' '<section class="issue_comment">' '<div class="comment_body">' '%(comment)s' '</div>' '</section>' '<div class="issue_actions m-t-2">' '%(templ_edited)s' '<aside class="btn-group issue_action icon ' 'pull-xs-right p-b-1">' '%(templ_edit)s' '%(templ_delete)s' '</aside>' '</div></div></div>' '</td></tr>' % ({ 'url': flask.url_for('ui_ns.view_user', username=comment.user.user), 'templ_delete': templ_delete, 'templ_edit': templ_edit, 'templ_edited': templ_edited, 'user': comment.user.user, 'user_html': comment.user.html_title, 'avatar_url': avatar_url(comment.user.default_email, 16), 'date': format_ts(comment.date_created), 'human_date': humanize_date(comment.date_created), 'comment': markdown_filter(comment.comment), 'commentid': comment.id, })) output.append('</table></div>') return '\n'.join(output)
def format_loc( loc, commit=None, filename=None, tree_id=None, prequest=None, index=None, isprdiff=False, ): """ Template filter putting the provided lines of code into a table """ if loc is None: return output = ['<div class="highlight">', '<table class="code_table">'] commit_hash = commit if hasattr(commit_hash, "hex"): commit_hash = commit_hash.hex comments = {} if prequest and not isinstance(prequest, flask.wrappers.Request): for com in prequest.comments: if (commit and com.commit_id == commit_hash and com.filename == filename): if com.line in comments: comments[com.line].append(com) else: comments[com.line] = [com] for key in comments: comments[key] = sorted(comments[key], key=lambda obj: obj.date_created) if not index: index = "" cnt = 1 for line in loc.split("\n"): if filename and commit: if isinstance(filename, str) and six.PY2: filename = filename.decode("UTF-8") if isprdiff and (line.startswith("@@") or line.startswith("+") or line.startswith("-")): if line.startswith("@@"): output.append('<tr class="stretch-table-column bg-light"\ id="c-%(commit)s-%(cnt_lbl)s">' % ({ "cnt_lbl": cnt, "commit": commit })) elif line.startswith("+"): output.append( '<tr class="stretch-table-column alert-success" \ id="c-%(commit)s-%(cnt_lbl)s">' % ({ "cnt_lbl": cnt, "commit": commit })) elif line.startswith("-"): output.append( '<tr class="stretch-table-column alert-danger" \ id="c-%(commit)s-%(cnt_lbl)s">' % ({ "cnt_lbl": cnt, "commit": commit })) else: output.append('<tr id="c-%(commit)s-%(cnt_lbl)s">' % ({ "cnt_lbl": cnt, "commit": commit })) output.append( '<td class="cell1">' '<a id="%(cnt)s" href="#%(cnt)s" data-line-number=' '"%(cnt_lbl)s" data-file-number=' '"%(line)s"></a></td>' '<td class="prc border-right" data-row="%(cnt_lbl)s"' ' data-filename="%(filename)s" data-commit="%(commit)s"' ' data-tree="%(tree_id)s">' "<p>" '<span class="fa fa-comment prc_img" style="display: none;"' 'alt="Add comment" title="Add comment"></span>' "</p>" "</td>" % ({ "cnt": "_%s__%s" % (index, cnt), "cnt_lbl": cnt, "line": index, "filename": filename, "commit": commit, "tree_id": tree_id, })) else: output.append('<tr><td class="cell1">' '<a id="%(cnt)s" href="#%(cnt)s" data-line-number=' '"%(cnt_lbl)s"></a></td>' % ({ "cnt": "%s_%s" % (index, cnt), "cnt_lbl": cnt })) cnt += 1 if not line: output.append(line) continue if line.startswith("@@"): if prequest and prequest.project_from: rangeline = (line.partition("@@ ")[2] if line.partition("@@ ")[1] == "@@ " else None) if rangeline: rangeline = rangeline.split(" @@")[0] linenumber = rangeline.split("+")[1].split(",")[0] line = line + ' <a href="%s#_%s" target="_blank" ' % ( flask.url_for( "ui_ns.view_file", repo=prequest.project_from.name, username=prequest.project_from.user.username if prequest.project_from.is_fork else None, namespace=prequest.project_from.namespace, identifier=prequest.branch_from, filename=filename, ), linenumber, ) line = (line + 'class="open_changed_file_icon_wrap">' + '<span class="fa fa-file-code-o fa-fw" ' + 'alt="Open changed file" ' + 'title="Open changed file"></span></a>') if isprdiff and (line.startswith("@@") or line.startswith("+") or line.startswith("-")): if line.startswith("@@"): output.append('<td class="cell2 stretch-table-column">\ <pre class="text-muted"><code>%s</code></pre></td>' % line) elif line.startswith("+"): output.append('<td class="cell2 stretch-table-column">\ <pre class="alert-success"><code>%s</code></pre></td>' % escape(line)) elif line.startswith("-"): output.append('<td class="cell2 stretch-table-column">\ <pre class="alert-danger"><code>%s</code></pre></td>' % escape(line)) else: output.append('<td class="cell2"><pre><code>%s</code></pre></td>' % (escape(line))) output.append("</tr>") tpl_edit = ('<a href="%(edit_url)s" ' 'class="btn btn-outline-primary border-0" ' 'data-comment="%(commentid)s" ' 'data-objid="%(requestid)s">' '<i class="fa fa-pencil"></i>' "</a>") tpl_edited = ('<small class="text-muted" title="%(edit_date)s"> ' "Edited %(human_edit_date)s by %(user)s </small>") tpl_delete = ( '<button class="btn btn-outline-primary border-0" ' 'title="Remove comment" ' 'name="drop_comment" value="%(commentid)s" type="submit" ' "onclick=\"return confirm('Do you really want to remove this" ' comment?\');" ><i class="fa fa-trash"></i>' "</button>") if cnt - 1 in comments: for comment in comments[cnt - 1]: templ_delete = "" templ_edit = "" templ_edited = "" if authenticated() and ( (is_true(comment.parent.status, ["true", "open"]) and comment.user.user == flask.g.fas_user.username) or is_repo_committer(comment.parent.project)): templ_delete = tpl_delete % ({"commentid": comment.id}) templ_edit = tpl_edit % ({ "edit_url": flask.url_for( "ui_ns.pull_request_edit_comment", repo=comment.parent.project.name, requestid=comment.parent.id, commentid=comment.id, username=comment.parent.user.user if comment.parent.project.is_fork else None, ), "requestid": comment.parent.id, "commentid": comment.id, }) if comment.edited_on: templ_edited = tpl_edited % ( { "edit_date": format_ts(comment.edited_on), "human_edit_date": humanize_date( comment.edited_on), "user": comment.editor.user, }) output.append( '<tr class="inline-pr-comment">' '<td colspan="3" class="p-3 border">' '<div class="card clearfix">' '<div class="card-header bg-light d-flex ' 'align-items-center px-3 py-2">' "<div>" '<div id="comment-%(commentid)s">' '<img class="avatar circle" src="%(avatar_url)s"/>' '<a href="%(url)s" title="%(user_html)s">' "%(user)s</a> commented " '<a class="headerlink" title="Permalink ' 'to this headline" href="#comment-%(commentid)s">' '<span title="%(date)s">%(human_date)s</span>' "</a></div>" "</div>" '<div class="mr-auto">' "%(templ_edit)s" "%(templ_delete)s" "</div>" "</div>" '<div class="card-block">' "<small></small>" '<section class="issue_comment">' '<div class="comment_body">' "%(comment)s" "</div>" "</section>" "</div></div>" "</td></tr>" % ({ "url": flask.url_for("ui_ns.view_user", username=comment.user.user), "templ_delete": templ_delete, "templ_edit": templ_edit, "templ_edited": templ_edited, "user": comment.user.user, "user_html": comment.user.html_title, "avatar_url": avatar_url(comment.user.default_email, 16), "date": format_ts(comment.date_created), "human_date": humanize_date(comment.date_created), "comment": markdown_filter(comment.comment), "commentid": comment.id, })) output.append("</table></div>") return "\n".join(output)
def format_loc( loc, commit=None, filename=None, tree_id=None, prequest=None, index=None, isprdiff=False, ): """ Template filter putting the provided lines of code into a table """ if loc is None: return output = ['<div class="highlight">', '<table class="code_table">'] commit_hash = commit if hasattr(commit_hash, "hex"): commit_hash = commit_hash.hex comments = {} if prequest and not isinstance(prequest, flask.wrappers.Request): for com in prequest.comments: if ( commit and com.commit_id == commit_hash and com.filename == filename ): if com.line in comments: comments[com.line].append(com) else: comments[com.line] = [com] for key in comments: comments[key] = sorted(comments[key], key=lambda obj: obj.date_created) if not index: index = "" cnt = 1 for line in loc.split("\n"): if filename and commit: if isinstance(filename, str) and six.PY2: filename = filename.decode("UTF-8") if isprdiff and ( line.startswith("@@") or line.startswith("+") or line.startswith("-") ): if line.startswith("@@"): output.append( '<tr class="stretch-table-column bg-light"\ id="c-%(commit)s-%(cnt_lbl)s">' % ({"cnt_lbl": cnt, "commit": commit}) ) elif line.startswith("+"): output.append( '<tr class="stretch-table-column alert-success" \ id="c-%(commit)s-%(cnt_lbl)s">' % ({"cnt_lbl": cnt, "commit": commit}) ) elif line.startswith("-"): output.append( '<tr class="stretch-table-column alert-danger" \ id="c-%(commit)s-%(cnt_lbl)s">' % ({"cnt_lbl": cnt, "commit": commit}) ) else: output.append( '<tr id="c-%(commit)s-%(cnt_lbl)s">' % ({"cnt_lbl": cnt, "commit": commit}) ) output.append( '<td class="cell1">' '<a id="%(cnt)s" href="#%(cnt)s" data-line-number=' '"%(cnt_lbl)s" data-file-number=' '"%(line)s"></a></td>' '<td class="prc border-right" data-row="%(cnt_lbl)s"' ' data-filename="%(filename)s" data-commit="%(commit)s"' ' data-tree="%(tree_id)s">' "<p>" '<span class="fa fa-comment prc_img" style="display: none;"' 'alt="Add comment" title="Add comment"></span>' "</p>" "</td>" % ( { "cnt": "_%s__%s" % (index, cnt), "cnt_lbl": cnt, "line": index, "filename": filename, "commit": commit, "tree_id": tree_id, } ) ) else: output.append( '<tr><td class="cell1">' '<a id="%(cnt)s" href="#%(cnt)s" data-line-number=' '"%(cnt_lbl)s"></a></td>' % ({"cnt": "%s_%s" % (index, cnt), "cnt_lbl": cnt}) ) cnt += 1 if not line: output.append(line) continue if line.startswith("@@"): if prequest and prequest.project_from: rangeline = ( line.partition("@@ ")[2] if line.partition("@@ ")[1] == "@@ " else None ) if rangeline: rangeline = rangeline.split(" @@")[0] linenumber = rangeline.split("+")[1].split(",")[0] line = line + ' <a href="%s#_%s" target="_blank" ' % ( flask.url_for( "ui_ns.view_file", repo=prequest.project_from.name, username=prequest.project_from.user.username if prequest.project_from.is_fork else None, namespace=prequest.project_from.namespace, identifier=prequest.branch_from, filename=filename, ), linenumber, ) line = ( line + 'class="open_changed_file_icon_wrap">' + '<span class="fa fa-file-code-o fa-fw" ' + 'alt="Open changed file" ' + 'title="Open changed file"></span></a>' ) if isprdiff and ( line.startswith("@@") or line.startswith("+") or line.startswith("-") ): if line.startswith("@@"): output.append( '<td class="cell2 stretch-table-column">\ <pre class="text-muted"><code>%s</code></pre></td>' % line ) elif line.startswith("+"): output.append( '<td class="cell2 stretch-table-column">\ <pre class="alert-success"><code>%s</code></pre></td>' % escape(line) ) elif line.startswith("-"): output.append( '<td class="cell2 stretch-table-column">\ <pre class="alert-danger"><code>%s</code></pre></td>' % escape(line) ) else: output.append( '<td class="cell2"><pre><code>%s</code></pre></td>' % (escape(line)) ) output.append("</tr>") tpl_edit = ( '<a href="%(edit_url)s" ' 'class="btn btn-outline-primary border-0" ' 'data-comment="%(commentid)s" ' 'data-objid="%(requestid)s">' '<i class="fa fa-pencil"></i>' "</a>" ) tpl_edited = ( '<small class="text-muted" title="%(edit_date)s"> ' "Edited %(human_edit_date)s by %(user)s </small>" ) tpl_delete = ( '<button class="btn btn-outline-primary border-0" ' 'title="Remove comment" ' 'name="drop_comment" value="%(commentid)s" type="submit" ' "onclick=\"return confirm('Do you really want to remove this" ' comment?\');" ><i class="fa fa-trash"></i>' "</button>" ) if cnt - 1 in comments: for comment in comments[cnt - 1]: templ_delete = "" templ_edit = "" templ_edited = "" if authenticated() and ( ( is_true(comment.parent.status, ["true", "open"]) and comment.user.user == flask.g.fas_user.username ) or is_repo_committer(comment.parent.project) ): templ_delete = tpl_delete % ({"commentid": comment.id}) templ_edit = tpl_edit % ( { "edit_url": flask.url_for( "ui_ns.pull_request_edit_comment", repo=comment.parent.project.name, namespace=comment.parent.project.namespace, requestid=comment.parent.id, commentid=comment.id, username=comment.parent.user.user if comment.parent.project.is_fork else None, ), "requestid": comment.parent.id, "commentid": comment.id, } ) if comment.edited_on: templ_edited = tpl_edited % ( { "edit_date": format_ts(comment.edited_on), "human_edit_date": humanize_date( comment.edited_on ), "user": comment.editor.user, } ) output.append( '<tr class="inline-pr-comment">' '<td colspan="3" class="p-3 border">' '<div class="card clearfix">' '<div class="card-header bg-light d-flex ' 'align-items-center px-3 py-2">' "<div>" '<div id="comment-%(commentid)s">' '<img class="avatar circle" src="%(avatar_url)s"/>' '<a href="%(url)s" title="%(user_html)s">' "%(user)s</a> commented " '<a class="headerlink" title="Permalink ' 'to this headline" href="#comment-%(commentid)s">' '<span title="%(date)s">%(human_date)s</span>' "</a></div>" "</div>" '<div class="mr-auto">' "%(templ_edit)s" "%(templ_delete)s" "</div>" "</div>" '<div class="card-block">' "<small></small>" '<section class="issue_comment">' '<div class="comment_body">' "%(comment)s" "</div>" "</section>" "</div></div>" "</td></tr>" % ( { "url": flask.url_for( "ui_ns.view_user", username=comment.user.user ), "templ_delete": templ_delete, "templ_edit": templ_edit, "templ_edited": templ_edited, "user": comment.user.user, "user_html": comment.user.html_title, "avatar_url": avatar_url( comment.user.default_email, 16 ), "date": format_ts(comment.date_created), "human_date": humanize_date(comment.date_created), "comment": markdown_filter(comment.comment), "commentid": comment.id, } ) ) output.append("</table></div>") return "\n".join(output)