diff --git a/pagure/static/pagure.css b/pagure/static/pagure.css
index a75c4be..3ac7fab 100644
--- a/pagure/static/pagure.css
+++ b/pagure/static/pagure.css
@@ -893,3 +893,25 @@ span.CONFLICTS {
#pr_flags table tr{
margin-bottom: 1em;
}
+
+.textAreaLine {
+ width: 950px;
+ overflow: hidden;
+ position: relative;
+ text-indent: 1em;
+}
+
+.lineNum {
+ left: 0;
+ position: absolute;
+ text-align: right;
+ top: 0;
+ width: 27px;
+ font-size: 92.3%;
+ line-height: 100%;
+}
+
+#commit {
+ padding-top: 2em;
+ padding-left: 2em;
+}
diff --git a/pagure/templates/edit_file.html b/pagure/templates/edit_file.html
new file mode 100644
index 0000000..d8c6bbe
--- /dev/null
+++ b/pagure/templates/edit_file.html
@@ -0,0 +1,112 @@
+{% extends "repo_master.html" %}
+{% from "_formhelper.html" import render_field %}
+
+{% block title %}Edit - {{ repo.name }}{% endblock %}
+{%block tag %}home{% endblock %}
+
+
+{% block repo %}
+
+
+ {{ branchname }}/{%
+ for file in filename.split('/') %}
+ {% if loop.first %}
+ {% set path = file %}
+ {% else %}
+ {% set path = path + '/' + file %}
+ {% endif %}
+ {% if loop.index != loop.length %}{{ file }}/{% else %}{{ file }}{% endif %}
+ {% endfor %}
+
+
+
+
+{% endblock %}
+
+{% block jscripts %}
+{{ super() }}
+
+{% endblock %}
diff --git a/pagure/ui/repo.py b/pagure/ui/repo.py
index c55bea8..c9bc121 100644
--- a/pagure/ui/repo.py
+++ b/pagure/ui/repo.py
@@ -1131,3 +1131,82 @@ def revoke_api_token(repo, token_id, username=None):
flask.url_for(
'.view_settings', repo=repo.name, username=username)
)
+
+
+@APP.route(
+ '//edit//f/',
+ methods=('GET', 'POST'))
+@APP.route(
+ '/fork///edit//f/',
+ methods=('GET', 'POST'))
+@cla_required
+def edit_file(repo, branchname, filename, username=None):
+ """ Edit a file online.
+ """
+ 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 change the settings for this project')
+
+ 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')
+
+ branch = None
+ if branchname in repo_obj.listall_branches():
+ branch = repo_obj.lookup_branch(branchname)
+ commit = branch.get_object()
+ else:
+ flask.abort(400, 'Invalid branch specified')
+
+ form = pagure.forms.EditFileForm()
+ if form.validate_on_submit():
+ try:
+ pagure.lib.git.update_file_in_git(
+ repo,
+ branch=branchname,
+ filename=filename,
+ content=form.content.data,
+ message='%s\n\n%s' % (
+ form.commit_title.data.strip(),
+ form.commit_message.data.strip()
+ ),
+ user=flask.g.fas_user
+ )
+
+ return flask.redirect(
+ flask.url_for(
+ '.view_file', repo=repo.name, username=username,
+ identifier=branchname, filename=filename)
+ )
+ except pagure.exceptions.PagureException as err: # pragma: no cover
+ APP.logger.exception(err)
+ flask.flash('Commit could not be done', 'error')
+ data = form.content.data
+ elif flask.request.method == 'GET':
+ content = __get_file_in_tree(
+ repo_obj, commit.tree, filename.split('/'))
+ if not content or isinstance(content, pygit2.Tree):
+ flask.abort(404, 'File not found')
+ data = repo_obj[content.oid].data
+ else:
+ data = form.content.data
+
+ return flask.render_template(
+ 'edit_file.html',
+ select='tree',
+ repo=repo,
+ username=username,
+ branchname=branchname,
+ data=data,
+ filename=filename,
+ form=form,
+ )