# success: true
# model.Url
- def send_book(self, book):
- wlbook = book.wldocument(librarian2=True)
+ def send_book(self, book, changes=None):
+ wlbook = book.wldocument(librarian2=True, changes=changes)
meta = wlbook.meta
cover = LabelMarquiseCover(meta, width=1200).output_file()
--- /dev/null
+from django.core.management.base import BaseCommand
+from depot.models import LegimiBookPublish
+
+
+class Command(BaseCommand):
+ def handle(self, **options):
+ for p in LegimiBookPublish.objects.filter(status=0).order_by('created_at'):
+ print(p, p.book.slug, p.created_at)
+ p.publish()
+
--- /dev/null
+# Generated by Django 3.2.12 on 2022-07-14 10:36
+
+from django.conf import settings
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ migrations.swappable_dependency(settings.AUTH_USER_MODEL),
+ ('documents', '0008_book_legimi_id'),
+ ('depot', '0001_initial'),
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='LegimiBookPublish',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('created_at', models.DateTimeField()),
+ ('started_at', models.DateTimeField(blank=True, null=True)),
+ ('finished_at', models.DateTimeField(blank=True, null=True)),
+ ('status', models.PositiveSmallIntegerField(choices=[(0, 'queued'), (10, 'running'), (100, 'done'), (110, 'error')], default=0)),
+ ('error', models.TextField(blank=True)),
+ ('book', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='documents.book')),
+ ('user', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL)),
+ ],
+ ),
+ migrations.CreateModel(
+ name='LegimiChunkPublish',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('book_publish', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='depot.legimibookpublish')),
+ ('change', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='documents.chunkchange')),
+ ],
+ ),
+ ]
import json
import os
import tempfile
+import traceback
import zipfile
from datetime import datetime
+from django.conf import settings
from django.db import models
+from django.utils.timezone import now
from librarian.cover import make_cover
from librarian.builders import EpubBuilder, MobiBuilder
+from .legimi import legimi
class Package(models.Model):
fname,
output.get_bytes()
)
+
+
+class LegimiBookPublish(models.Model):
+ book = models.ForeignKey('documents.Book', models.CASCADE)
+ user = models.ForeignKey(settings.AUTH_USER_MODEL, models.SET_NULL, null=True)
+ created_at = models.DateTimeField()
+ started_at = models.DateTimeField(null=True, blank=True)
+ finished_at = models.DateTimeField(null=True, blank=True)
+ status = models.PositiveSmallIntegerField(choices=[
+ (0, 'queued'),
+ (10, 'running'),
+ (100, 'done'),
+ (110, 'error'),
+ ], default=0)
+ error = models.TextField(blank=True)
+
+ @classmethod
+ def create_for(cls, book, user):
+ book.assert_publishable()
+ changes = book.get_current_changes(publishable=True)
+ me = cls.objects.create(book=book, user=user, created_at=now())
+ for change in changes:
+ me.legimichunkpublish_set.create(change=change)
+ return me
+
+ def publish(self):
+ self.status = 10
+ self.started_at = now()
+ self.save(update_fields=['status', 'started_at'])
+ try:
+ changes = [
+ p.change for p in
+ self.legimichunkpublish_set.order_by('change__chunk__number')
+ ]
+ legimi.send_book(self.book, changes=changes)
+ except Exception:
+ self.status = 110
+ self.error = traceback.format_exc()
+ else:
+ self.status = 100
+ self.error = ''
+ self.finished_at = now()
+ self.save(update_fields=['status', 'finished_at', 'error'])
+
+
+class LegimiChunkPublish(models.Model):
+ book_publish = models.ForeignKey(LegimiBookPublish, models.CASCADE)
+ change = models.ForeignKey('documents.ChunkChange', models.CASCADE)
--- /dev/null
+from django.urls import path
+from . import views
+
+
+urlpatterns = [
+ path(
+ 'legimi-publish/<int:book_id>/',
+ views.LegimiPublishView.as_view(),
+ name='depot_legimi_publish'
+ )
+]
-from django.shortcuts import render
+from django.contrib.auth.mixins import PermissionRequiredMixin
+from django.shortcuts import get_object_or_404, redirect
+from django.views import View
+from documents.models import Book
+from . import models
-# Create your views here.
+
+class LegimiPublishView(PermissionRequiredMixin, View):
+ permission_required = 'depot.add_legimibookpublish'
+
+ def post(self, request, book_id):
+ book = get_object_or_404(Book, pk=book_id)
+ try:
+ publish = models.LegimiBookPublish.create_for(book, request.user)
+ except AssertionError:
+ pass
+ return redirect(book.get_absolute_url())
except IndexError:
return None
+ def last_legimi_publish(self):
+ return self.legimibookpublish_set.order_by('-created_at').first()
+
def assert_publishable(self):
assert self.chunk_set.exists(), _('No chunks in the book.')
try:
{{ publish_options_form.as_p }}
<img src="{{ STATIC_URL }}img/angel-left.png" style="vertical-align: middle" />
<button id="publish-button" type="submit">
- <span>{% trans "Publish" %}</span></button>
+ <span>{% trans "Publish" %}</span></button>
<img src="{{ STATIC_URL }}img/angel-right.png" style="vertical-align: middle" />
- </form>
+ </form>
+
+ {% if perms.depot.add_legimibookpublish %}
+ <hr>
+ <form method="post" action="{% url 'depot_legimi_publish' book.pk %}">
+ {% csrf_token %}
+ <button class="btn btn-primary" type="submit">Opublikuj na Legimi<br><small>w kategorii: {{ doc.book_info.legimi|default_if_none:doc.book_info.epoch }}</small></button>
+ {% with llp=book.last_legimi_publish %}
+ {% if llp %}
+ {{ llp.created_at }} →
+ {{ llp.started_at }} →
+ {{ llp.finished_at }}
+ ({{ llp.get_status_display }})
+ <!-- {{ llp.id }} -->
+ {% endif %}
+ {% endwith %}
+ </form>
+ {% endif %}
+
{% else %}
<a href="{% url 'cas_ng_login' %}">{% trans "Log in to publish." %}</a>
{% endif %}
<ul><li>{{ publishable_error }}</li></ul>
{% endif %}
-</div>
+
+
+ </div>
</div>
</div>
</div>
+
{% if doc %}
<div class="card mt-4">
<div class="card-header">
</tr>
</thead>
<tbody>
- {% with stats=book.wldocument.get_statistics %}
+ {% with stats=doc.get_statistics %}
{% include 'documents/book_stats.html' with book=book stats=stats depth=0 %}
{% endwith %}
</tbody>
url(r'^editor/', include('wiki.urls')),
url(r'^images/', include('wiki_img.urls')),
url(r'^cover/', include('cover.urls')),
+ url(r'^depot/', include('depot.urls')),
url(r'^wlxml/', include('wlxml.urls')),
path('api/', include('redakcja.api.urls')),