WIP pdf embedding

This commit is contained in:
vabene1111
2020-02-19 16:55:13 +01:00
parent fc1cc70870
commit 88dc713683
12 changed files with 134 additions and 90 deletions

View File

@ -0,0 +1,23 @@
# Generated by Django 3.0.2 on 2020-02-19 15:05
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('cookbook', '0025_userpreference_nav_color'),
]
operations = [
migrations.AddField(
model_name='recipe',
name='cors_link',
field=models.CharField(blank=True, max_length=1024, null=True),
),
migrations.AlterField(
model_name='recipe',
name='link',
field=models.CharField(blank=True, max_length=512, null=True),
),
]

View File

@ -84,7 +84,8 @@ class Recipe(models.Model):
storage = models.ForeignKey(Storage, on_delete=models.PROTECT, blank=True, null=True) storage = models.ForeignKey(Storage, on_delete=models.PROTECT, blank=True, null=True)
file_uid = models.CharField(max_length=256, default="") file_uid = models.CharField(max_length=256, default="")
file_path = models.CharField(max_length=512, default="") file_path = models.CharField(max_length=512, default="")
link = models.CharField(max_length=512, default="") link = models.CharField(max_length=512, null=True, blank=True)
cors_link = models.CharField(max_length=1024, null=True, blank=True)
keywords = models.ManyToManyField(Keyword, blank=True) keywords = models.ManyToManyField(Keyword, blank=True)
working_time = models.IntegerField(default=0) working_time = models.IntegerField(default=0)
waiting_time = models.IntegerField(default=0) waiting_time = models.IntegerField(default=0)

View File

@ -88,6 +88,16 @@ class Dropbox(Provider):
response = Dropbox.create_share_link(recipe) response = Dropbox.create_share_link(recipe)
return response['url'] return response['url']
@staticmethod
def get_cors_link(recipe):
if not recipe.link:
recipe.link = Dropbox.get_share_link(recipe)
recipe.save()
recipe.cors_link = recipe.link.replace('www.dropbox.', 'dl.dropboxusercontent.')
return recipe.cors_link
@staticmethod @staticmethod
def rename_file(recipe, new_name): def rename_file(recipe, new_name):
url = "https://api.dropboxapi.com/2/files/move_v2" url = "https://api.dropboxapi.com/2/files/move_v2"

View File

@ -11,10 +11,14 @@ class Provider:
def get_share_link(recipe): def get_share_link(recipe):
raise Exception('Method not implemented in storage provider') raise Exception('Method not implemented in storage provider')
@staticmethod
def get_cors_link(recipe):
raise Exception('Method not implemented in storage provider')
@staticmethod @staticmethod
def rename_file(recipe, new_name): def rename_file(recipe, new_name):
raise Exception('Method not implemented in storage provider') raise Exception('Method not implemented in storage provider')
@staticmethod @staticmethod
def delete_file(recipe, new_name): def delete_file(recipe):
raise Exception('Method not implemented in storage provider') raise Exception('Method not implemented in storage provider')

View File

@ -8,8 +8,7 @@ from .models import *
class RecipeTable(tables.Table): class RecipeTable(tables.Table):
id = tables.LinkColumn('edit_recipe', args=[A('id')]) id = tables.LinkColumn('edit_recipe', args=[A('id')])
name = tables.TemplateColumn( name = tables.LinkColumn('view_recipe', args=[A('id')])
"<a href='#' onClick='openRecipe({{record.id}})'>{{record.name}}</a>")
all_tags = tables.Column( all_tags = tables.Column(
attrs={'td': {'class': 'd-none d-lg-table-cell'}, 'th': {'class': 'd-none d-lg-table-cell'}}) attrs={'td': {'class': 'd-none d-lg-table-cell'}, 'th': {'class': 'd-none d-lg-table-cell'}})

View File

@ -41,7 +41,7 @@
{% for r in b.recipes %} {% for r in b.recipes %}
<div class="row"> <div class="row">
<div class="col col-md-10"> <div class="col col-md-10">
<li><a href="#" onClick='openRecipe({{ r.recipe.pk }})'>{{ r.recipe.name }}</a></li> <li><a href="{% url 'view_recipe' r.recipe.pk %}">{{ r.recipe.name }}</a></li>
</div> </div>
<div class="col col-md-2" style="text-align: right"> <div class="col col-md-2" style="text-align: right">
<a href="{% url 'delete_recipe_book_entry' r.pk %}"><i class="fas fa-trash-alt"></i></a> <a href="{% url 'delete_recipe_book_entry' r.pk %}"><i class="fas fa-trash-alt"></i></a>
@ -58,5 +58,4 @@
<br/> <br/>
{% endfor %} {% endfor %}
{% include 'include/recipe_open_modal.html' %}
{% endblock %} {% endblock %}

View File

