Skip to content

Commit

Permalink
feat: add basic revisions page
Browse files Browse the repository at this point in the history
  • Loading branch information
Kyle Clemens committed Jun 27, 2018
1 parent eeb6c55 commit 964efbd
Show file tree
Hide file tree
Showing 13 changed files with 325 additions and 75 deletions.
2 changes: 2 additions & 0 deletions webserver/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,8 @@ fn main() {

routes::web::pastes::files::raw::get,

routes::web::pastes::revisions::get,

routes::web::pastes::get::edit,

routes::web::pastes::post::post,
Expand Down
1 change: 1 addition & 0 deletions webserver/src/routes/web/pastes/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ pub mod files;
pub mod get;
pub mod patch;
pub mod post;
pub mod revisions;
106 changes: 106 additions & 0 deletions webserver/src/routes/web/pastes/revisions.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
use config::Config;
use database::DbConn;
use database::models::pastes::Paste as DbPaste;
use database::models::users::User;
use database::schema::users;
use errors::*;
use models::id::PasteId;
use models::paste::output::{Output, OutputAuthor};
use routes::web::{context, Rst, OptionalWebUser, Session};

use diesel::prelude::*;

use git2::{Repository, DiffFormat, Oid, Commit, Tree};

use rocket::http::Status as HttpStatus;
use rocket::State;

use rocket_contrib::Template;

#[get("/pastes/<username>/<id>/revisions")]
fn get(username: String, id: PasteId, config: State<Config>, user: OptionalWebUser, mut sess: Session, conn: DbConn) -> Result<Rst> {
let paste: DbPaste = match id.get(&conn)? {
Some(p) => p,
None => return Ok(Rst::Status(HttpStatus::NotFound)),
};

let (expected_username, author): (String, Option<OutputAuthor>) = match paste.author_id() {
Some(author) => {
let user: User = users::table.find(author).first(&*conn)?;
(user.username().to_string(), Some(OutputAuthor::new(author, user.username(), user.name())))
},
None => ("anonymous".into(), None),
};

if username != expected_username {
return Ok(Rst::Status(HttpStatus::NotFound));
}

if let Some((status, _)) = paste.check_access(user.as_ref().map(|x| x.id())) {
return Ok(Rst::Status(status));
}

let repo = Repository::open(paste.files_directory())?;
let head = repo.refname_to_id("HEAD")?;
let head_commit = repo.find_commit(head)?;

let mut diffs = Vec::new();
let mut commit = head_commit;
loop {
let parent = match commit.parent(0) {
Ok(p) => DiffArg::Commit(p),
Err(_) => DiffArg::Tree(
// FIXME: this is using the sha1 of the empty tree, which all repos have, but there must be
// a better way
repo.find_tree(Oid::from_str("4b825dc642cb6eb9a060e54bf8d69288fbee4904")?)?,
),
};

let parent_tree = match parent {
DiffArg::Commit(ref c) => c.tree()?,
DiffArg::Tree(ref t) => t.clone(),
};

let diff = repo.diff_tree_to_tree(Some(&parent_tree), Some(&commit.tree()?), None)?;
let mut diff_str = String::new();
diff.print(DiffFormat::Patch, |_delta, _hunk, line| {
match line.origin() {
'+' | '-' | ' ' => diff_str.push(line.origin()),
_ => {}
}
diff_str += ::std::str::from_utf8(line.content()).unwrap();
true
})?;

diffs.push(diff_str);

match parent {
DiffArg::Commit(c) => commit = c,
DiffArg::Tree(_) => break,
}
}

let output = Output::new(
id,
author,
paste.name(),
paste.description(),
paste.visibility(),
None,
None,
);

let author_name = output.author.as_ref().map(|x| x.username.to_string()).unwrap_or_else(|| "anonymous".into());

let mut ctx = context(&*config, user.into_inner().as_ref(), &mut sess);
ctx["paste"] = json!(output);
ctx["author_name"] = json!(author_name);
ctx["diffs"] = json!(diffs);

Ok(Rst::Template(Template::render("paste/revisions", ctx)))
}

enum DiffArg<'repo> {
Commit(Commit<'repo>),
Tree(Tree<'repo>),
}
16 changes: 16 additions & 0 deletions webserver/web/src/css/custom.scss
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,18 @@ td.hljs-ln-code {
margin-top: -0.75rem;
}

.paste.hero-body {
padding-bottom: 1.5rem;
}

.hero-foot .tabs {
padding-bottom: 2px;

& ul {
align-items: flex-end;
}
}

.paste.container {
display: flex;
flex-direction: row;
Expand Down Expand Up @@ -129,6 +141,10 @@ td.hljs-ln-code {
white-space: pre-wrap;
}

.right.tag {
margin-left: .5rem;
}

a.external::after {
display: inline-block;
font-style: normal;
Expand Down
4 changes: 4 additions & 0 deletions webserver/web/src/css/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ td.hljs-ln-numbers {
color: hsl(228, 8%, 80%)
}

.hero-foot .tabs {
padding-bottom: 1px;
}

.box-title {
box-shadow: inset 0 -1px 0 0 $grey;

Expand Down
2 changes: 1 addition & 1 deletion webserver/web/static/css/dark-style.css

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion webserver/web/static/css/dark-style.css.map

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion webserver/web/static/css/style.css

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion webserver/web/static/css/style.css.map

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions webserver/web/templates/base.html.tera
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@
title="dark"
rel="stylesheet alternate"
href="/static/css/dark-style.css?v={{ resources_version }}"
integrity="sha384-OC4fJPnOypc1n0gONFndM5+Hokd/YKREaga28V8hY7MTf0EOOVBjkd4yDmv/N1MM"/>
integrity="sha384-pEGe8rRWhh6WmvgBmfJgWtraiZYAN5az4F60FEdoZvCKXdli0nOuuDypDLeWHhw4"/>
<link
title="light"
rel="stylesheet"
href="/static/css/style.css?v={{ resources_version }}"
integrity="sha384-XyHiIMsX1k4IwjRLp1zTLPKUD1X0pJfgrLjwSpxcS1yappHOWrnYZqCs7ehYhW7L"/>
integrity="sha384-lIWgzaaY3ALyBzkjZ1D/EobVOijI285t/uSGk5tHkrqHyMqgsfOVg1lYfl1FkSsD"/>
<script
src="/static/js/style.js?v={{ resources_version }}"
integrity="sha384-Jkt7YLun9UdrUCzwOTcLZcmUpkLflmI9Y/ksdoxa8m7HmpxkETujPoYB/av7Hy5E"></script>
Expand Down
93 changes: 60 additions & 33 deletions webserver/web/templates/paste/edit.html.tera
Original file line number Diff line number Diff line change
Expand Up @@ -41,41 +41,68 @@ Edit untitled paste
{% endif %}
{% endblock title %}

{% block header_title %}
{% if paste.name %}
Edit {{ paste.name }}
{% else %}
Edit <em>untitled paste</em>
{% endif %}
{% endblock header_title %}

{% block header_subtitle %}
Change this paste<span class="requires-js"> and its files</span>.
{% endblock header_subtitle %}
{% block header %}
<section class="hero is-dark">
<div class="paste hero-body">
<div class="paste container">
<div class="right">
<div class="field is-grouped">
{% if is_owner %}
<div class="control">
<a class="button is-info is-large" href="/pastes/{{ author_name | urlencode(safe="") }}/{{ paste.id }}/edit">
<span class="icon is-large">
<i class="fas fa-pencil-alt"></i>
</span>
</a>
</div>
{% endif %}
{% if not paste.author or is_owner %}
<div class="control">
<button class="button is-danger is-large opens-modal">
<span class="icon is-large">
<i class="fas fa-trash-alt"></i>
</span>
</button>
</div>
{% endif %}
</div>
</div>
<div class="left">
<h1 class="title">
Edit
{% if paste.name %}
<span class="keeps-spaces">{{ paste.name }}</span>
{% else %}
<em>untitled paste</em>
{% endif %}
</h1>
{% if paste.description %}
<h2 class="subtitle">
Change this paste<span class="requires-js"> and its files</span>.
</h2>
{% endif %}
</div>
</div>
</div>
<div class="hero-foot">
<div class="paste container">
<div class="right">
<em class="has-text-grey">{{ paste.visibility }}</em>
<span class="has-text-grey-light">/</span>
<em class="has-text-grey">2 days ago</em>
</div>
<div class="left tabs">
<ul>
<li><a href="/pastes/{{ author_name | urlencode(safe="") }}/{{ paste.id }}">files</a></li>
<li><a href="/pastes/{{ author_name | urlencode(safe="") }}/{{ paste.id }}/revisions">revisions <span class="right tag">2</span></a></li>
</ul>
</div>
</div>
</div>
</section>
{% endblock header %}

{% block main %}
<nav class="breadcrumb" aria-label="breadcrumbs">
<ul>
<li>
{% if paste.author.username %}
<a href="/users/{{ paste.author.username | urlencode(safe="") }}">{{ paste.author.username }}</a>
{% else %}
<a>anonymous</a>
{% endif %}
</li>
<li>
{% if paste.name %}
<a href="/pastes/{{ author_name | urlencode(safe="") }}/{{ paste.id }}">{{ paste.name }}</a>
{% else %}
<a href="/pastes/{{ author_name | urlencode(safe="") }}/{{ paste.id }}"><em>untitled paste</em></a>
{% endif %}
</li>
<li class="is-active">
<a>edit</a>
</li>
</ul>
</nav>

<form id="paste_upload" method="post" action="/pastes/{{ author_name | urlencode(safe="") }}/{{ paste.id }}">
<input type="hidden" name="_method" value="patch"/>
<input type="hidden" name="anti_csrf_token" value="{{ session.data.anti_csrf_token }}"/>
Expand Down
52 changes: 16 additions & 36 deletions webserver/web/templates/paste/index.html.tera
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ untitled paste

{% block header %}
<section class="hero is-dark">
<div class="hero-body">
<div class="paste hero-body">
<div class="paste container">
<div class="right">
<div class="field is-grouped">
Expand Down Expand Up @@ -80,20 +80,21 @@ untitled paste
<span class="keeps-spaces">{{ paste.description }}</span>
</h2>
{% endif %}
<div class="info-tags field is-grouped is-grouped-multiline">
<div class="control">
<div class="tags has-addons">
<span class="tag">visibility</span>
<span class="tag is-info">{{ paste.visibility }}</span>
</div>
</div>
{# <div class="control">
<div class="tags has-addons">
<span class="tag">created</span>
<span class="tag is-info">5 Dec 2017</span>
</div>
</div> #}
</div>
</div>
</div>
</div>
<div class="hero-foot">
<div class="paste container">
<div class="right">
<em class="has-text-grey">{{ paste.visibility }}</em>
<span class="has-text-grey-light">/</span>
<em class="has-text-grey">2 days ago</em>
</div>
<div class="left tabs">
<ul>
<li class="is-active"><a href="/pastes/{{ author_name | urlencode(safe="") }}/{{ paste.id }}">files</a></li>
<li><a href="/pastes/{{ author_name | urlencode(safe="") }}/{{ paste.id }}/revisions">revisions <span class="right tag">2</span></a></li>
</ul>
</div>
</div>
</div>
Expand Down Expand Up @@ -168,27 +169,6 @@ untitled paste
</div>
{% endif %}

<nav class="breadcrumb" aria-label="breadcrumbs">
<ul>
<li>
{% if paste.author.username and paste.author.name %}
<a href="/users/{{ paste.author.username | urlencode(safe="") }}">
{{ paste.author.name }}
</a>
{% else %}
<a>anonymous</a>
{% endif %}
</li>
<li class="is-active">
{% if paste.name %}
<a>{{ paste.name }}</a>
{% else %}
<a><em>untitled paste</em></a>
{% endif %}
</li>
</ul>
</nav>

{% for file in paste.files %}
<div class="box">
{% if file.name %}
Expand Down
Loading

0 comments on commit 964efbd

Please sign in to comment.