Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] Export html #9

Open
wants to merge 27 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
8e331b4
basic html export
dschick Feb 17, 2019
d632eae
add link to export logbook to html
dschick Feb 17, 2019
ffb66f0
use slugify for filenames and improve temp-file handling
dschick Feb 17, 2019
b1cfe06
change file closing
dschick Feb 17, 2019
ccad908
Add buttons for hiding logbookstree and logbook
Mar 19, 2019
82af3c8
remove log
Mar 19, 2019
d683ec4
Added button to noentry for showing logbooktree and logbook
Mar 19, 2019
ab6b7b4
fix indent and clean uo
Mar 19, 2019
1ac7018
remove old design
Mar 22, 2019
bf24536
css for vertical text
Mar 22, 2019
d776498
remove legacy code from old design
Mar 25, 2019
631b3f1
remove legacy
Mar 25, 2019
cb6c8e1
legacy code
Mar 25, 2019
7aa8e11
fix css for border
Mar 25, 2019
7b83764
Merge branch 'show_hide_columns_hannes' into 'master'
hannes-petri-maxiv-lu-se Mar 25, 2019
4cfaf9d
filter out all descendants from select options in logbookselector
Jonas-Rosenqvist-maxiv May 24, 2019
f9d65be
Merge branch 'limit_logbook_move_to_non_descendants' into 'master'
Jonas-Rosenqvist-maxiv May 27, 2019
dcd3829
gitlab ci
Jonas-Rosenqvist-maxiv May 28, 2019
a38433a
Update .gitlab-ci.yml
Jonas-Rosenqvist-maxiv May 28, 2019
c1a6c6a
Update .gitlab-ci.yml
Jonas-Rosenqvist-maxiv May 28, 2019
073453f
Improved logbook editor component; disable editing of names of existi…
hannes-petri-maxiv-lu-se Jun 12, 2019
5528df9
Fixed whitespace issue
hannes-petri-maxiv-lu-se Jun 12, 2019
9a3b212
Added clarifying comment
hannes-petri-maxiv-lu-se Jun 12, 2019
a9cca5f
Made buttons in logbook edit mode not tiny
hannes-petri-maxiv-lu-se Jun 12, 2019
3de405a
Merge branch 'restrict_logbook_attribute_editing' into 'master'
Jonas-Rosenqvist-maxiv Jun 14, 2019
785ba53
Merge branch 'master' into export-html
dschick Jul 24, 2019
d1de59f
disable html attachment
dschick Jul 24, 2019
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions .gitlab-ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
before_script:
- docker info

build_backend_test_image:
stage: build
script:
- docker build ./backend/ -t docker.maxiv.lu.se/elogy_backend-test
- docker push docker.maxiv.lu.se/elogy_backend-test
only:
- master

build_frontend_test_image:
stage: build
script:
- docker build ./frontend/ -t docker.maxiv.lu.se/elogy_frontend-test
- docker push docker.maxiv.lu.se/elogy_frontend-test
only:
- master

deploy_test_image:
stage: deploy
script:
- 'curl -H "Authorization: Bearer $AWX_TOKEN" -XPOST https://ansible.maxiv.lu.se/api/v2/job_templates/22/launch/'
only:
- master
13 changes: 12 additions & 1 deletion backend/backend/api/entries.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import logging
from slugify import slugify

from flask import request, send_file
from flask_restful import Resource, marshal, marshal_with, abort
Expand All @@ -8,7 +9,7 @@

from ..db import Entry, Logbook, EntryLock
from ..attachments import handle_img_tags
from ..export import export_entries_as_pdf
from ..export import export_entries_as_pdf, export_entries_as_html
from ..actions import new_entry, edit_entry
from . import fields, send_signal

Expand Down Expand Up @@ -196,6 +197,16 @@ def get(self, args, logbook_id=None):
as_attachment=True,
attachment_filename=("{logbook.name}.pdf"
.format(logbook=logbook)))
elif args.get("download") == "html":
# return a PDF version
# TODO: not sure if this belongs in the API
html = export_entries_as_html(logbook, entries)
if html is None:
abort(400, message="Could not create HTML!")
return send_file(html, mimetype="text/html",
as_attachment=False,
attachment_filename=(slugify("{logbook.name}.html"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you think this the slugifying is really necessary? Shouldn't UTF-8 be OK in filenames nowadays? I'm asking because it is another dependency and I always like to think twice before adding those.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was also not sure about that either.
If you think filenames with '`´" etc. are okay, than I can remove it, no problem. I have not tested this for now myself.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll do some testing.

.format(logbook=logbook))))

return marshal(dict(logbook=logbook,
entries=list(entries)), fields.entries)
Expand Down
33 changes: 33 additions & 0 deletions backend/backend/export.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from tempfile import NamedTemporaryFile
from slugify import slugify

try:
import pdfkit
Expand Down Expand Up @@ -52,3 +53,35 @@ def export_entries_as_pdf(logbook, entries):
# https://github.com/wkhtmltopdf/wkhtmltopdf/issues/2051
pass
return f.name

def export_entries_as_html(logbook, entries):

"""
Super basic "proof-of-concept" html export
No proper formatting, and does not embed images.
"""

# export = ""
entries_html = [
"""
<div><b>Created at:</b> {created_at}</div>
<div><b>Title:</b> {title}</div>
<div><b>Authors:</b> {authors}</div>
<div>{content}</div>
<hr/>
""".format(title=entry.title or "(No title)",
authors=", ".join(a["name"] for a in entry.authors),
created_at=entry.created_at,
content=entry.content or "---")
for entry in entries
]

