Skip to content

Commit 539a7f4

Browse files
authored
Merge pull request #43 from DataManagementLab/#26_pdf
#26 pdf
2 parents 146c8db + f7efbf2 commit 539a7f4

13 files changed

Lines changed: 151 additions & 5 deletions

File tree

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ Collab Coursebook has two types of requirements: System requirements are depende
2020

2121
* Python 3.6 incl. development tools
2222
* Virtualenv
23+
* poppler
2324
* for production using uwsgi:
2425
* C compiler e.g. gcc
2526
* uwsgi

collab_coursebook/settings.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
1818
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
1919

20+
## Allow Pdf Previewer
21+
X_FRAME_OPTIONS = 'SAMEORIGIN'
2022

2123
# Quick-start development settings - unsuitable for production
2224
# See https://docs.djangoproject.com/en/3.0/howto/deployment/checklist/

content/admin.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from django.contrib import admin
22

3-
from content.models import YTVideoContent, ImageContent
3+
from content.models import YTVideoContent, ImageContent, PdfContent
44

55

66
@admin.register(YTVideoContent)
@@ -11,3 +11,8 @@ class YTVideoContentAdmin(admin.ModelAdmin):
1111
@admin.register(ImageContent)
1212
class ImageContentAdmin(admin.ModelAdmin):
1313
pass
14+
15+
16+
@admin.register(PdfContent)
17+
class PdfContentAdmin(admin.ModelAdmin):
18+
pass

content/forms.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
from django import forms
2-
from content.models import YTVideoContent, ImageContent
2+
from content.models import YTVideoContent, ImageContent, PdfContent
33

44

55
class AddContentFormYoutubeVideo(forms.ModelForm):
@@ -14,7 +14,14 @@ class Meta:
1414
exclude = ['content']
1515

1616

17+
class AddContentFormPdf(forms.ModelForm):
18+
class Meta:
19+
model = PdfContent
20+
exclude = ['content']
21+
22+
1723
CONTENT_TYPE_FORMS = {
1824
YTVideoContent.TYPE: AddContentFormYoutubeVideo,
1925
ImageContent.TYPE: AddContentFormImage,
26+
PdfContent.TYPE: AddContentFormPdf
2027
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# Generated by Django 3.0.4 on 2020-06-22 15:33
2+
3+
from django.db import migrations, models
4+
import django.db.models.deletion
5+
6+
7+
class Migration(migrations.Migration):
8+
9+
dependencies = [
10+
('base', '0010_favorite'),
11+
('content', '0003_license_verbose_name'),
12+
]
13+
14+
operations = [
15+
migrations.CreateModel(
16+
name='PdfContent',
17+
fields=[
18+
('content', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, primary_key=True, serialize=False, to='base.Content', verbose_name='Content')),
19+
('pdf', models.ImageField(upload_to='uploads/contents/%Y/%m/%d/', verbose_name='pdf')),
20+
('source', models.TextField(verbose_name='Source')),
21+
('license', models.CharField(blank=True, max_length=200, verbose_name='License')),
22+
],
23+
options={
24+
'verbose_name': 'Pdf Content',
25+
'verbose_name_plural': 'Pdf Contents',
26+
},
27+
),
28+
]
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# Generated by Django 3.0.4 on 2020-07-29 14:05
2+
3+
from django.db import migrations, models
4+
5+
6+
class Migration(migrations.Migration):
7+
8+
dependencies = [
9+
('content', '0004_pdfcontent'),
10+
]
11+
12+
operations = [
13+
migrations.AlterField(
14+
model_name='pdfcontent',
15+
name='pdf',
16+
field=models.FileField(upload_to='uploads/contents/%Y/%m/%d/', verbose_name='Pdf'),
17+
),
18+
]

content/mixin.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
2+
class GeneratePreviewMixin:
3+
"""
4+
Provides method to generate Preview Images
5+
"""
6+
def generate_preview(self):
7+
return

content/models.py

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,18 @@
1+
import os
2+
13
from django.db import models
24
from django.utils.translation import gettext_lazy as _
3-
45
from base.models import Content
6+
from content.mixin import GeneratePreviewMixin
7+
from pdf2image import convert_from_path, convert_from_bytes
8+
from PIL import Image
9+
from pdf2image.exceptions import (
10+
PDFInfoNotInstalledError,
11+
PDFPageCountError,
12+
PDFSyntaxError
13+
)
14+
15+
from django.conf import settings
516

617

718
class YTVideoContent(models.Model):
@@ -15,6 +26,9 @@ class Meta:
1526
content = models.OneToOneField(Content, verbose_name=_("Content"), on_delete=models.CASCADE, primary_key=True)
1627
url = models.URLField(verbose_name=_("Video URL"))
1728

29+
def generate_preview(self):
30+
return
31+
1832
@property
1933
def id(self):
2034
return self.url.split("=")[1]
@@ -39,8 +53,42 @@ class Meta:
3953
def __str__(self):
4054
return f"{self.content}: {self.image}"
4155

56+
def generate_preview(self):
57+
# TODO generate small image previews
58+
return
59+
60+
61+
class PdfContent(models.Model, GeneratePreviewMixin):
62+
TYPE = "Pdf"
63+
DESC = _("Pdf")
64+
65+
class Meta:
66+
verbose_name = _("Pdf Content")
67+
verbose_name_plural = _("Pdf Contents")
68+
69+
content = models.OneToOneField(Content, verbose_name=_("Content"), on_delete=models.CASCADE, primary_key=True)
70+
pdf = models.FileField(verbose_name=_("Pdf"), upload_to='uploads/contents/%Y/%m/%d/')
71+
source = models.TextField(verbose_name=_("Source"))
72+
license = models.CharField(verbose_name=_("License"), blank=True, max_length=200)
73+
74+
def generate_preview(self):
75+
preview_folder = 'uploads/previews/'
76+
# Check if Folder exists
77+
if not os.path.exists(os.path.join(settings.MEDIA_ROOT,preview_folder)):
78+
os.makedirs(os.path.join(settings.MEDIA_ROOT,preview_folder))
79+
base_filename = os.path.splitext(os.path.basename(self.pdf.name))[0] + '.jpg'
80+
# get images for every page
81+
pages = convert_from_path(self.pdf.path, last_page=2)
82+
# save first page to disk
83+
pages[0].save(os.path.join(settings.MEDIA_ROOT,preview_folder, base_filename))
84+
return os.path.join(preview_folder, base_filename)
85+
86+
def __str__(self):
87+
return f"{self.content}: {self.pdf}"
88+
4289

4390
CONTENT_TYPES = {
4491
YTVideoContent.TYPE: YTVideoContent,
4592
ImageContent.TYPE: ImageContent,
93+
PdfContent.TYPE: PdfContent
4694
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
2+
3+
<img class="card-img-top fit" style="height: 180px;" src="{% if content.preview %}{{content.preview.url}}{% endif %}" alt="{{ content.description }}" width="500" height="600">
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
{% load i18n %}
2+
3+
4+
5+
<div class="row">
6+
<div class="col">
7+
<embed src="{{ content.pdfcontent.pdf.url }}" type="application/pdf" height="700px" width="100%">
8+
9+
10+
</div>
11+
12+
</div>
13+
<b>{% trans "Source" %}:</b>
14+
<p>{{ content.Pdfcontent.source }}</p>
15+
16+
{% if content.Pdfcontent.license %}
17+
<b>{% trans "License" %}:</b>
18+
<p>{{ content.Pdfcontent.license }}</p>
19+
{% endif %}

0 commit comments

Comments
 (0)