Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 63 additions & 14 deletions admin.py
Original file line number Diff line number Diff line change
@@ -1,35 +1,84 @@
from django.contrib import admin

from plugins.books.models import *
import plugins.books.models as models


@admin.register(models.BookSetting)
class BookSettingAdmin(admin.ModelAdmin):
list_display = ('book_page_title',)


@admin.register(models.Chapter)
class ChapterAdmin(admin.ModelAdmin):
"""Displays objects in the Django admin interface."""
list_display = ('title', 'number', 'book', 'pages', 'doi')
list_filter = ('book',)
search_fields = ('title',)
search_fields = ('title', 'book__title', 'doi')
raw_id_fields = ('book',)
filter_horizontal = ('contributors',)


@admin.register(models.BookAccess)
class BookAccessAdmin(admin.ModelAdmin):
list_display = ('book', 'chapter', 'type', 'format', 'country', 'accessed')
list_filter = ('book', 'type', 'format', 'country')
search_fields = ('book__title', 'chapter__title')


@admin.register(models.Book)
class BookAdmin(admin.ModelAdmin):
list_display = ('title', 'publisher_name', 'date_published', 'is_open_access')
list_filter = ('is_open_access', 'peer_reviewed', 'date_published', 'category')
search_fields = ('title', 'subtitle', 'publisher_name', 'isbn', 'doi')
raw_id_fields = ('category',)
filter_horizontal = ('keywords', 'publisher_notes', 'linked_repository_objects')


@admin.register(models.Contributor)
class ContributorAdmin(admin.ModelAdmin):
list_display = ('last_name', 'first_name', 'book', 'affiliation', 'sequence')
list_filter = ('book',)
search_fields = ('first_name', 'last_name', 'affiliation', 'email')
raw_id_fields = ('book',)


@admin.register(models.Format)
class FormatAdmin(admin.ModelAdmin):
list_display = ('title', 'book', 'sequence')
list_filter = ('book',)
search_fields = ('title', 'filename')
raw_id_fields = ('book',)


@admin.register(models.Category)
class CategoryAdmin(admin.ModelAdmin):
list_display = ('name', 'slug', 'display_title')
search_fields = ('name', 'slug')


@admin.register(models.BookPreprint)
class BookPreprintAdmin(admin.ModelAdmin):
list_display = ('book', 'preprint', 'order')
list_filter = ('book',)
search_fields = ('book__title',)
raw_id_fields = ('book', 'preprint')


@admin.register(models.KeywordBook)
class KeywordBookAdmin(admin.ModelAdmin):
list_display = ('keyword', 'book', 'order')
list_filter = ('book',)
search_fields = ('keyword__word',)
raw_id_fields = ('keyword', 'book')


@admin.register(models.KeywordChapter)
class KeywordChapterAdmin(admin.ModelAdmin):
list_display = ('keyword', 'chapter', 'order')
list_filter = ('chapter',)
search_fields = ('keyword__word',)
raw_id_fields = ('keyword', 'chapter')

admin_list = [
(Book, ),
(Contributor,),
(Format,),
(BookAccess, BookAccessAdmin),
(Chapter, ChapterAdmin),
(Category,),
(BookSetting, BookSettingAdmin)
]

[admin.site.register(*t) for t in admin_list]
@admin.register(models.PublisherNote)
class PublisherNoteAdmin(admin.ModelAdmin):
list_display = ('note',)
search_fields = ('note',)
28 changes: 25 additions & 3 deletions forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from django_summernote.widgets import SummernoteWidget

from plugins.books import models, files
from repository import models as repository_models


class DateInput(forms.DateInput):
Expand Down Expand Up @@ -44,7 +45,7 @@ class BookForm(forms.ModelForm):