with NamedTemporaryFile(prefix=slugify(logbook.name),
suffix=".html",
delete=False) as f:
f.write('<h1>{}</h1>'.format(logbook.name).encode('utf8'))
f.write('<div>{}</div><hr/>'.format(logbook.description).encode('utf8'))
for entry_html in entries_html:
f.write(entry_html.encode('utf8'))
f.close()
return f.name
1 change: 1 addition & 0 deletions backend/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ peewee==2.10.2
Pillow==5.0.0
pyldap==2.4.45
python-dateutil==2.6.1
python-slugify==2.0.1
pytz==2017.3
six==1.11.0
uWSGI==2.0.15
Expand Down
13 changes: 13 additions & 0 deletions frontend/src/app.css
Original file line number Diff line number Diff line change
Expand Up @@ -105,4 +105,17 @@ a {
#entry .timestamp {
display: block;
}
}

.vertical-text {
writing-mode: tb-rl;
margin: 0px;
}

.showColumn{
margin: 5px;
}
.hiddenColumn{
background: #eee;
border-right: 1px solid #bbb;
}
63 changes: 56 additions & 7 deletions frontend/src/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ class NoEntry extends React.Component {
console.log(this.props.match.location);
return (
<div className="empty">
<i className="fa fa-arrow-left" /> Select an entry to read it
<i className="fa fa-arrow-left" /> Select an entry to read it
{logbookId ? (
<div>
{" "}
Expand All @@ -78,13 +78,61 @@ class NoEntry extends React.Component {
}
}

const Elogy = () => (
class HiddenColumn extends React.Component {

render() {
return (
<div className="hiddenColumn">
<a href="#">
<i className="fa fa-plus showColumn" onClick={() => this.props.show()}/>
</a>
<p className="vertical-text">{this.props.text}</p>
</div>
);
}
}



class Elogy extends React.Component {

constructor() {
super();
this.state = {
hideLogbookTree: false,
hideLogbook: false
};
this._hideLogbookTree = this._hideLogbookTree.bind(this);
this._hideLogbook = this._hideLogbook.bind(this);
}

componentDidMount() {
eventbus.subscribe("logbooktree.hide", this._hideLogbookTree);
eventbus.subscribe("logbook.hide", this._hideLogbook);
}

componentWillUnmount() {
eventbus.unsubscribe("logbooktree.hide", this._hideLogbookTree);
eventbus.unsubscribe("logbook.hide", this._hideLogbook);
}

_hideLogbookTree(hide) {
this.setState({hideLogbookTree: hide});
}

_hideLogbook(hide) {
this.setState({hideLogbook: hide});
}

render() {

return (
/* Set up a browser router that will render the correct component
in the right places, all depending on the current URL. */

<Router>
<div id="app">
<div id="logbooks">
{!this.state.hideLogbookTree ? <div id="logbooks">
<Switch>
<Route
path="/logbooks/:logbookId"
Expand All @@ -99,9 +147,9 @@ const Elogy = () => (
/>
<Route component={QuickSearch} />
</Switch>
</div>
</div> : <HiddenColumn text={"Show LogbookTree"} show={this._hideLogbookTree.bind(this, false)}/>}

<div id="logbook">
{!this.state.hideLogbook ? <div id="logbook">
<Switch>
<Route
path="/logbooks/:logbookId/entries/:entryId"
Expand All @@ -113,7 +161,7 @@ const Elogy = () => (
/>
<Route component={NoLogbook} />
</Switch>
</div>
</div> : <HiddenColumn text={"Show Logbook"} show={this._hideLogbook.bind(this, false)}/>}

<div id="entry">
<Switch>
Expand Down Expand Up @@ -146,5 +194,6 @@ const Elogy = () => (
</div>
</Router>
);

}
}
export default Elogy;
4 changes: 4 additions & 0 deletions frontend/src/logbook.css
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@
border-bottom: 1px solid #aaa;
}

#logbook header .commands {
float: right;
}

#logbook header .name {
font-size: 120%;
font-weight: bold;
Expand Down
22 changes: 21 additions & 1 deletion frontend/src/logbook.js
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,10 @@ class Logbook extends React.Component {
this.props.history.push(`?sort_by=${sortBy}`);
}

hide(){
this.props.eventbus.publish("logbook.hide", true);
}

render() {
const logbook = this.state.logbook,
entryId = this.props.match.params.entryId
Expand Down Expand Up @@ -239,7 +243,12 @@ class Logbook extends React.Component {
<i className="fa fa-book" />
{logbook.id === 0 ? "[All logbooks]" : logbook.name}
</span>

<div className="commands">
<a href="#">
<i className="fa fa-minus" onClick={() => this.hide()}/>
</a>
&nbsp;
</div>
<div>
{logbook.id ? (
<span>
Expand All @@ -264,6 +273,17 @@ class Logbook extends React.Component {
Configure
</Link>{" "}
|&nbsp;
<Link
to={{
pathname: `/api/logbooks/${logbook.id}/entries/?download=html`,
search: window.location.search
}}
title={`Export the logbook '${logbook.name}' to html`}
target="_blank"
>
Export HTML
</Link>{" "}
|&nbsp;
</span>
) : null}
<Link
Expand Down
1 change: 0 additions & 1 deletion frontend/src/logbookeditor.css
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@

#logbookeditor .attributes button {
margin: 0;
padding: 0;
}

#logbookeditor .attribute label {
Expand Down
Loading