@login_required
def woblink_autocomplete(request, category):
- shop = depot.models.Shop.objects.filter(shop='woblink').first()
- if shop is None:
+ site = depot.models.Site.objects.filter(site_type='woblink').first()
+ if site is None:
return JsonResponse({})
- woblink = shop.get_publisher()
+ woblink = site.get_publisher()
term = request.GET.get('term')
if not term:
return JsonResponse({})
extra = 0
-@admin.register(models.Shop)
-class ShopAdmin(admin.ModelAdmin):
+@admin.register(models.Site)
+class SiteAdmin(admin.ModelAdmin):
inlines = [
MediaInsertTextInline,
PriceLevelInline,
]
-@admin.register(models.ShopBookPublish)
-class ShopBookPublishAdmin(admin.ModelAdmin):
- list_display = ['created_at', 'book', 'user', 'shop', 'status', 'started_at', 'finished_at']
- list_filter = ['status', 'shop']
+@admin.register(models.SiteBookPublish)
+class SiteBookPublishAdmin(admin.ModelAdmin):
+ list_display = ['created_at', 'site_book', 'user', 'status', 'started_at', 'finished_at']
+ list_filter = ['status', 'site_book__site']
search_fields = ['book', 'user']
date_hierarchy = 'started_at'
+ raw_id_fields = ['site_book']
from django.core.management.base import BaseCommand
-from depot.models import ShopBookPublish
+from depot.models import SiteBookPublish
class Command(BaseCommand):
def handle(self, **options):
- for p in ShopBookPublish.objects.filter(status=0).order_by('created_at'):
- print(p.id, p.shop, p.book.slug, p.created_at)
+ for p in SiteBookPublish.objects.filter(status=0).order_by('created_at'):
+ print(p.id, p.site_book, p.created_at)
p.publish()
--- /dev/null
+# Generated by Django 4.1.9 on 2023-09-05 14:03
+
+from django.conf import settings
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ migrations.swappable_dependency(settings.AUTH_USER_MODEL),
+ ("documents", "0011_book_woblink_id"),
+ ("depot", "0006_shop_description_add"),
+ ]
+
+ operations = [
+ migrations.RenameModel(
+ old_name="ShopBookPublish",
+ new_name="SiteBookPublish",
+ ),
+ migrations.RenameModel(
+ old_name="ShopChunkPublish",
+ new_name="SiteChunkPublish",
+ ),
+ migrations.RenameField(
+ model_name="mediainserttext",
+ old_name="shop",
+ new_name="site",
+ ),
+ migrations.RenameField(
+ model_name="pricelevel",
+ old_name="shop",
+ new_name="site",
+ ),
+ migrations.RenameField(
+ model_name="shop",
+ old_name="shop",
+ new_name="site_type",
+ ),
+ migrations.RenameField(
+ model_name="sitebookpublish",
+ old_name="shop",
+ new_name="site",
+ ),
+ ]
--- /dev/null
+# Generated by Django 4.1.9 on 2023-09-05 14:04
+
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ("depot", "0007_rename_shopbookpublish_sitebookpublish_and_more"),
+ ]
+
+ operations = [
+ migrations.RenameModel(
+ old_name="Shop",
+ new_name="Site",
+ ),
+ ]
--- /dev/null
+# Generated by Django 4.1.9 on 2023-09-05 14:13
+
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ("documents", "0011_book_woblink_id"),
+ ("depot", "0008_rename_shop_site"),
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name="SiteBook",
+ fields=[
+ (
+ "id",
+ models.AutoField(
+ auto_created=True,
+ primary_key=True,
+ serialize=False,
+ verbose_name="ID",
+ ),
+ ),
+ ("external_id", models.CharField(blank=True, max_length=255)),
+ ("created_at", models.DateTimeField(auto_now_add=True)),
+ (
+ "book",
+ models.ForeignKey(
+ on_delete=django.db.models.deletion.CASCADE, to="documents.book"
+ ),
+ ),
+ (
+ "site",
+ models.ForeignKey(
+ null=True,
+ on_delete=django.db.models.deletion.SET_NULL,
+ to="depot.site",
+ ),
+ ),
+ ],
+ options={
+ "unique_together": {("book", "site")},
+ },
+ ),
+ migrations.AddField(
+ model_name="sitebookpublish",
+ name="site_book",
+ field=models.ForeignKey(
+ blank=True,
+ null=True,
+ on_delete=django.db.models.deletion.PROTECT,
+ to="depot.sitebook",
+ ),
+ ),
+ ]
--- /dev/null
+# Generated by Django 4.1.9 on 2023-09-05 14:14
+
+from django.db import migrations
+
+
+def migrate_external_ids(apps, schema_editor):
+ Book = apps.get_model('documents', 'Book')
+ Site = apps.get_model('depot', 'Site')
+ SiteBook = apps.get_model('depot', 'SiteBook')
+ SiteBookPublish = apps.get_model('depot', 'SiteBookPublish')
+
+ site_types = ('legimi', 'woblink')
+ for site_type in site_types:
+ site = Site.objects.filter(site_type=site_type).first()
+ if site is None:
+ continue
+ for book in Book.objects.exclude(**{f'{site_type}_id': ''}):
+ SiteBook.objects.get_or_create(
+ site=site, book=book,
+ external_id=getattr(book, f'{site_type}_id')
+ )
+
+ for p in SiteBookPublish.objects.all():
+ p.site_book, created = SiteBook.objects.get_or_create(
+ site=p.site,
+ book=p.book
+ )
+ p.save(update_fields=['site_book'])
+
+
+
+def remigrate_external_ids(apps, schema_editor):
+ Book = apps.get_model('documents', 'Book')
+ Site = apps.get_model('depot', 'Site')
+ SiteBook = apps.get_model('depot', 'SiteBook')
+ SiteBookPublish = apps.get_model('depot', 'SiteBookPublish')
+
+ for p in SiteBookPublish.objects.exclude(site_book=None):
+ p.site = p.site_book.site
+ p.book = p.site_book.book
+ p.save(update_fields=['site', 'book'])
+
+ site_types = ('legimi', 'woblink')
+ for site_type in site_types:
+ for site_book in SiteBook.objects.exclude(external_id=None):
+ book = site_book.book
+ setattr(book, f'{site_type}_id', site_book.external_id)
+ book.save(update_fields=[f'{site_type}_id'])
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ("depot", "0009_sitebook_sitebookpublish_site_book"),
+ ]
+
+ operations = [
+ migrations.RunPython(
+ migrate_external_ids,
+ remigrate_external_ids,
+ )
+ ]
--- /dev/null
+# Generated by Django 4.1.9 on 2023-09-05 14:50
+
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ("depot", "0010_migrate_external_ids"),
+ ]
+
+ operations = [
+ migrations.RemoveField(
+ model_name="sitebookpublish",
+ name="book",
+ ),
+ migrations.RemoveField(
+ model_name="sitebookpublish",
+ name="site",
+ ),
+ ]
)
-class ShopBookPublish(models.Model):
+class SiteBook(models.Model):
+ site = models.ForeignKey('Site', models.SET_NULL, null=True)
book = models.ForeignKey('documents.Book', models.CASCADE)
+ external_id = models.CharField(max_length=255, blank=True)
+ created_at = models.DateTimeField(auto_now_add=True)
+
+ class Meta:
+ unique_together = (('book', 'site'),)
+
+ def __str__(self):
+ return f'{self.site} : {self.book} : {self.external_id}'
+
+
+class SiteBookPublish(models.Model):
+ site_book = models.ForeignKey(SiteBook, models.PROTECT, null=True, blank=True)
user = models.ForeignKey(settings.AUTH_USER_MODEL, models.SET_NULL, null=True)
- shop = models.ForeignKey('Shop', 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)
error = models.TextField(blank=True)
@classmethod
- def create_for(cls, book, user, shop):
+ def create_for(cls, book, user, site):
book.assert_publishable()
changes = book.get_current_changes(publishable=True)
- me = cls.objects.create(book=book, user=user, shop=shop, created_at=now())
+ site_book, created = SiteBook.objects.get_or_create(
+ site=site, book=book
+ )
+ me = cls.objects.create(
+ site_book=site_book, user=user, created_at=now())
for change in changes:
- me.shopchunkpublish_set.create(change=change)
+ me.sitechunkpublish_set.create(change=change)
return me
def publish(self):
try:
changes = [
p.change for p in
- self.shopchunkpublish_set.order_by('change__chunk__number')
+ self.sitechunkpublish_set.order_by('change__chunk__number')
]
- self.shop.publish(self.book, changes=changes)
+ self.site.publish(self, changes=changes)
except Exception:
self.status = 110
self.save(update_fields=['status', 'finished_at', 'error'])
-class ShopChunkPublish(models.Model):
- book_publish = models.ForeignKey(ShopBookPublish, models.CASCADE)
+class SiteChunkPublish(models.Model):
+ book_publish = models.ForeignKey(SiteBookPublish, models.CASCADE)
change = models.ForeignKey('documents.ChunkChange', models.CASCADE)
-class Shop(models.Model):
+class Site(models.Model):
name = models.CharField(max_length=255)
- shop = models.CharField(max_length=32, choices=[
+ site_type = models.CharField(max_length=32, choices=[
('legimi', 'Legimi'),
('woblink', 'Woblink'),
])
description_add = models.TextField(blank=True)
def __str__(self):
- return self.shop
+ return self.name
def get_texts(self):
return [t.text for t in self.mediainserttext_set.all()]
return price_obj.price
def get_publisher(self):
- if self.shop == 'legimi':
+ if self.site_type == 'legimi':
pub_class = Legimi
- elif self.shop == 'woblink':
+ elif self.site_type == 'woblink':
pub_class = Woblink
return pub_class(self.username, self.password, self.publisher_handle)
- def publish(self, book, changes):
+ def publish(self, site_book_publish, changes):
self.get_publisher().send_book(
- self, book, changes=changes,
+ site_book_publish,
+ changes=changes,
)
def can_publish(self, book):
return self.get_publisher().can_publish(self, book)
def get_last(self, book):
- return self.shopbookpublish_set.filter(book=book).order_by('-created_at').first()
+ return SiteBookPublish.objects.filter(
+ site_book__site=self, site_book__book=book
+ ).order_by('-created_at').first()
+ def get_external_id_for_book(self, book):
+ site_book = self.sitebook_set.filter(book=book).first()
+ return (site_book and site_book.external_id) or ''
class PriceLevel(models.Model):
- shop = models.ForeignKey(Shop, models.CASCADE)
+ site = models.ForeignKey(Site, models.CASCADE)
min_pages = models.IntegerField(null=True, blank=True)
min_words = models.IntegerField(null=True, blank=True)
price = models.IntegerField()
class MediaInsertText(models.Model):
- shop = models.ForeignKey(Shop, models.CASCADE)
+ site = models.ForeignKey(Site, models.CASCADE)
ordering = models.IntegerField()
text = models.TextField()
self.login()
return self._session
- def send_book(self, shop, book, changes=None):
+ def send_book(self, site_book_publish, changes=None):
raise NotImplementedError()
def get_description(self, wlbook, description_add=''):
'Password': self.password,
})
- def can_publish(self, shop, book):
+ def can_publish(self, site, book):
meta = book.wldocument(librarian2=True).meta
d = {
'errors': [],
)
return thema
- def send_book(self, shop, book, changes=None):
+ def send_book(self, site_book_publish, changes=None):
+ site_book = site_book_publish.site_book
+ site = site_book.site
+ book = site_book.book
wlbook = book.wldocument(librarian2=True, changes=changes)
meta = wlbook.meta
cover = LabelMarquiseCover(meta, width=1200).output_file()
- texts = shop.get_texts()
+ texts = site.get_texts()
epub_file = EpubBuilder(
cover=MarquiseCover,
fundraising=texts,
'Isbn': '',
'LanguageLocale': lang_code_3to2(meta.language),
- 'Description': self.get_description(wlbook, shop.description_add),
+ 'Description': self.get_description(wlbook, site.description_add),
}
if meta.isbn_html:
isbn = meta.isbn_html
'BookMobi.Name': mobi_data['name'],
})
- if book.legimi_id:
+ if site_book.external_id:
self.edit(
- book.legimi_id,
+ site_book.external_id,
book_data
)
self.edit_files(
- book.legimi_id,
+ site_book.external_id,
files_data
)
else:
legimi_id = self.create_book(book_data, files_data)
if legimi_id:
- book.legimi_id = legimi_id
- book.save(update_fields=['legimi_id'])
+ site_book.external_id = legimi_id
+ site_book.save(update_fields=['external_id'])
self.edit_sale(book)
class NoPrice(WoblinkError):
def as_html(self):
return format_html(
- 'Brak <a href="/admin/depot/shop/{price}">określonej ceny</a>.',
- price=self.args[0].id
+ 'Brak <a href="/admin/depot/site/{site}">określonej ceny</a>.',
+ site=self.args[0].id
)
class NoIsbn(WoblinkError):
def get_lang2code(self, meta, errors=None):
return lang_code_3to2(meta.language)
- def get_price(self, shop, wldoc, errors=None):
+ def get_price(self, site, wldoc, errors=None):
try:
stats = wldoc.get_statistics()['total']
except:
if errors:
- errors.append(NoPrice(shop))
+ errors.append(NoPrice(site))
return 0
words = stats['words_with_fn']
pages = stats['chars_with_fn'] / 1800
- price = shop.get_price(words, pages)
+ price = site.get_price(words, pages)
if price is None:
if errors:
- errors.append(NoPrice(shop))
+ errors.append(NoPrice(site))
return 0
return price
- def can_publish(self, shop, book):
+ def can_publish(self, site, book):
wldoc = book.wldocument(librarian2=True)
d = {
'warnings': [],
'info': [],
}
errors = []
- book_data = self.get_book_data(shop, wldoc, errors)
+ book_data = self.get_book_data(site, wldoc, errors)
for error in errors:
if not isinstance(error, Warning):
errlist = d['errors']
if m is not None:
return m.group(1)
- def send_book(self, shop, book, changes=None):
+ def send_book(self, site_book_publish, changes=None):
+ site_book = site_book_publish.site_book
+ book = site_book.book
+ site = site_book.site
wldoc = book.wldocument(librarian2=True, changes=changes, publishable=False) # TODO pub
meta = wldoc.meta
- book_data = self.get_book_data(shop, wldoc)
+ book_data = self.get_book_data(site, wldoc)
- if not book.woblink_id:
- #book.woblink_id = 2959868
+ if not site_book.external_id:
woblink_id = self.create_book(book_data['isbn'])
assert woblink_id
- book.woblink_id = woblink_id
- book.save(update_fields=['woblink_id'])
+ site_book.external_id = woblink_id
+ site_book.save(update_fields=['external_id'])
+ woblink_id = site_book.external_id
- self.edit_step1(book.woblink_id, book_data)
- self.edit_step2(book.woblink_id, book_data)
- self.edit_step3(book.woblink_id, book_data)
- cover_id = self.send_cover(book.woblink_id, wldoc)
+ self.edit_step1(woblink_id, book_data)
+ self.edit_step2(woblink_id, book_data)
+ self.edit_step3(woblink_id, book_data)
+ cover_id = self.send_cover(woblink_id, wldoc)
- texts = shop.get_texts()
+ texts = site.get_texts()
epub_id, epub_demo = self.send_epub(
- book.woblink_id, wldoc, book.gallery_path(),
+ woblink_id, wldoc, book.gallery_path(),
fundraising=texts
)
mobi_id, mobi_demo = self.send_mobi(
- book.woblink_id, wldoc, book.gallery_path(),
+ woblink_id, wldoc, book.gallery_path(),
fundraising=texts
)
self.edit_step4(
- book.woblink_id, book_data,
+ woblink_id, book_data,
cover_id, epub_id, epub_demo, mobi_id, mobi_demo,
)
- self.edit_step5(book.woblink_id, book_data)
+ self.edit_step5(woblink_id, book_data)
- def get_book_data(self, shop, wldoc, errors=None):
+ def get_book_data(self, site, wldoc, errors=None):
return {
"title": wldoc.meta.title,
"isbn": self.get_isbn(wldoc.meta, errors=errors),
"authors": self.get_authors_data(wldoc.meta, errors=errors),
"abstract": self.get_abstract(
- wldoc, errors=errors, description_add=shop.description_add
+ wldoc, errors=errors, description_add=site.description_add
),
"lang2code": self.get_lang2code(wldoc.meta, errors=errors),
"genres": self.get_genres(wldoc.meta, errors=errors),
- "price": self.get_price(shop, wldoc, errors=errors),
+ "price": self.get_price(site, wldoc, errors=errors),
"series": self.get_series(wldoc.meta, errors=errors),
}
from django.template import Library
-from depot.models import Shop
+from depot.models import Site
register = Library()
@register.simple_tag(takes_context=True)
-def depot_shops(context, book):
- shops = []
- for shop in Shop.objects.all():
+def depot_sites(context, book):
+ sites = []
+ for site in Site.objects.all():
d = {
- 'shop_id': shop.id,
- 'name': shop.name,
+ 'site_id': site.id,
+ 'name': site.name,
}
- d.update(shop.can_publish(book))
- d['last'] = shop.get_last(book)
- d['id'] = getattr(book, shop.shop + '_id')
- shops.append(d)
- return shops
+ d.update(site.can_publish(book))
+ d['last'] = site.get_last(book)
+ d['id'] = site.get_external_id_for_book(book)
+ sites.append(d)
+ return sites
urlpatterns = [
- path('shop-publish/<int:shop_id>/<int:book_id>/',
- views.ShopPublishView.as_view(),
- name='depot_shop_publish'
+ path('site-publish/<int:site_id>/<int:book_id>/',
+ views.SitePublishView.as_view(),
+ name='depot_site_publish'
)
]
from . import models
-class ShopPublishView(PermissionRequiredMixin, View):
- permission_required = 'depot.add_shopbookpublish'
+class SitePublishView(PermissionRequiredMixin, View):
+ permission_required = 'depot.add_sitebookpublish'
- def post(self, request, shop_id, book_id):
- shop = get_object_or_404(models.Shop, pk=shop_id)
+ def post(self, request, site_id, book_id):
+ site = get_object_or_404(models.Site, pk=site_id)
book = get_object_or_404(Book, pk=book_id)
try:
- publish = models.ShopBookPublish.create_for(book, request.user, shop)
+ publish = models.SiteBookPublish.create_for(book, request.user, site)
except AssertionError:
pass
return redirect(book.get_absolute_url())
# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
#
from django.contrib import admin
+import depot.models
from . import models
+
+class SiteBookInline(admin.TabularInline):
+ model = depot.models.SiteBook
+ extra = 0
+
+
class BookAdmin(admin.ModelAdmin):
+ inlines = [SiteBookInline]
list_display = ['title', 'public', '_published', '_new_publishable', 'project']
list_filter = ['public', '_published', '_new_publishable', 'project']
prepopulated_fields = {'slug': ['title']}
class Meta:
model = Book
- exclude = ['project', 'cover', 'legimi_id', 'woblink_id']
+ exclude = ['project', 'cover']
def __init__(self, *args, **kwargs):
ret = super(BookForm, self).__init__(*args, **kwargs)
--- /dev/null
+# Generated by Django 4.1.9 on 2023-09-05 14:50
+
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ("documents", "0011_book_woblink_id"),
+ ]
+
+ operations = [
+ migrations.RemoveField(
+ model_name="book",
+ name="legimi_id",
+ ),
+ migrations.RemoveField(
+ model_name="book",
+ name="woblink_id",
+ ),
+ ]
related_name='document_books',
related_query_name='document_book',
)
- legimi_id = models.CharField(max_length=255, blank=True)
- woblink_id = models.CharField(max_length=255, blank=True)
class NoTextError(BaseException):
pass
</form>
- {% if perms.depot.add_shopbookpublish %}
- {% depot_shops book as shops %}
- {% for shop in shops %}
+ {% if perms.depot.add_sitebookpublish %}
+ {% depot_sites book as sites %}
+ {% for site in sites %}
<hr>
- <h3 class="mb-3">{{ shop.name }}</h3>
- {% if not shop.errors %}
- <form method="post" action="{% url 'depot_shop_publish' shop.shop_id book.pk %}">
+ <h3 class="mb-3">{{ site.name }}</h3>
+ {% if not site.errors %}
+ <form method="post" action="{% url 'depot_site_publish' site.site_id book.pk %}">
{% csrf_token %}
<button class="btn btn-primary mb-3" type="submit">
- Opublikuj na {{ shop.name }}
+ Opublikuj na {{ site.name }}
</button>
</form>
- {% for info in shop.info %}
+ {% for info in site.info %}
<div class="alert alert-info">
{{ info }}
</div>
{% endfor %}
{% else %}
- {% for error in shop.errors %}
+ {% for error in site.errors %}
<div class="alert alert-danger">
{{ error }}
</div>
{% endfor %}
{% endif %}
- {% for warning in shop.warnings %}
+ {% for warning in site.warnings %}
<div class="alert alert-warning">
{{ warning }}
</div>
{% endfor %}
- {% if shop.id %}
- id:{{ shop.id }}
+ {% if site.id %}
+ id:{{ site.id }}
{% endif %}
- {% with last=shop.last %}
+ {% with last=site.last %}
{% if last %}
{{ last.created_at }} →
{{ last.started_at }} →
<span title="{{ last.error }}">
({{ last.get_status_display }})
</span>
- <!-- {{ shop.last.id }} -->
+ <!-- {{ site.last.id }} -->
{% endif %}
{% endwith %}
{% endfor %}