class Meta:
model = models.Book
exclude = ('keywords', 'publisher_notes')
exclude = ('keywords', 'publisher_notes', 'linked_repository_objects')
widgets = {
'description': SummernoteWidget(),
'date_published': DateInput(),
Expand All @@ -68,15 +69,22 @@ class FormatForm(forms.ModelForm):

file = forms.FileField()

def __init__(self, *args, **kwargs):
super(FormatForm, self).__init__(*args, **kwargs)
if self.instance and self.instance.pk and self.instance.filename:
self.fields['file'].required = False

class Meta:
model = models.Format
exclude = ('book', 'filename')

def save(self, commit=True, *args, **kwargs):
save_format = super(FormatForm, self).save(commit=False)
file = self.cleaned_data["file"]
filename = files.save_file_to_disk(file, save_format)
save_format.filename = filename

if file:
filename = files.save_file_to_disk(file, save_format)
save_format.filename = filename

if commit:
save_format.save()
Expand Down Expand Up @@ -165,3 +173,17 @@ def save(self, commit=True):
save_category.save()

return save_category


class PreprintSelectionForm(forms.Form):
preprint_id = forms.ModelChoiceField(
queryset=repository_models.Preprint.objects.none(),
label="Select a Preprint",
required=True,
)

def __init__(self, *args, **kwargs):
available_preprints = kwargs.pop('available_preprints', None)
super().__init__(*args, **kwargs)
if available_preprints is not None:
self.fields['preprint_id'].queryset = available_preprints
26 changes: 25 additions & 1 deletion hooks.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,35 @@
from django.core.urlresolvers import reverse
from django.urls import reverse
from django.template.loader import render_to_string
from django.utils.safestring import mark_safe

from utils.function_cache import cache



@cache(600)
def nav_hook(context):
return '<li><a href="{url}"><i class="fa fa-book"></i> Books</a></li>'.format(
url=reverse('books_admin')
)


def linked_books(context):
request = context.get("request")
preprint = context.get("preprint")

if not preprint or not hasattr(preprint, "get_linked_books"):
return ""

theme = getattr(preprint.repository, "theme", "OLH")
template_path = f"books/{theme}/repository_linked_books.html"

books = preprint.get_linked_books()

return mark_safe(render_to_string(
template_path,
{
"preprint": preprint,
"linked_books": books,
},
request=request,
))
Empty file added management/__init__.py
Empty file.
Empty file added management/commands/__init__.py
Empty file.
145 changes: 145 additions & 0 deletions management/commands/generate_random_books.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
import random
import string
import os
from django.core.management.base import BaseCommand
from django.utils import timezone
from django.conf import settings
from faker import Faker
import svgwrite

from plugins.books import models as book_models

fake = Faker()

# Define the SVG cover creation path
COVERS_DIR = os.path.join(settings.MEDIA_ROOT, 'cover_images')


class Command(BaseCommand):
help = 'Generate a specified number of random Book instances with contributors and chapters.'

def add_arguments(self, parser):
parser.add_argument(
'num_books',
type=int,
help='The number of books to generate.',
)

def handle(self, *args, **kwargs):
num_books = kwargs['num_books']
categories = book_models.Category.objects.all()
if not categories:
self.stdout.write(self.style.ERROR(
"No categories available. Please add categories first."))
return

# Ensure the cover images directory exists
os.makedirs(COVERS_DIR, exist_ok=True)

books_created = []
for _ in range(num_books):
category = random.choice(categories)
title = fake.sentence(nb_words=3).title()
subtitle = fake.sentence(nb_words=5).title() if random.choice(
[True, False]) else None
publisher_name = fake.company()
publisher_loc = fake.city()

# Generate SVG cover
cover_filename = f"{title.replace(' ', '_')}_{random.randint(1000, 9999)}.svg"
cover_path = os.path.join(COVERS_DIR, cover_filename)
self.create_svg_cover(title, cover_path)

book = book_models.Book.objects.create(
title=title,
subtitle=subtitle,
category=category,
description=fake.text(max_nb_chars=200),
pages=random.randint(100, 500),
is_edited_volume=random.choice([True, False]),
is_open_access=random.choice([True, False]),
date_published=fake.date_this_century(),
publisher_name=publisher_name,
publisher_loc=publisher_loc,
doi=f'10.{random.randint(1000, 9999)}/{random.randint(1000000, 9999999)}',
isbn=''.join(random.choices(string.digits, k=13)),
purchase_url=fake.url(),
license_information=fake.sentence(nb_words=10),
cover=f'cover_images/{cover_filename}',
)

# Add random contributors
num_contributors = random.randint(2, 10)
self.create_contributors(book, num_contributors)

# Add random chapters
num_chapters = random.randint(5, 15)
self.create_chapters(book, num_chapters)

books_created.append(book)

self.stdout.write(
self.style.SUCCESS(
f'Successfully created {len(books_created)} books with contributors and chapters.')
)

def create_svg_cover(self, title, filepath):
# Create an SVG drawing with a black background and the title in white
svg = svgwrite.Drawing(filepath, size=("200px", "300px"))
svg.add(svg.rect(insert=(0, 0), size=("100%", "100%"), fill="black"))

# Add title text to the SVG, centered
svg.add(
svg.text(
title,
insert=("50%", "50%"),
text_anchor="middle",
alignment_baseline="middle",
fill="white",
font_size="20px",
font_family="Arial",
)
)
svg.save()

def create_contributors(self, book, num_contributors):
for sequence in range(1, num_contributors + 1):
first_name = fake.first_name()
last_name = fake.last_name()
middle_name = fake.first_name() if random.choice(
[True, False]) else None

book_models.Contributor.objects.create(
book=book,
first_name=first_name,
middle_name=middle_name,
last_name=last_name,
affiliation=fake.company(),
email=fake.email(),
sequence=sequence,
)

def create_chapters(self, book, num_chapters):
for sequence in range(1, num_chapters + 1):
title = fake.sentence(nb_words=5).title()
description = fake.text(max_nb_chars=200)
doi = f'10.{random.randint(1000, 9999)}/{random.randint(100000, 999999)}'
pages = random.randint(5, 20)

chapter = book_models.Chapter.objects.create(
book=book,
title=title,
description=description,
pages=pages,
doi=doi,
number=str(sequence),
date_published=fake.date_this_century(),
sequence=sequence,
filename=f"{title.replace(' ', '_')}.pdf",
)

# Add contributors to each chapter
num_contributors = random.randint(1, 3)
chapter_contributors = book_models.Contributor.objects.filter(
book=book).order_by('?')[:num_contributors]
chapter.contributors.add(*chapter_contributors)
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# Generated by Django 4.2.15 on 2024-11-06 14:56

from django.db import migrations, models
import django.db.models.deletion


class Migration(migrations.Migration):

dependencies = [
('core', '0099_alter_accountrole_options'),
('repository', '0045_historicalrepository_display_public_metrics_and_more'),
('books', '0020_auto_20220823_0931'),
]

operations = [
migrations.AlterField(
model_name='bookaccess',
name='chapter',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='books.chapter'),
),
migrations.AlterField(
model_name='bookaccess',
name='country',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='core.country'),
),
migrations.AlterField(
model_name='bookaccess',
name='format',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='books.format'),
),
migrations.CreateModel(
name='BookPreprint',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('order', models.IntegerField(default=0)),
('book', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='books.book')),
('preprint', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='repository.preprint')),
],
options={
'ordering': ['order'],
},
),
migrations.AddField(
model_name='book',
name='linked_repository_objects',
field=models.ManyToManyField(blank=True, help_text='Repository objects linked to this book.', through='books.BookPreprint', to='repository.preprint'),
),
]
Loading