def pull_request_drop_comment(repo, requestid, username=None): """ Delete a comment of a pull-request. """ repo = pagure.lib.get_project(SESSION, repo, user=username) if not repo: flask.abort(404, 'Project not found') if not repo.settings.get('pull_requests', True): flask.abort(404, 'No pull-requests found for this project') request = pagure.lib.search_pull_requests(SESSION, project_id=repo.id, requestid=requestid) if not request: flask.abort(404, 'Pull-request not found') if flask.request.form.get('edit_comment'): commentid = flask.request.form.get('edit_comment') form = pagure.forms.EditCommentForm() if form.validate_on_submit(): return pull_request_edit_comment(repo.name, requestid, commentid, username=username) form = pagure.forms.ConfirmationForm() if form.validate_on_submit(): if flask.request.form.get('drop_comment'): commentid = flask.request.form.get('drop_comment') comment = pagure.lib.get_request_comment(SESSION, request.uid, commentid) if comment is None or comment.pull_request.project != repo: flask.abort(404, 'Comment not found') if (flask.g.fas_user.username != comment.user.username or comment.parent.status is False) \ and not is_repo_admin(repo): flask.abort( 403, 'You are not allowed to remove this comment from ' 'this issue') SESSION.delete(comment) try: SESSION.commit() flask.flash('Comment removed') except SQLAlchemyError as err: # pragma: no cover SESSION.rollback() LOG.error(err) flask.flash('Could not remove the comment: %s' % commentid, 'error') return flask.redirect( flask.url_for('request_pull', username=username, repo=repo.name, requestid=requestid))
def edit_tag(repo, tag, username=None): """ Edit the specified tag of a project. """ repo = pagure.lib.get_project(SESSION, repo, user=username) if not repo: flask.abort(404, 'Project not found') if not is_repo_admin(repo): flask.abort( 403, 'You are not allowed to edt tags of this project') form = pagure.forms.AddIssueTagForm() if form.validate_on_submit(): new_tag = form.tag.data msgs = pagure.lib.edit_issue_tags( SESSION, repo, tag, new_tag, user=flask.g.fas_user.username, ticketfolder=APP.config['TICKETS_FOLDER'] ) try: SESSION.commit() for msg in msgs: flask.flash(msg) except SQLAlchemyError, err: # pragma: no cover SESSION.rollback() LOG.error(err) flask.flash('Could not edit tag: %s' % tag, 'error') return flask.redirect(flask.url_for( '.view_settings', repo=repo.name, username=username))
def remove_tag(repo, username=None): """ Remove the specified tag from the project. """ repo = pagure.lib.get_project(SESSION, repo, user=username) if not repo: flask.abort(404, 'Project not found') if not is_repo_admin(repo): flask.abort( 403, 'You are not allowed to remove tags of this project') form = pagure.forms.AddIssueTagForm() if form.validate_on_submit(): tags = form.tag.data tags = [tag.strip() for tag in tags.split(',')] msgs = pagure.lib.remove_tags( SESSION, repo, tags, user=flask.g.fas_user.username, ticketfolder=APP.config['TICKETS_FOLDER'] ) try: SESSION.commit() for msg in msgs: flask.flash(msg) except SQLAlchemyError, err: # pragma: no cover SESSION.rollback() LOG.error(err) flask.flash( 'Could not remove tag: %s' % ','.join(tags), 'error')
def edit_comment_issue(repo, issueid, commentid, username=None): """Edit comment of an issue """ is_js = flask.request.args.get('js', False) project = pagure.lib.get_project(SESSION, repo, user=username) if not project: flask.abort(404, 'Project not found') if not project.settings.get('issue_tracker', True): flask.abort(404, 'No issue tracker found for this project') issue = pagure.lib.search_issues(SESSION, project, issueid=issueid) if issue is None or issue.project != project: flask.abort(404, 'Issue not found') comment = pagure.lib.get_issue_comment( SESSION, issue.uid, commentid) if comment is None or comment.parent.project != project: flask.abort(404, 'Comment not found') if (flask.g.fas_user.username != comment.user.username or comment.parent.status != 'Open') \ and not is_repo_admin(project): flask.abort(403, 'You are not allowed to edit this comment') form = pagure.forms.EditCommentForm() if form.validate_on_submit(): updated_comment = form.update_comment.data try: message = pagure.lib.edit_comment( SESSION, parent=issue, comment=comment, user=flask.g.fas_user.username, updated_comment=updated_comment, folder=APP.config['TICKETS_FOLDER'], ) SESSION.commit() if not is_js: flask.flash(message) except SQLAlchemyError, err: # pragma: no cover SESSION.rollback() LOG.error(err) if is_js: return 'error' flask.flash( 'Could not edit the comment: %s' % commentid, 'error') if is_js: return 'ok' return flask.redirect(flask.url_for( 'view_issue', username=username, repo=project.name, issueid=issueid))
def edit_comment_issue(repo, issueid, commentid, username=None): """Edit comment of an issue """ is_js = flask.request.args.get('js', False) project = pagure.lib.get_project(SESSION, repo, user=username) if not project: flask.abort(404, 'Project not found') if not project.settings.get('issue_tracker', True): flask.abort(404, 'No issue tracker found for this project') issue = pagure.lib.search_issues(SESSION, project, issueid=issueid) if issue is None or issue.project != project: flask.abort(404, 'Issue not found') comment = pagure.lib.get_issue_comment(SESSION, issue.uid, commentid) if comment is None or comment.parent.project != project: flask.abort(404, 'Comment not found') if (flask.g.fas_user.username != comment.user.username or comment.parent.status != 'Open') \ and not is_repo_admin(project): flask.abort(403, 'You are not allowed to edit this comment') form = pagure.forms.EditCommentForm() if form.validate_on_submit(): updated_comment = form.update_comment.data try: message = pagure.lib.edit_comment( SESSION, parent=issue, comment=comment, user=flask.g.fas_user.username, updated_comment=updated_comment, folder=APP.config['TICKETS_FOLDER'], ) SESSION.commit() if not is_js: flask.flash(message) except SQLAlchemyError, err: # pragma: no cover SESSION.rollback() LOG.error(err) if is_js: return 'error' flask.flash('Could not edit the comment: %s' % commentid, 'error') if is_js: return 'ok' return flask.redirect( flask.url_for('view_issue', username=username, repo=project.name, issueid=issueid))
def edit_tag(repo, tag, username=None): """ Edit the specified tag of a project. """ repo = pagure.lib.get_project(SESSION, repo, user=username) if not repo: flask.abort(404, 'Project not found') if not is_repo_admin(repo): flask.abort(403, 'You are not allowed to edt tags of this project') form = pagure.forms.AddIssueTagForm() if form.validate_on_submit(): new_tag = form.tag.data msgs = pagure.lib.edit_issue_tags( SESSION, repo, tag, new_tag, user=flask.g.fas_user.username, ticketfolder=APP.config['TICKETS_FOLDER']) try: SESSION.commit() for msg in msgs: flask.flash(msg) except SQLAlchemyError, err: # pragma: no cover SESSION.rollback() LOG.error(err) flask.flash('Could not edit tag: %s' % tag, 'error') return flask.redirect( flask.url_for('.view_settings', repo=repo.name, username=username))
def remove_tag(repo, username=None): """ Remove the specified tag from the project. """ repo = pagure.lib.get_project(SESSION, repo, user=username) if not repo: flask.abort(404, 'Project not found') if not is_repo_admin(repo): flask.abort(403, 'You are not allowed to remove tags of this project') form = pagure.forms.AddIssueTagForm() if form.validate_on_submit(): tags = form.tag.data tags = [tag.strip() for tag in tags.split(',')] msgs = pagure.lib.remove_tags( SESSION, repo, tags, user=flask.g.fas_user.username, ticketfolder=APP.config['TICKETS_FOLDER']) try: SESSION.commit() for msg in msgs: flask.flash(msg) except SQLAlchemyError, err: # pragma: no cover SESSION.rollback() LOG.error(err) flask.flash('Could not remove tag: %s' % ','.join(tags), 'error')
def pull_request_drop_comment(repo, requestid, username=None): """ Delete a comment of a pull-request. """ repo = pagure.lib.get_project(SESSION, repo, user=username) if not repo: flask.abort(404, 'Project not found') if not repo.settings.get('pull_requests', True): flask.abort(404, 'No pull-requests found for this project') request = pagure.lib.search_pull_requests( SESSION, project_id=repo.id, requestid=requestid) if not request: flask.abort(404, 'Pull-request not found') if flask.request.form.get('edit_comment'): commentid = flask.request.form.get('edit_comment') form = pagure.forms.EditCommentForm() if form.validate_on_submit(): return pull_request_edit_comment( repo.name, requestid, commentid, username=username) form = pagure.forms.ConfirmationForm() if form.validate_on_submit(): if flask.request.form.get('drop_comment'): commentid = flask.request.form.get('drop_comment') comment = pagure.lib.get_request_comment( SESSION, request.uid, commentid) if comment is None or comment.pull_request.project != repo: flask.abort(404, 'Comment not found') if (flask.g.fas_user.username != comment.user.username or comment.parent.status is False) \ and not is_repo_admin(repo): flask.abort( 403, 'You are not allowed to remove this comment from ' 'this issue') SESSION.delete(comment) try: SESSION.commit() flask.flash('Comment removed') except SQLAlchemyError as err: # pragma: no cover SESSION.rollback() LOG.error(err) flask.flash( 'Could not remove the comment: %s' % commentid, 'error') return flask.redirect(flask.url_for( 'request_pull', username=username, repo=repo.name, requestid=requestid))
def pull_request_edit_comment(repo, requestid, commentid, username=None): """Edit comment of a pull request """ is_js = flask.request.args.get("js", False) project = pagure.lib.get_project(SESSION, repo, user=username) if not project: flask.abort(404, "Project not found") if not project.settings.get("pull_requests", True): flask.abort(404, "No pull-requests found for this project") request = pagure.lib.search_pull_requests(SESSION, project_id=project.id, requestid=requestid) if not request: flask.abort(404, "Pull-request not found") comment = pagure.lib.get_request_comment(SESSION, request.uid, commentid) if comment is None or comment.parent.project != project: flask.abort(404, "Comment not found") if (flask.g.fas_user.username != comment.user.username or comment.parent.status != "Open") and not is_repo_admin( project ): flask.abort(403, "You are not allowed to edit the comment") form = pagure.forms.EditCommentForm() if form.validate_on_submit(): updated_comment = form.update_comment.data try: message = pagure.lib.edit_comment( SESSION, parent=request, comment=comment, user=flask.g.fas_user.username, updated_comment=updated_comment, folder=APP.config["REQUESTS_FOLDER"], ) SESSION.commit() if not is_js: flask.flash(message) except SQLAlchemyError, err: # pragma: no cover SESSION.rollback() LOG.error(err) if is_js: return "error" flask.flash("Could not edit the comment: %s" % commentid, "error") if is_js: return "ok" return flask.redirect(flask.url_for("request_pull", username=username, repo=project.name, requestid=requestid))
def edit_tag(repo, tag, username=None): """ Edit the specified tag associated with the issues of a project. """ repo = pagure.lib.get_project(SESSION, repo, user=username) if not repo: flask.abort(404, 'Project not found') if not is_repo_admin(repo): flask.abort( 403, 'You are not allowed to edit tags associated with the issues of \ this project') if not repo.settings.get('issue_tracker', True): flask.abort(404, 'No issue tracker found for this project') tags = pagure.lib.get_tags_of_project(SESSION, repo) if not tags or tag not in [t.tag for t in tags]: flask.abort(404, 'Tag %s not found in this project' % tag) form = pagure.forms.AddIssueTagForm() if form.validate_on_submit(): new_tag = form.tag.data msgs = pagure.lib.edit_issue_tags( SESSION, repo, tag, new_tag, user=flask.g.fas_user.username, ticketfolder=APP.config['TICKETS_FOLDER']) try: SESSION.commit() for msg in msgs: flask.flash(msg) except SQLAlchemyError as err: # pragma: no cover SESSION.rollback() LOG.error(err) flask.flash('Could not edit tag: %s' % tag, 'error') return flask.redirect( flask.url_for('.view_settings', repo=repo.name, username=username)) return flask.render_template( 'edit_tag.html', form=form, username=username, repo=repo, edit_tag=tag, )
def edit_tag(repo, tag, username=None): """ Edit the specified tag associated with the issues of a project. """ repo = pagure.lib.get_project(SESSION, repo, user=username) if not repo: flask.abort(404, 'Project not found') if not is_repo_admin(repo): flask.abort( 403, 'You are not allowed to edit tags associated with the issues of \ this project') if not repo.settings.get('issue_tracker', True): flask.abort(404, 'No issue tracker found for this project') tags = pagure.lib.get_tags_of_project(SESSION, repo) if not tags or tag not in [t.tag for t in tags]: flask.abort(404, 'Tag %s not found in this project' % tag ) form = pagure.forms.AddIssueTagForm() if form.validate_on_submit(): new_tag = form.tag.data msgs = pagure.lib.edit_issue_tags( SESSION, repo, tag, new_tag, user=flask.g.fas_user.username, ticketfolder=APP.config['TICKETS_FOLDER'] ) try: SESSION.commit() for msg in msgs: flask.flash(msg) except SQLAlchemyError as err: # pragma: no cover SESSION.rollback() LOG.error(err) flask.flash('Could not edit tag: %s' % tag, 'error') return flask.redirect(flask.url_for( '.view_settings', repo=repo.name, username=username)) return flask.render_template( 'edit_tag.html', form=form, username=username, repo=repo, edit_tag=tag, )
def remove_tag(repo, username=None): """ Remove the specified tag, associated with the issues, from the project. """ repo = pagure.lib.get_project(SESSION, repo, user=username) if not repo: flask.abort(404, 'Project not found') if not is_repo_admin(repo): flask.abort( 403, 'You are not allowed to remove tags associated with the issues \ of this project') if not repo.settings.get('issue_tracker', True): flask.abort(404, 'No issue tracker found for this project') form = pagure.forms.AddIssueTagForm() if form.validate_on_submit(): tags = form.tag.data tags = [tag.strip() for tag in tags.split(',')] msgs = pagure.lib.remove_tags( SESSION, repo, tags, user=flask.g.fas_user.username, ticketfolder=APP.config['TICKETS_FOLDER'] ) try: SESSION.commit() for msg in msgs: flask.flash(msg) except SQLAlchemyError as err: # pragma: no cover SESSION.rollback() LOG.error(err) flask.flash( 'Could not remove tag: %s' % ','.join(tags), 'error') return flask.redirect( flask.url_for('.view_settings', repo=repo.name, username=username) )
def remove_tag(repo, username=None): """ Remove the specified tag, associated with the issues, from the project. """ repo = pagure.lib.get_project(SESSION, repo, user=username) if not repo: flask.abort(404, 'Project not found') if not is_repo_admin(repo): flask.abort( 403, 'You are not allowed to remove tags associated with the issues \ of this project') if not repo.settings.get('issue_tracker', True): flask.abort(404, 'No issue tracker found for this project') form = pagure.forms.AddIssueTagForm() if form.validate_on_submit(): tags = form.tag.data tags = [tag.strip() for tag in tags.split(',')] msgs = pagure.lib.remove_tags( SESSION, repo, tags, user=flask.g.fas_user.username, ticketfolder=APP.config['TICKETS_FOLDER']) try: SESSION.commit() for msg in msgs: flask.flash(msg) except SQLAlchemyError as err: # pragma: no cover SESSION.rollback() LOG.error(err) flask.flash('Could not remove tag: %s' % ','.join(tags), 'error') return flask.redirect( flask.url_for('.view_settings', repo=repo.name, username=username))
def view_file(repo, identifier, filename, username=None): """ Displays the content of a file or a tree for the specified repo. """ repo = pagure.lib.get_project(SESSION, repo, user=username) if not repo: flask.abort(404, 'Project not found') reponame = pagure.get_repo_path(repo) repo_obj = pygit2.Repository(reponame) if repo_obj.is_empty: flask.abort(404, 'Empty repo cannot have a file') if identifier in repo_obj.listall_branches(): branchname = identifier branch = repo_obj.lookup_branch(identifier) commit = branch.get_object() else: try: commit = repo_obj.get(identifier) branchname = identifier except ValueError: if 'master' not in repo_obj.listall_branches(): flask.abort(404, 'Branch no found') # If it's not a commit id then it's part of the filename commit = repo_obj[repo_obj.head.target] branchname = 'master' if commit and not isinstance(commit, pygit2.Blob): content = __get_file_in_tree(repo_obj, commit.tree, filename.split('/')) if not content: flask.abort(404, 'File not found') content = repo_obj[content.oid] else: content = commit if isinstance(content, pygit2.Blob): if content.is_binary or not pagure.lib.could_be_text(content.data): ext = filename[filename.rfind('.'):] if ext in ('.gif', '.png', '.bmp', '.tif', '.tiff', '.jpg', '.jpeg', '.ppm', '.pnm', '.pbm', '.pgm', '.webp', '.ico'): try: Image.open(StringIO(content.data)) output_type = 'image' except IOError as err: LOG.debug('Failed to load image %s, error: %s', filename, err) output_type = 'binary' else: output_type = 'binary' else: try: lexer = guess_lexer_for_filename(filename, content.data) except ClassNotFound: lexer = TextLexer() content = highlight(content.data, lexer, HtmlFormatter( noclasses=True, style="tango", )) output_type = 'file' else: content = sorted(content, key=lambda x: x.filemode) output_type = 'tree' return flask.render_template( 'file.html', select='tree', repo=repo, username=username, branchname=branchname, filename=filename, content=content, output_type=output_type, repo_admin=is_repo_admin(repo), )
def update_issue(repo, issueid, username=None, namespace=None): ''' Add a comment to an issue. ''' is_js = flask.request.args.get('js', False) repo = flask.g.repo if flask.request.method == 'GET': if not is_js: flask.flash('Invalid method: GET', 'error') return flask.redirect(flask.url_for( 'view_issue', username=username, repo=repo.name, namespace=repo.namespace, issueid=issueid)) if not repo.settings.get('issue_tracker', True): flask.abort(404, 'No issue tracker found for this project') issue = pagure.lib.search_issues(SESSION, repo, issueid=issueid) if issue is None or issue.project != repo: flask.abort(404, 'Issue not found') if issue.private and not flask.g.repo_admin \ and (not authenticated() or not issue.user.user == flask.g.fas_user.username): flask.abort( 403, 'This issue is private and you are not allowed to view it') if flask.request.form.get('edit_comment'): commentid = flask.request.form.get('edit_comment') form = pagure.forms.EditCommentForm() if form.validate_on_submit(): return edit_comment_issue( repo.name, issueid, commentid, username=username) status = pagure.lib.get_issue_statuses(SESSION) form = pagure.forms.UpdateIssueForm( status=status, priorities=repo.priorities, milestones=repo.milestones, ) if form.validate_on_submit(): repo_admin = flask.g.repo_admin if flask.request.form.get('drop_comment'): commentid = flask.request.form.get('drop_comment') comment = pagure.lib.get_issue_comment( SESSION, issue.uid, commentid) if comment is None or comment.issue.project != repo: flask.abort(404, 'Comment not found') if (flask.g.fas_user.username != comment.user.username or comment.parent.status != 'Open') \ and not flask.g.repo_admin: flask.abort( 403, 'You are not allowed to remove this comment from ' 'this issue') SESSION.delete(comment) try: SESSION.commit() if not is_js: flask.flash('Comment removed') except SQLAlchemyError as err: # pragma: no cover is_js = False SESSION.rollback() LOG.error(err) if not is_js: flask.flash( 'Could not remove the comment: %s' % commentid, 'error') if is_js: return 'ok' else: return flask.redirect(flask.url_for( 'view_issue', username=username, repo=repo.name, namespace=repo.namespace, issueid=issueid)) comment = form.comment.data depends = [] for depend in form.depends.data.split(','): if depend.strip(): try: depends.append(int(depend.strip())) except ValueError: pass blocks = [] for block in form.blocks.data.split(','): if block.strip(): try: blocks.append(int(block.strip())) except ValueError: pass assignee = form.assignee.data new_status = form.status.data new_priority = None try: new_priority = int(form.priority.data) except: pass tags = [ tag.strip() for tag in form.tag.data.split(',') if tag.strip()] new_milestone = None try: new_milestone = form.milestone.data.strip() or None except: pass try: messages = set() # New comment if comment: message = pagure.lib.add_issue_comment( SESSION, issue=issue, comment=comment, user=flask.g.fas_user.username, ticketfolder=APP.config['TICKETS_FOLDER'], ) SESSION.commit() if message and not is_js: messages.add(message) if repo_admin: # Adjust (add/remove) tags messages.union(set(pagure.lib.update_tags( SESSION, issue, tags, username=flask.g.fas_user.username, ticketfolder=APP.config['TICKETS_FOLDER'] ))) # The meta-data can only be changed by admins, which means they # will be missing for non-admin and thus reset if we let them if repo_admin: # Assign or update assignee of the ticket message = pagure.lib.add_issue_assignee( SESSION, issue=issue, assignee=assignee or None, user=flask.g.fas_user.username, ticketfolder=APP.config['TICKETS_FOLDER'], ) SESSION.commit() if message: messages.add(message) # Update status if new_status in status: message = pagure.lib.edit_issue( SESSION, issue=issue, status=new_status, private=issue.private, user=flask.g.fas_user.username, ticketfolder=APP.config['TICKETS_FOLDER'], ) SESSION.commit() if message: messages.add(message) # Update priority if str(new_priority) in repo.priorities: message = pagure.lib.edit_issue( SESSION, issue=issue, priority=new_priority, private=issue.private, user=flask.g.fas_user.username, ticketfolder=APP.config['TICKETS_FOLDER'], ) SESSION.commit() if message: messages.add(message) # Update milestone and privacy setting message = pagure.lib.edit_issue( SESSION, issue=issue, milestone=new_milestone, private=form.private.data, user=flask.g.fas_user.username, ticketfolder=APP.config['TICKETS_FOLDER'], ) SESSION.commit() if message: messages.add(message) # Update ticket this one depends on messages.union(set(pagure.lib.update_dependency_issue( SESSION, repo, issue, depends, username=flask.g.fas_user.username, ticketfolder=APP.config['TICKETS_FOLDER'], ))) # Update ticket(s) depending on this one messages.union(set(pagure.lib.update_blocked_issue( SESSION, repo, issue, blocks, username=flask.g.fas_user.username, ticketfolder=APP.config['TICKETS_FOLDER'], ))) if not is_js: for message in messages: flask.flash(message) except pagure.exceptions.PagureException as err: is_js = False SESSION.rollback() if not is_js: flask.flash(err.message, 'error') except SQLAlchemyError as err: # pragma: no cover is_js = False SESSION.rollback() APP.logger.exception(err) if not is_js: flask.flash(str(err), 'error') if is_js: return 'ok' else: return flask.redirect(flask.url_for( 'view_issue', username=username, repo=repo.name, issueid=issueid))
def view_file(repo, identifier, filename, username=None): """ Displays the content of a file or a tree for the specified repo. """ repo = pagure.lib.get_project(SESSION, repo, user=username) if not repo: flask.abort(404, 'Project not found') reponame = pagure.get_repo_path(repo) repo_obj = pygit2.Repository(reponame) if repo_obj.is_empty: flask.abort(404, 'Empty repo cannot have a file') if identifier in repo_obj.listall_branches(): branchname = identifier branch = repo_obj.lookup_branch(identifier) commit = branch.get_object() else: try: commit = repo_obj.get(identifier) branchname = identifier except ValueError: if 'master' not in repo_obj.listall_branches(): flask.abort(404, 'Branch no found') # If it's not a commit id then it's part of the filename commit = repo_obj[repo_obj.head.target] branchname = 'master' if commit and not isinstance(commit, pygit2.Blob): content = __get_file_in_tree( repo_obj, commit.tree, filename.split('/'), bail_on_tree=True) if not content: flask.abort(404, 'File not found') content = repo_obj[content.oid] else: content = commit if not content: flask.abort(404, 'File not found') if isinstance(content, pygit2.Blob): if content.is_binary or not pagure.lib.could_be_text(content.data): ext = filename[filename.rfind('.'):] if ext in ( '.gif', '.png', '.bmp', '.tif', '.tiff', '.jpg', '.jpeg', '.ppm', '.pnm', '.pbm', '.pgm', '.webp', '.ico'): try: Image.open(StringIO(content.data)) output_type = 'image' except IOError as err: LOG.debug( 'Failed to load image %s, error: %s', filename, err ) output_type = 'binary' else: output_type = 'binary' else: try: lexer = guess_lexer_for_filename( filename, content.data ) except (ClassNotFound, TypeError): lexer = TextLexer() content = highlight( content.data, lexer, HtmlFormatter( noclasses=True, style="tango",) ) output_type = 'file' else: content = sorted(content, key=lambda x: x.filemode) output_type = 'tree' return flask.render_template( 'file.html', select='tree', repo=repo, username=username, branchname=branchname, filename=filename, content=content, output_type=output_type, repo_admin=is_repo_admin(repo), )
def view_file(repo, identifier, filename, username=None): """ Displays the content of a file or a tree for the specified repo. """ repo = pagure.lib.get_project(SESSION, repo, user=username) if not repo: flask.abort(404, "Project not found") reponame = pagure.get_repo_path(repo) repo_obj = pygit2.Repository(reponame) if repo_obj.is_empty: flask.abort(404, "Empty repo cannot have a file") if identifier in repo_obj.listall_branches(): branchname = identifier branch = repo_obj.lookup_branch(identifier) commit = branch.get_object() else: try: commit = repo_obj.get(identifier) branchname = identifier except ValueError: if "master" not in repo_obj.listall_branches(): flask.abort(404, "Branch no found") # If it's not a commit id then it's part of the filename commit = repo_obj[repo_obj.head.target] branchname = "master" if isinstance(commit, pygit2.Tag): commit = commit.get_object() if commit and not isinstance(commit, pygit2.Blob): content = __get_file_in_tree(repo_obj, commit.tree, filename.split("/"), bail_on_tree=True) if not content: flask.abort(404, "File not found") content = repo_obj[content.oid] else: content = commit if not content: flask.abort(404, "File not found") if isinstance(content, pygit2.Blob): ext = filename[filename.rfind(".") :] if ext in ( ".gif", ".png", ".bmp", ".tif", ".tiff", ".jpg", ".jpeg", ".ppm", ".pnm", ".pbm", ".pgm", ".webp", ".ico", ): try: Image.open(StringIO(content.data)) output_type = "image" except IOError as err: LOG.debug("Failed to load image %s, error: %s", filename, err) output_type = "binary" elif not content.is_binary and pagure.lib.could_be_text(content.data): file_content = content.data.decode("utf-8") try: lexer = guess_lexer_for_filename(filename, file_content) except (ClassNotFound, TypeError): lexer = TextLexer() content = highlight(file_content, lexer, HtmlFormatter(noclasses=True, style="tango")) output_type = "file" else: output_type = "binary" else: content = sorted(content, key=lambda x: x.filemode) output_type = "tree" return flask.render_template( "file.html", select="tree", repo=repo, username=username, branchname=branchname, filename=filename, content=content, output_type=output_type, repo_admin=is_repo_admin(repo), )
def update_issue(repo, issueid, username=None): ''' Add a comment to an issue. ''' is_js = flask.request.args.get('js', False) repo = pagure.lib.get_project(SESSION, repo, user=username) if flask.request.method == 'GET': if not is_js: flask.flash('Invalid method: GET', 'error') return flask.redirect(flask.url_for( 'view_issue', username=username, repo=repo.name, issueid=issueid)) if repo is None: flask.abort(404, 'Project not found') if not repo.settings.get('issue_tracker', True): flask.abort(404, 'No issue tracker found for this project') issue = pagure.lib.search_issues(SESSION, repo, issueid=issueid) if issue is None or issue.project != repo: flask.abort(404, 'Issue not found') if issue.private and not is_repo_admin(repo) \ and (not authenticated() or not issue.user.user == flask.g.fas_user.username): flask.abort( 403, 'This issue is private and you are not allowed to view it') if flask.request.form.get('edit_comment'): commentid = flask.request.form.get('edit_comment') form = pagure.forms.EditCommentForm() if form.validate_on_submit(): return edit_comment_issue( repo.name, issueid, commentid, username=username) status = pagure.lib.get_issue_statuses(SESSION) form = pagure.forms.UpdateIssueForm( status=status, priorities=repo.priorities) if form.validate_on_submit(): repo_admin = is_repo_admin(repo) if flask.request.form.get('drop_comment'): commentid = flask.request.form.get('drop_comment') comment = pagure.lib.get_issue_comment( SESSION, issue.uid, commentid) if comment is None or comment.issue.project != repo: flask.abort(404, 'Comment not found') if (flask.g.fas_user.username != comment.user.username or comment.parent.status != 'Open') \ and not is_repo_admin(repo): flask.abort( 403, 'You are not allowed to remove this comment from ' 'this issue') SESSION.delete(comment) try: SESSION.commit() if not is_js: flask.flash('Comment removed') except SQLAlchemyError as err: # pragma: no cover is_js = False SESSION.rollback() LOG.error(err) if not is_js: flask.flash( 'Could not remove the comment: %s' % commentid, 'error') if is_js: return 'ok' else: return flask.redirect(flask.url_for( 'view_issue', username=username, repo=repo.name, issueid=issueid)) comment = form.comment.data depends = [] for depend in form.depends.data.split(','): if depend.strip(): try: depends.append(int(depend.strip())) except ValueError: pass blocks = [] for block in form.blocks.data.split(','): if block.strip(): try: blocks.append(int(block.strip())) except ValueError: pass assignee = form.assignee.data new_status = form.status.data new_priority = None try: new_priority = int(form.priority.data) except: pass tags = [ tag.strip() for tag in form.tag.data.split(',') if tag.strip()] try: # New comment if comment: message = pagure.lib.add_issue_comment( SESSION, issue=issue, comment=comment, user=flask.g.fas_user.username, ticketfolder=APP.config['TICKETS_FOLDER'], ) SESSION.commit() if message and not is_js: flask.flash(message) if repo_admin: # Adjust (add/remove) tags messages = pagure.lib.update_tags( SESSION, issue, tags, username=flask.g.fas_user.username, ticketfolder=APP.config['TICKETS_FOLDER'] ) if not is_js: for message in messages: flask.flash(message) # Assign or update assignee of the ticket message = pagure.lib.add_issue_assignee( SESSION, issue=issue, assignee=assignee or None, user=flask.g.fas_user.username, ticketfolder=APP.config['TICKETS_FOLDER'], ) if message and not is_js: SESSION.commit() flask.flash(message) if repo_admin: # Update status if new_status in status: message = pagure.lib.edit_issue( SESSION, issue=issue, status=new_status, private=issue.private, user=flask.g.fas_user.username, ticketfolder=APP.config['TICKETS_FOLDER'], ) SESSION.commit() if message: flask.flash(message) # Update priority if str(new_priority) in repo.priorities: message = pagure.lib.edit_issue( SESSION, issue=issue, priority=new_priority, private=issue.private, user=flask.g.fas_user.username, ticketfolder=APP.config['TICKETS_FOLDER'], ) SESSION.commit() if message: flask.flash(message) # Update ticket this one depends on messages = pagure.lib.update_dependency_issue( SESSION, repo, issue, depends, username=flask.g.fas_user.username, ticketfolder=APP.config['TICKETS_FOLDER'], ) if not is_js: for message in messages: flask.flash(message) # Update ticket(s) depending on this one messages = pagure.lib.update_blocked_issue( SESSION, repo, issue, blocks, username=flask.g.fas_user.username, ticketfolder=APP.config['TICKETS_FOLDER'], ) if not is_js: for message in messages: flask.flash(message) except pagure.exceptions.PagureException as err: is_js = False SESSION.rollback() if not is_js: flask.flash(err.message, 'error') except SQLAlchemyError as err: # pragma: no cover is_js = False SESSION.rollback() APP.logger.exception(err) if not is_js: flask.flash(str(err), 'error') if is_js: return 'ok' else: return flask.redirect(flask.url_for( 'view_issue', username=username, repo=repo.name, issueid=issueid))
def view_issue_raw_file( repo, filename=None, username=None, namespace=None): """ Displays the raw content of a file of a commit for the specified ticket repo. """ repo = flask.g.repo if not repo.settings.get('issue_tracker', True): flask.abort(404, 'No issue tracker found for this project') reponame = os.path.join(APP.config['TICKETS_FOLDER'], repo.path) repo_obj = pygit2.Repository(reponame) if repo_obj.is_empty: flask.abort(404, 'Empty repo cannot have a file') branch = repo_obj.lookup_branch('master') commit = branch.get_object() mimetype = None encoding = None content = __get_file_in_tree( repo_obj, commit.tree, filename.split('/'), bail_on_tree=True) if not content or isinstance(content, pygit2.Tree): flask.abort(404, 'File not found') mimetype, encoding = mimetypes.guess_type(filename) data = repo_obj[content.oid].data if not data: flask.abort(404, 'No content found') if (filename.endswith('.patch') or filename.endswith('.diff')) \ and not is_binary_string(content.data): # We have a patch file attached to this issue, render the diff in html orig_filename = filename.partition('-')[2] return flask.render_template( 'patchfile.html', select='issues', repo=repo, username=username, diff=data, patchfile=orig_filename, form=pagure.forms.ConfirmationForm(), ) if not mimetype and data[:2] == '#!': mimetype = 'text/plain' headers = {} if not mimetype: if '\0' in data: mimetype = 'application/octet-stream' else: mimetype = 'text/plain' elif 'html' in mimetype: mimetype = 'application/octet-stream' headers['Content-Disposition'] = 'attachment' if mimetype.startswith('text/') and not encoding: try: encoding = pagure.lib.encoding_utils.guess_encoding( ktc.to_bytes(data)) except pagure.exceptions.PagureException: # We cannot decode the file, so bail but warn the admins LOG.exception('File could not be decoded') if encoding: mimetype += '; charset={encoding}'.format(encoding=encoding) headers['Content-Type'] = mimetype return (data, 200, headers)
def edit_tag(repo, tag, username=None, namespace=None): """ Edit the specified tag associated with the issues of a project. """ repo = flask.g.repo if not flask.g.repo_admin: flask.abort( 403, 'You are not allowed to edit tags associated with the issues of \ this project') if not repo.settings.get('issue_tracker', True): flask.abort(404, 'No issue tracker found for this project') tags = pagure.lib.get_tags_of_project(SESSION, repo) if not tags: flask.abort(404, 'Project has no tags to edit') # Check the tag exists, and get its old/original color tagobj = pagure.lib.get_tag(SESSION, tag, repo.id) if not tagobj: flask.abort(404, 'Tag %s not found in this project' % tag) form = pagure.forms.AddIssueTagForm() if form.validate_on_submit(): new_tag = form.tag.data new_tag_color = form.tag_color.data msgs = pagure.lib.edit_issue_tags( SESSION, repo, tagobj, new_tag, new_tag_color, user=flask.g.fas_user.username, ticketfolder=APP.config['TICKETS_FOLDER'] ) try: SESSION.commit() for msg in msgs: flask.flash(msg) except SQLAlchemyError as err: # pragma: no cover SESSION.rollback() LOG.error(err) flask.flash('Could not edit tag: %s' % tag, 'error') return flask.redirect(flask.url_for( '.view_settings', repo=repo.name, username=username, namespace=repo.namespace)) elif flask.request.method == 'GET': form.tag_color.data = tagobj.tag_color form.tag.data = tag return flask.render_template( 'edit_tag.html', username=username, repo=repo, form=form, tagname=tag, )
def update_issue(repo, issueid, username=None, namespace=None): ''' Add a comment to an issue. ''' is_js = flask.request.args.get('js', False) repo = flask.g.repo if flask.request.method == 'GET': if not is_js: flask.flash('Invalid method: GET', 'error') return flask.redirect(flask.url_for( 'view_issue', username=username, repo=repo.name, namespace=repo.namespace, issueid=issueid)) if not repo.settings.get('issue_tracker', True): flask.abort(404, 'No issue tracker found for this project') issue = pagure.lib.search_issues(SESSION, repo, issueid=issueid) if issue is None or issue.project != repo: flask.abort(404, 'Issue not found') if issue.private and not flask.g.repo_admin \ and (not authenticated() or not issue.user.user == flask.g.fas_user.username): flask.abort( 403, 'This issue is private and you are not allowed to view it') if flask.request.form.get('edit_comment'): commentid = flask.request.form.get('edit_comment') form = pagure.forms.EditCommentForm() if form.validate_on_submit(): return edit_comment_issue( repo.name, issueid, commentid, username=username) status = pagure.lib.get_issue_statuses(SESSION) form = pagure.forms.UpdateIssueForm( status=status, priorities=repo.priorities, milestones=repo.milestones, close_status=repo.close_status, ) if form.validate_on_submit(): repo_admin = flask.g.repo_admin if flask.request.form.get('drop_comment'): commentid = flask.request.form.get('drop_comment') comment = pagure.lib.get_issue_comment( SESSION, issue.uid, commentid) if comment is None or comment.issue.project != repo: flask.abort(404, 'Comment not found') if (flask.g.fas_user.username != comment.user.username or comment.parent.status != 'Open') \ and not flask.g.repo_admin: flask.abort( 403, 'You are not allowed to remove this comment from ' 'this issue') issue.last_updated = datetime.datetime.utcnow() SESSION.add(issue) SESSION.delete(comment) try: SESSION.commit() if not is_js: flask.flash('Comment removed') except SQLAlchemyError as err: # pragma: no cover is_js = False SESSION.rollback() LOG.error(err) if not is_js: flask.flash( 'Could not remove the comment: %s' % commentid, 'error') if is_js: return 'ok' else: return flask.redirect(flask.url_for( 'view_issue', username=username, repo=repo.name, namespace=repo.namespace, issueid=issueid)) comment = form.comment.data depends = [] for depend in form.depends.data.split(','): if depend.strip(): try: depends.append(int(depend.strip())) except ValueError: pass blocks = [] for block in form.blocks.data.split(','): if block.strip(): try: blocks.append(int(block.strip())) except ValueError: pass assignee = form.assignee.data.strip() or None new_status = form.status.data.strip() or None close_status = form.close_status.data or None if new_status != 'Closed': close_status = None if close_status not in repo.close_status: close_status = None new_priority = None try: new_priority = int(form.priority.data) except: pass tags = [ tag.strip() for tag in form.tag.data.split(',') if tag.strip()] new_milestone = None try: if repo.milestones: new_milestone = form.milestone.data.strip() or None except: pass try: messages = set() # New comment if comment: message = pagure.lib.add_issue_comment( SESSION, issue=issue, comment=comment, user=flask.g.fas_user.username, ticketfolder=APP.config['TICKETS_FOLDER'], ) SESSION.commit() if message and not is_js: messages.add(message) # The status field can be updated by both the admin and the # person who opened the ticket. # Update status if repo_admin or flask.g.fas_user.username == issue.user.user: if new_status in status: message = pagure.lib.edit_issue( SESSION, issue=issue, status=new_status, close_status=close_status, private=issue.private, user=flask.g.fas_user.username, ticketfolder=APP.config['TICKETS_FOLDER'], ) SESSION.commit() if message: messages.add(message) # All the other meta-data can be changed only by admins # while other field will be missing for non-admin and thus # reset if we let them if repo_admin: # Adjust (add/remove) tags messages.union(set(pagure.lib.update_tags( SESSION, issue, tags, username=flask.g.fas_user.username, ticketfolder=APP.config['TICKETS_FOLDER'] ))) # The meta-data can be changed by admins and issue creator, # where issue creators can only change status of their issue while # other fields will be missing for non-admin and thus reset if we let them if repo_admin: # Assign or update assignee of the ticket message = pagure.lib.add_issue_assignee( SESSION, issue=issue, assignee=assignee or None, user=flask.g.fas_user.username, ticketfolder=APP.config['TICKETS_FOLDER'], ) SESSION.commit() if message and message != 'Nothing to change': messages.add(message) # Update priority if str(new_priority) in repo.priorities: message = pagure.lib.edit_issue( SESSION, issue=issue, priority=new_priority, private=issue.private, user=flask.g.fas_user.username, ticketfolder=APP.config['TICKETS_FOLDER'], ) SESSION.commit() if message: messages.add(message) # Update milestone and privacy setting message = pagure.lib.edit_issue( SESSION, issue=issue, milestone=new_milestone, private=form.private.data, user=flask.g.fas_user.username, ticketfolder=APP.config['TICKETS_FOLDER'], ) SESSION.commit() if message: messages.add(message) # Update the custom keys/fields for key in repo.issue_keys: value = flask.request.form.get(key.name) if value: if key.key_type == 'link': links = value.split(',') for link in links: link = link.replace(' ', '') if not urlpattern.match(link): flask.abort( 400, 'Meta-data "link" field ' '(%s) has invalid url (%s) ' % (key.name, link)) messages.add( pagure.lib.set_custom_key_value( SESSION, issue, key, value) ) # Update ticket this one depends on messages.union(set(pagure.lib.update_dependency_issue( SESSION, repo, issue, depends, username=flask.g.fas_user.username, ticketfolder=APP.config['TICKETS_FOLDER'], ))) # Update ticket(s) depending on this one messages.union(set(pagure.lib.update_blocked_issue( SESSION, repo, issue, blocks, username=flask.g.fas_user.username, ticketfolder=APP.config['TICKETS_FOLDER'], ))) if not is_js: for message in messages: flask.flash(message) except pagure.exceptions.PagureException as err: is_js = False SESSION.rollback() flask.flash(err.message, 'error') except SQLAlchemyError as err: # pragma: no cover is_js = False SESSION.rollback() APP.logger.exception(err) flask.flash(str(err), 'error') except filelock.Timeout as err: # pragma: no cover is_js = False SESSION.rollback() APP.logger.exception(err) flask.flash( 'We could not save all the info, please try again', 'error') else: if is_js: return 'notok: %s' % form.errors if is_js: return 'ok' else: return flask.redirect(flask.url_for( 'view_issue', repo=repo.name, username=username, namespace=namespace, issueid=issueid) )
def update_issue(repo, issueid, username=None): ''' Add a comment to an issue. ''' is_js = flask.request.args.get('js', False) repo = pagure.lib.get_project(SESSION, repo, user=username) if flask.request.method == 'GET': if not is_js: flask.flash('Invalid method: GET', 'error') return flask.redirect( flask.url_for('view_issue', username=username, repo=repo.name, issueid=issueid)) if repo is None: flask.abort(404, 'Project not found') if not repo.settings.get('issue_tracker', True): flask.abort(404, 'No issue tracker found for this project') issue = pagure.lib.search_issues(SESSION, repo, issueid=issueid) if issue is None or issue.project != repo: flask.abort(404, 'Issue not found') if issue.private and not is_repo_admin(repo) \ and (not authenticated() or not issue.user.user == flask.g.fas_user.username): flask.abort( 403, 'This issue is private and you are not allowed to view it') status = pagure.lib.get_issue_statuses(SESSION) form = pagure.forms.UpdateIssueForm(status=status) if form.validate_on_submit(): repo_admin = is_repo_admin(repo) if flask.request.form.get('drop_comment'): commentid = flask.request.form.get('drop_comment') comment = pagure.lib.get_issue_comment(SESSION, issue.uid, commentid) if comment is None or comment.issue.project != repo: flask.abort(404, 'Comment not found') if (flask.g.fas_user.username != comment.user.username or comment.parent.status != 'Open') \ and not is_repo_admin(repo): flask.abort( 403, 'You are not allowed to remove this comment from ' 'this issue') SESSION.delete(comment) try: SESSION.commit() if not is_js: flask.flash('Comment removed') except SQLAlchemyError, err: # pragma: no cover is_js = False SESSION.rollback() LOG.error(err) if not is_js: flask.flash('Could not remove the comment: %s' % commentid, 'error') comment = form.comment.data depends = [] for depend in form.depends.data.split(','): if depend.strip(): try: depends.append(int(depend.strip())) except ValueError: pass blocks = [] for block in form.blocks.data.split(','): if block.strip(): try: blocks.append(int(block.strip())) except ValueError: pass assignee = form.assignee.data new_status = form.status.data tags = [tag.strip() for tag in form.tag.data.split(',') if tag.strip()] try: # New comment if comment: message = pagure.lib.add_issue_comment( SESSION, issue=issue, comment=comment, user=flask.g.fas_user.username, ticketfolder=APP.config['TICKETS_FOLDER'], redis=REDIS, ) SESSION.commit() if message and not is_js: flask.flash(message) if repo_admin: # Adjust (add/remove) tags messages = pagure.lib.update_tags( SESSION, issue, tags, username=flask.g.fas_user.username, ticketfolder=APP.config['TICKETS_FOLDER'], redis=REDIS) if not is_js: for message in messages: flask.flash(message) # Assign or update assignee of the ticket message = pagure.lib.add_issue_assignee( SESSION, issue=issue, assignee=assignee or None, user=flask.g.fas_user.username, ticketfolder=APP.config['TICKETS_FOLDER'], redis=REDIS, ) if message and not is_js: SESSION.commit() flask.flash(message) if repo_admin: # Update status if new_status in status: message = pagure.lib.edit_issue( SESSION, issue=issue, status=new_status, private=issue.private, user=flask.g.fas_user.username, ticketfolder=APP.config['TICKETS_FOLDER'], redis=REDIS, ) SESSION.commit() if message: flask.flash(message) # Update ticket this one depends on messages = pagure.lib.update_dependency_issue( SESSION, repo, issue, depends, username=flask.g.fas_user.username, ticketfolder=APP.config['TICKETS_FOLDER'], redis=REDIS, ) if not is_js: for message in messages: flask.flash(message) # Update ticket(s) depending on this one messages = pagure.lib.update_blocked_issue( SESSION, repo, issue, blocks, username=flask.g.fas_user.username, ticketfolder=APP.config['TICKETS_FOLDER'], redis=REDIS, ) if not is_js: for message in messages: flask.flash(message) except pagure.exceptions.PagureException, err: is_js = False SESSION.rollback() if not is_js: flask.flash(err.message, 'error')