@ -43,15 +43,12 @@
</div> </div>
<script type="text/javascript"> <script type="text/javascript">
function openRecipe(id, force_external = false) { function openRecipe(id) {
var link = $('#a_recipe_open'); var link = $('#a_recipe_open');
link.hide(); link.hide();
$('#div_loader').show(); $('#div_loader').show();
var url = "{% url 'api_get_file_link' recipe_id=12345 %}".replace(/12345/, id); var url = "{% url 'api_get_external_file_link' recipe_id=12345 %}".replace(/12345/, id);
if (force_external) {
url = "{% url 'api_get_external_file_link' recipe_id=12345 %}".replace(/12345/, id);
}
link.text("{% trans 'Open Recipe' %}"); link.text("{% trans 'Open Recipe' %}");
$('#modal_recipe').modal('show'); $('#modal_recipe').modal('show');

View File

@ -63,6 +63,4 @@
</div> </div>
{% endif %} {% endif %}
{% include 'include/recipe_open_modal.html' %}
{% endblock %} {% endblock %}

View File

@ -56,7 +56,7 @@
<td> <td>
{% for mp in days_value %} {% for mp in days_value %}
<a href="{% url 'edit_plan' mp.pk %}"><i class="fas fa-edit"></i></a> <a href="{% url 'edit_plan' mp.pk %}"><i class="fas fa-edit"></i></a>
<a href="#" onclick="openRecipe({{ mp.recipe.id }})">{{ mp.recipe.name }}</a><br/> <a href="{% url 'view_recipe' mp.recipe.id %}">{{ mp.recipe.name }}</a><br/>
{% endfor %} {% endfor %}
</td> </td>
{% endfor %} {% endfor %}
@ -67,6 +67,4 @@
</div> </div>
</div> </div>
{% include 'include/recipe_open_modal.html' %}
{% endblock %} {% endblock %}

View File

@ -134,21 +134,23 @@
{% if recipe.storage %} {% if recipe.storage %}
<div class="row"> <div class="row">
{% if recipe.internal %} {% if recipe.internal %}
<a href='#' onClick='openRecipe({{ recipe.id }}, true)' <a href='#' onClick='openRecipe({{ recipe.id }})'
class="d-print-none">{% trans 'View external recipe' %} <i class="fas fa-external-link-alt"></i></a> class="d-print-none">{% trans 'View external recipe' %} <i class="fas fa-external-link-alt"></i></a>
{% else %} {% else %}
<div class="col col-md-12" style="margin-top: 2vh">
<div class="loader" id="id_loader"></div>
<canvas id="id_pdf_canvas" class="border"></canvas> <canvas id="id_pdf_canvas" class="border"></canvas>
</div>
<br/> <div class="col col-md-12" style="margin-top: 2vh">
<br/>
<br/>
<div class="card border-info"> <div class="card border-info">
<div class="card-body text-info"> <div class="card-body text-info">
<h5 class="card-title">{% trans 'External recipe' %}</h5> <h5 class="card-title">{% trans 'External recipe' %}</h5>
<p class="card-text"> <p class="card-text">
{% blocktrans %} {% blocktrans %}
This is an external recipe, which means you can only view it by opening the link above. This is an external recipe, which means you can only view it by opening the link
above.
You can convert this recipe to a fancy recipe by pressing the convert button. The You can convert this recipe to a fancy recipe by pressing the convert button. The
original original
file file
@ -158,33 +160,43 @@
<br/> <br/>
<a href="{% url 'edit_convert_recipe' recipe.pk %}" <a href="{% url 'edit_convert_recipe' recipe.pk %}"
class="card-link btn btn-info">{% trans 'Convert now!' %}</a> class="card-link btn btn-info">{% trans 'Convert now!' %}</a>
<a href='#' onClick='openRecipe({{ recipe.id }})'
class="d-print-none btn btn-warning">{% trans 'View external recipe' %} <i
class="fas fa-external-link-alt"></i></a>
</p> </p>
</div> </div>
</div> </div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/pdf.js/2.3.200/pdf.min.js" <script src="https://cdnjs.cloudflare.com/ajax/libs/pdf.js/2.3.200/pdf.min.js"
integrity="sha256-J4Z8Fhj2MITUakMQatkqOVdtqodUlwHtQ/ey6fSsudE=" integrity="sha256-J4Z8Fhj2MITUakMQatkqOVdtqodUlwHtQ/ey6fSsudE="
crossorigin="anonymous"></script> crossorigin="anonymous"></script>
<script type="text/javascript"> <script type="text/javascript">
var url = "{% url 'api_get_external_file_link' recipe_id=12345 %}".replace(/12345/, {{ recipe.id }}); var url = "{% url 'api_get_cors_file_link' recipe_id=12345 %}".replace(/12345/, {{ recipe.id }});
$('#id_pdf_canvas').hide();
var xhttp = new XMLHttpRequest(); var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function () { xhttp.onreadystatechange = function () {
if (this.readyState === 4 && this.status === 200) { if (this.readyState === 4 && this.status === 200) {
var url = this.responseText; var url = this.responseText;
$('#id_loader').hide();
var loadingTask = pdfjsLib.getDocument(url.replace('www.dropbox.', 'dl.dropboxusercontent.')); if (url === "None") {
// direct previews are not supported for this provider
//TODO implement something useful for providers not allowing cors links
} else {
var loadingTask = pdfjsLib.getDocument(url);
loadingTask.promise.then(function (pdf) { loadingTask.promise.then(function (pdf) {
console.log('PDF loaded'); $('#id_pdf_canvas').show();
// Fetch the first page // Fetch the first page
var pageNumber = 1; var pageNumber = 1;
pdf.getPage(pageNumber).then(function (page) { pdf.getPage(pageNumber).then(function (page) {
console.log('Page loaded');
var scale = 1.5; var scale = 1.5;
var viewport = page.getViewport({scale: scale*0.8}); var viewport = page.getViewport({scale: scale * 0.8});
// Prepare canvas using PDF page dimensions // Prepare canvas using PDF page dimensions
var canvas = document.getElementById('id_pdf_canvas'); var canvas = document.getElementById('id_pdf_canvas');
@ -207,11 +219,11 @@
console.error(reason); console.error(reason);
}); });
} }
}
}; };
xhttp.open("GET", url, true); xhttp.open("GET", url, true);
xhttp.send(); xhttp.send();
</script> </script>
{% endif %} {% endif %}
</div> </div>

View File

@ -60,8 +60,8 @@ urlpatterns = [
path('data/sync/wait', data.sync_wait, name='data_sync_wait'), path('data/sync/wait', data.sync_wait, name='data_sync_wait'),
path('data/statistics', data.statistics, name='data_stats'), path('data/statistics', data.statistics, name='data_stats'),
path('api/get_file_link/<int:recipe_id>/', api.get_file_link, name='api_get_file_link'),
path('api/get_external_file_link/<int:recipe_id>/', api.get_external_file_link, name='api_get_external_file_link'), path('api/get_external_file_link/<int:recipe_id>/', api.get_external_file_link, name='api_get_external_file_link'),
path('api/get_cors_file_link/<int:recipe_id>/', api.get_cors_file_link, name='api_get_cors_file_link'),
path('api/sync_all/', api.sync_all, name='api_sync'), path('api/sync_all/', api.sync_all, name='api_sync'),

View File

@ -10,40 +10,43 @@ from cookbook.provider.dropbox import Dropbox
from cookbook.provider.nextcloud import Nextcloud from cookbook.provider.nextcloud import Nextcloud
@login_required def update_recipe_links(recipe):
def get_file_link(request, recipe_id): if recipe.storage.method == Storage.DROPBOX:
recipe = Recipe.objects.get(id=recipe_id) provider = Dropbox
elif recipe.storage.method == Storage.NEXTCLOUD:
provider = Nextcloud
else:
raise Exception('Provider not implemented')
if recipe.internal: if not recipe.link:
return HttpResponse(reverse('view_recipe', args=[recipe_id])) recipe.link = provider.get_share_link(recipe) # TODO response validation in apis
if recipe.storage.method == Storage.DROPBOX: # TODO move to central location (as all provider related functions) if not recipe.cors_link:
if recipe.link == "": try:
recipe.link = Dropbox.get_share_link(recipe) # TODO response validation recipe.cors_link = provider.get_cors_link(recipe)
recipe.save() except Exception:
if recipe.storage.method == Storage.NEXTCLOUD: pass
if recipe.link == "":
recipe.link = Nextcloud.get_share_link(recipe) # TODO response validation
recipe.save()
return HttpResponse(recipe.link) recipe.save()
@login_required @login_required
def get_external_file_link(request, recipe_id): def get_external_file_link(request, recipe_id):
recipe = Recipe.objects.get(id=recipe_id) recipe = Recipe.objects.get(id=recipe_id)
if not recipe.link:
if recipe.storage.method == Storage.DROPBOX: # TODO move to central location (as all provider related functions) update_recipe_links(recipe)
if recipe.link == "":
recipe.link = Dropbox.get_share_link(recipe) # TODO response validation
recipe.save()
if recipe.storage.method == Storage.NEXTCLOUD:
if recipe.link == "":
recipe.link = Nextcloud.get_share_link(recipe) # TODO response validation
recipe.save()
return HttpResponse(recipe.link) return HttpResponse(recipe.link)
@login_required
def get_cors_file_link(request, recipe_id):
recipe = Recipe.objects.get(id=recipe_id)
if not recipe.cors_link:
update_recipe_links(recipe)
return HttpResponse(recipe.cors_link)
@login_required @login_required
def sync_all(request): def sync_all(request):
monitors = Sync.objects.filter(active=True) monitors = Sync.objects.filter(active=True)