mirror of
https://github.com/bookwyrm-social/bookwyrm.git
synced 2024-11-26 03:21:05 +00:00
Covers
This commit is contained in:
parent
789b9a1dc0
commit
f3330ab6e7
9 changed files with 58 additions and 24 deletions
|
@ -1,4 +1,4 @@
|
||||||
# Generated by Django 3.0.2 on 2020-01-29 06:31
|
# Generated by Django 3.0.2 on 2020-01-29 07:36
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
import django.contrib.auth.models
|
import django.contrib.auth.models
|
||||||
|
@ -43,7 +43,7 @@ class Migration(migrations.Migration):
|
||||||
('local', models.BooleanField(default=True)),
|
('local', models.BooleanField(default=True)),
|
||||||
('localname', models.CharField(blank=True, max_length=255, null=True, unique=True)),
|
('localname', models.CharField(blank=True, max_length=255, null=True, unique=True)),
|
||||||
('name', models.CharField(blank=True, max_length=100, null=True)),
|
('name', models.CharField(blank=True, max_length=100, null=True)),
|
||||||
('avatar', models.ImageField(blank=True, null=True, upload_to='uploads/')),
|
('avatar', models.ImageField(blank=True, null=True, upload_to='avatars/')),
|
||||||
('created_date', models.DateTimeField(auto_now_add=True)),
|
('created_date', models.DateTimeField(auto_now_add=True)),
|
||||||
('updated_date', models.DateTimeField(auto_now=True)),
|
('updated_date', models.DateTimeField(auto_now=True)),
|
||||||
('followers', models.ManyToManyField(to=settings.AUTH_USER_MODEL)),
|
('followers', models.ManyToManyField(to=settings.AUTH_USER_MODEL)),
|
||||||
|
@ -89,6 +89,7 @@ class Migration(migrations.Migration):
|
||||||
('activitypub_id', models.CharField(max_length=255)),
|
('activitypub_id', models.CharField(max_length=255)),
|
||||||
('openlibrary_key', models.CharField(max_length=255, unique=True)),
|
('openlibrary_key', models.CharField(max_length=255, unique=True)),
|
||||||
('data', django.contrib.postgres.fields.jsonb.JSONField()),
|
('data', django.contrib.postgres.fields.jsonb.JSONField()),
|
||||||
|
('cover', models.ImageField(blank=True, null=True, upload_to='covers/')),
|
||||||
('added_date', models.DateTimeField(auto_now_add=True)),
|
('added_date', models.DateTimeField(auto_now_add=True)),
|
||||||
('updated_date', models.DateTimeField(auto_now=True)),
|
('updated_date', models.DateTimeField(auto_now=True)),
|
||||||
('added_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to=settings.AUTH_USER_MODEL)),
|
('added_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to=settings.AUTH_USER_MODEL)),
|
||||||
|
|
|
@ -30,7 +30,7 @@ class User(AbstractUser):
|
||||||
)
|
)
|
||||||
# name is your display name, which you can change at will
|
# name is your display name, which you can change at will
|
||||||
name = models.CharField(max_length=100, blank=True, null=True)
|
name = models.CharField(max_length=100, blank=True, null=True)
|
||||||
avatar = models.ImageField(upload_to='uploads/', blank=True, null=True)
|
avatar = models.ImageField(upload_to='avatars/', blank=True, null=True)
|
||||||
# TODO: a field for if non-local users are readers or others
|
# TODO: a field for if non-local users are readers or others
|
||||||
followers = models.ManyToManyField('self', symmetrical=False)
|
followers = models.ManyToManyField('self', symmetrical=False)
|
||||||
created_date = models.DateTimeField(auto_now_add=True)
|
created_date = models.DateTimeField(auto_now_add=True)
|
||||||
|
@ -205,6 +205,7 @@ class Book(models.Model):
|
||||||
data = JSONField()
|
data = JSONField()
|
||||||
works = models.ManyToManyField('Work')
|
works = models.ManyToManyField('Work')
|
||||||
authors = models.ManyToManyField('Author')
|
authors = models.ManyToManyField('Author')
|
||||||
|
cover = models.ImageField(upload_to='covers/', blank=True, null=True)
|
||||||
shelves = models.ManyToManyField(
|
shelves = models.ManyToManyField(
|
||||||
'Shelf',
|
'Shelf',
|
||||||
symmetrical=False,
|
symmetrical=False,
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
''' activitystream api and books '''
|
''' activitystream api and books '''
|
||||||
from django.core.exceptions import ObjectDoesNotExist
|
from django.core.exceptions import ObjectDoesNotExist
|
||||||
|
from django.core.files.base import ContentFile
|
||||||
import requests
|
import requests
|
||||||
|
|
||||||
from fedireads.models import Author, Book, Work
|
from fedireads.models import Author, Book, Work
|
||||||
from fedireads.settings import OL_URL
|
from fedireads.settings import OL_URL
|
||||||
|
|
||||||
|
|
||||||
def get_or_create_book(olkey, user=None, update=True):
|
def get_or_create_book(olkey, user=None, update=False):
|
||||||
''' add a book '''
|
''' add a book '''
|
||||||
# TODO: check if this is a valid open library key, and a book
|
# TODO: check if this is a valid open library key, and a book
|
||||||
olkey = olkey
|
olkey = olkey
|
||||||
|
@ -44,9 +45,23 @@ def get_or_create_book(olkey, user=None, update=True):
|
||||||
author_id = author_id['key']
|
author_id = author_id['key']
|
||||||
book.authors.add(get_or_create_author(author_id))
|
book.authors.add(get_or_create_author(author_id))
|
||||||
|
|
||||||
|
if len(data['covers']):
|
||||||
|
book.cover.save(*get_cover(data['covers'][0]), save=True)
|
||||||
|
|
||||||
return book
|
return book
|
||||||
|
|
||||||
|
|
||||||
|
def get_cover(cover_id):
|
||||||
|
''' ask openlibrary for the cover '''
|
||||||
|
image_name = '%s-M.jpg' % cover_id
|
||||||
|
url = 'https://covers.openlibrary.org/b/id/%s' % image_name
|
||||||
|
response = requests.get(url)
|
||||||
|
if not response.ok:
|
||||||
|
response.raise_for_status()
|
||||||
|
image_content = ContentFile(requests.get(url).content)
|
||||||
|
return [image_name, image_content]
|
||||||
|
|
||||||
|
|
||||||
def get_or_create_work(olkey):
|
def get_or_create_work(olkey):
|
||||||
''' load em up '''
|
''' load em up '''
|
||||||
# TODO: validate that this is a work key
|
# TODO: validate that this is a work key
|
||||||
|
|
|
@ -33,6 +33,10 @@ h2 {
|
||||||
#branding {
|
#branding {
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
}
|
}
|
||||||
|
#branding a {
|
||||||
|
text-decoration: none;
|
||||||
|
color: black;
|
||||||
|
}
|
||||||
#actions {
|
#actions {
|
||||||
flex-grow: 0;
|
flex-grow: 0;
|
||||||
text-align: right;
|
text-align: right;
|
||||||
|
@ -44,11 +48,6 @@ h2 {
|
||||||
padding: 0.5rem;
|
padding: 0.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
#top-bar a {
|
|
||||||
color: black;
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
#branding {
|
#branding {
|
||||||
font-size: 2em;
|
font-size: 2em;
|
||||||
}
|
}
|
||||||
|
@ -76,6 +75,11 @@ h2 {
|
||||||
margin-right: 0.5em;
|
margin-right: 0.5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.book-cover.small {
|
||||||
|
width: 50px;
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
|
||||||
#feed, #content {
|
#feed, #content {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
<div id="content">
|
<div id="content">
|
||||||
<div>
|
<div>
|
||||||
<div class="book-preview">
|
<div class="book-preview">
|
||||||
<img class="book-cover" src="/static/images/med.jpg">
|
<img class="book-cover" src="{% if book.cover %}/images/{{ book.cover }}{% else %}/static/images/no_cover.jpg{% endif %}">
|
||||||
<h1>{{ book.data.title }}</h1>
|
<h1>{{ book.data.title }}</h1>
|
||||||
by {{ book.authors.first.data.name }}
|
by {{ book.authors.first.data.name }}
|
||||||
{{ rating }} stars
|
{{ rating }} stars
|
||||||
|
|
|
@ -3,7 +3,6 @@
|
||||||
<div id="content">
|
<div id="content">
|
||||||
<div class="user-profile">
|
<div class="user-profile">
|
||||||
<h1>{% if user.localname %}{{ user.localname }}{% else %}{{ user.username }}{% endif %}</h1>
|
<h1>{% if user.localname %}{{ user.localname }}{% else %}{{ user.username }}{% endif %}</h1>
|
||||||
<img class="user-pic" src="/static/images/profile.jpg">
|
|
||||||
<form name="avatar" action="/edit_profile/" method="post" enctype="multipart/form-data">
|
<form name="avatar" action="/edit_profile/" method="post" enctype="multipart/form-data">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
{{ form.as_p }}
|
{{ form.as_p }}
|
||||||
|
|
|
@ -4,18 +4,24 @@
|
||||||
<div>
|
<div>
|
||||||
<h2>Currently Reading</h2>
|
<h2>Currently Reading</h2>
|
||||||
{# listing books currently on user's shelves #}
|
{# listing books currently on user's shelves #}
|
||||||
{% if not shelves.first.books.all %}
|
{% if not reading.books.all %}
|
||||||
<p>Start a book!</p>
|
<p>Start a book!</p>
|
||||||
{% endif %}
|
{% for book in to_read.books.all %}
|
||||||
{% for book in shelves.first.books.all %}
|
|
||||||
<div class="book-preview">
|
<div class="book-preview">
|
||||||
<img class="cover" src="static/images/small.jpg">
|
<img class="book-cover small" src="{% if book.cover %}/images/{{ book.cover }}{% else %}/static/images/no_cover.jpg{% endif %}">
|
||||||
|
<p class="title"><a href="{{ book.openlibrary_key }}">{{ book.data.title }}</a></p>
|
||||||
|
<p>by <a href="" class="author">{{ book.authors.first.data.name }}</a></p>
|
||||||
|
<button>start reading</button>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% for book in reading.books.all %}
|
||||||
|
<div class="book-preview">
|
||||||
|
<img class="book-cover small" src="{% if book.cover %}/images/{{ book.cover }}{% else %}/static/images/no_cover.jpg{% endif %}">
|
||||||
<p class="title"><a href="{{ book.openlibrary_key }}">{{ book.data.title }}</a></p>
|
<p class="title"><a href="{{ book.openlibrary_key }}">{{ book.data.title }}</a></p>
|
||||||
<p>by <a href="" class="author">{{ book.authors.first.data.name }}</a></p>
|
<p>by <a href="" class="author">{{ book.authors.first.data.name }}</a></p>
|
||||||
{% if shelf.type == 'reading' %}
|
|
||||||
{# TODO: re-shelve a book #}
|
|
||||||
<button>done reading</button>
|
<button>done reading</button>
|
||||||
{% endif %}
|
|
||||||
</div>
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
|
@ -24,7 +30,7 @@
|
||||||
<h2>Recently Added Books</h2>
|
<h2>Recently Added Books</h2>
|
||||||
{% for book in recent_books %}
|
{% for book in recent_books %}
|
||||||
<div class="book-preview">
|
<div class="book-preview">
|
||||||
<img class="cover" src="static/images/small.jpg">
|
<img class="book-cover small" src="{% if book.cover %}/images/{{ book.cover }}{% else %}/static/images/no_cover.jpg{% endif %}">
|
||||||
<p class="title">
|
<p class="title">
|
||||||
<a href="{{ book.openlibrary_key }}">{{ book.data.title }}</a>
|
<a href="{{ book.openlibrary_key }}">{{ book.data.title }}</a>
|
||||||
by
|
by
|
||||||
|
@ -65,7 +71,7 @@
|
||||||
</h2>
|
</h2>
|
||||||
{# TODO: wouldn't it rule if this was a reusable piece of markup? #}
|
{# TODO: wouldn't it rule if this was a reusable piece of markup? #}
|
||||||
<div class="book-preview">
|
<div class="book-preview">
|
||||||
<img class="cover" src="static/images/med.jpg">
|
<img class="book-cover" src="{% if activity.book.cover %}/images/{{ activity.book.cover }}{% else %}/static/images/no_cover.jpg{% endif %}">
|
||||||
<p class="title">
|
<p class="title">
|
||||||
<a href="{{ activity.book.openlibrary_key }}">{{ activity.book.data.title }}</a>
|
<a href="{{ activity.book.openlibrary_key }}">{{ activity.book.data.title }}</a>
|
||||||
by
|
by
|
||||||
|
@ -77,7 +83,7 @@
|
||||||
reviewed {{ activity.book.data.title }}
|
reviewed {{ activity.book.data.title }}
|
||||||
</h2>
|
</h2>
|
||||||
<div class="book-preview review">
|
<div class="book-preview review">
|
||||||
<img class="cover" src="static/images/med.jpg">
|
<img class="book-cover" src="{% if activity.book.cover %}/images/{{ activity.book.cover }}{% else %}/static/images/no_cover.jpg{% endif %}">
|
||||||
<p class="title">
|
<p class="title">
|
||||||
<a href="{{ activity.book.openlibrary_key }}">{{ activity.book.data.title }}</a>
|
<a href="{{ activity.book.openlibrary_key }}">{{ activity.book.data.title }}</a>
|
||||||
by
|
by
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
<div id="account">
|
<div id="account">
|
||||||
{% if user.is_authenticated %}
|
{% if user.is_authenticated %}
|
||||||
<form name="logout" action="/logout/" method="post">
|
<form name="logout" action="/logout/" method="post">
|
||||||
Welcome, <a href="{{ request.user.actor }}">{% if request.user.localname %}{{ request.user.localname }}{% else %}{{ request.user.username }}{% endif %}</a>
|
Welcome, <a href="/user/{{ request.user.localname }}">{{ request.user.localname }}</a>
|
||||||
<input type="submit" value="Log out"></input>
|
<input type="submit" value="Log out"></input>
|
||||||
</form>
|
</form>
|
||||||
{% else %}
|
{% else %}
|
||||||
|
|
|
@ -15,7 +15,14 @@ from fedireads.settings import DOMAIN
|
||||||
@login_required
|
@login_required
|
||||||
def home(request):
|
def home(request):
|
||||||
''' user's homepage with activity feed '''
|
''' user's homepage with activity feed '''
|
||||||
shelves = models.Shelf.objects.filter(user=request.user.id)
|
reading = models.Shelf.objects.get(
|
||||||
|
user=request.user,
|
||||||
|
shelf_type='reading'
|
||||||
|
)
|
||||||
|
to_read = models.Shelf.objects.get(
|
||||||
|
user=request.user,
|
||||||
|
shelf_type='to-read'
|
||||||
|
)
|
||||||
user_books = models.Book.objects.filter(shelves__user=request.user).all()
|
user_books = models.Book.objects.filter(shelves__user=request.user).all()
|
||||||
recent_books = models.Book.objects.order_by(
|
recent_books = models.Book.objects.order_by(
|
||||||
'added_date'
|
'added_date'
|
||||||
|
@ -35,7 +42,8 @@ def home(request):
|
||||||
login_form = forms.LoginForm()
|
login_form = forms.LoginForm()
|
||||||
data = {
|
data = {
|
||||||
'user': request.user,
|
'user': request.user,
|
||||||
'shelves': shelves,
|
'reading': reading,
|
||||||
|
'to_read': to_read,
|
||||||
'recent_books': recent_books,
|
'recent_books': recent_books,
|
||||||
'user_books': user_books,
|
'user_books': user_books,
|
||||||
'activities': activities,
|
'activities': activities,
|
||||||
|
|
Loading…
Reference in a new issue