WIP pdf embedding
This commit is contained in:
23
cookbook/migrations/0026_auto_20200219_1605.py
Normal file
23
cookbook/migrations/0026_auto_20200219_1605.py
Normal 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),
|
||||||
|
),
|
||||||
|
]
|
@ -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)
|
||||||
|
@ -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"
|
||||||
|
@ -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')
|
||||||
|
@ -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'}})
|
||||||
|
|
||||||
|
@ -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 %}
|
@ -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');
|
||||||
|
@ -63,6 +63,4 @@
|
|||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% include 'include/recipe_open_modal.html' %}
|
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
@ -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 %}
|
@ -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>
|
||||||
|
@ -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'),
|
||||||
|
|
||||||
|
@ -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)
|
||||||
|
Reference in New Issue
Block a user