mirror of
https://github.com/bookwyrm-social/bookwyrm.git
synced 2024-10-31 22:19:00 +00:00
Merge branch 'main' into production
This commit is contained in:
commit
a8052c2dd0
29 changed files with 724 additions and 521 deletions
2
.github/workflows/black.yml
vendored
2
.github/workflows/black.yml
vendored
|
@ -8,6 +8,6 @@ jobs:
|
|||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-python@v2
|
||||
- uses: psf/black@stable
|
||||
- uses: psf/black@20.8b1
|
||||
with:
|
||||
args: ". --check -l 80 -S"
|
||||
|
|
|
@ -26,15 +26,21 @@ class ActivityStream(ABC):
|
|||
""" the redis key for this user's unread count for this stream """
|
||||
return "{}-unread".format(self.stream_id(user))
|
||||
|
||||
def get_value(self, status): # pylint: disable=no-self-use
|
||||
""" the status id and the rank (ie, published date) """
|
||||
return {status.id: status.published_date.timestamp()}
|
||||
|
||||
def add_status(self, status):
|
||||
""" add a status to users' feeds """
|
||||
value = self.get_value(status)
|
||||
# we want to do this as a bulk operation, hence "pipeline"
|
||||
pipeline = r.pipeline()
|
||||
for user in self.stream_users(status):
|
||||
# add the status to the feed
|
||||
pipeline.lpush(self.stream_id(user), status.id)
|
||||
pipeline.ltrim(self.stream_id(user), 0, settings.MAX_STREAM_LENGTH)
|
||||
|
||||
pipeline.zadd(self.stream_id(user), value)
|
||||
pipeline.zremrangebyrank(
|
||||
self.stream_id(user), settings.MAX_STREAM_LENGTH, -1
|
||||
)
|
||||
# add to the unread status count
|
||||
pipeline.incr(self.unread_id(user))
|
||||
# and go!
|
||||
|
@ -44,14 +50,19 @@ class ActivityStream(ABC):
|
|||
""" remove a status from all feeds """
|
||||
pipeline = r.pipeline()
|
||||
for user in self.stream_users(status):
|
||||
pipeline.lrem(self.stream_id(user), -1, status.id)
|
||||
pipeline.zrem(self.stream_id(user), -1, status.id)
|
||||
pipeline.execute()
|
||||
|
||||
def add_user_statuses(self, viewer, user):
|
||||
""" add a user's statuses to another user's feed """
|
||||
pipeline = r.pipeline()
|
||||
for status in user.status_set.all()[: settings.MAX_STREAM_LENGTH]:
|
||||
pipeline.lpush(self.stream_id(viewer), status.id)
|
||||
statuses = user.status_set.all()[: settings.MAX_STREAM_LENGTH]
|
||||
for status in statuses:
|
||||
pipeline.zadd(self.stream_id(viewer), self.get_value(status))
|
||||
if statuses:
|
||||
pipeline.zremrangebyrank(
|
||||
self.stream_id(user), settings.MAX_STREAM_LENGTH, -1
|
||||
)
|
||||
pipeline.execute()
|
||||
|
||||
def remove_user_statuses(self, viewer, user):
|
||||
|
@ -66,7 +77,7 @@ class ActivityStream(ABC):
|
|||
# clear unreads for this feed
|
||||
r.set(self.unread_id(user), 0)
|
||||
|
||||
statuses = r.lrange(self.stream_id(user), 0, -1)
|
||||
statuses = r.zrevrange(self.stream_id(user), 0, -1)
|
||||
return (
|
||||
models.Status.objects.select_subclasses()
|
||||
.filter(id__in=statuses)
|
||||
|
@ -75,7 +86,7 @@ class ActivityStream(ABC):
|
|||
|
||||
def get_unread_count(self, user):
|
||||
""" get the unread status count for this user's feed """
|
||||
return int(r.get(self.unread_id(user)))
|
||||
return int(r.get(self.unread_id(user)) or 0)
|
||||
|
||||
def populate_stream(self, user):
|
||||
""" go from zero to a timeline """
|
||||
|
@ -84,7 +95,11 @@ class ActivityStream(ABC):
|
|||
|
||||
stream_id = self.stream_id(user)
|
||||
for status in statuses.all()[: settings.MAX_STREAM_LENGTH]:
|
||||
pipeline.lpush(stream_id, status.id)
|
||||
pipeline.zadd(stream_id, self.get_value(status))
|
||||
|
||||
# only trim the stream if statuses were added
|
||||
if statuses.exists():
|
||||
pipeline.zremrangebyrank(stream_id, settings.MAX_STREAM_LENGTH, -1)
|
||||
pipeline.execute()
|
||||
|
||||
def stream_users(self, status): # pylint: disable=no-self-use
|
||||
|
@ -274,7 +289,7 @@ def add_statuses_on_unblock(sender, instance, *args, **kwargs):
|
|||
|
||||
@receiver(signals.post_save, sender=models.User)
|
||||
# pylint: disable=unused-argument
|
||||
def populate_feed_on_account_create(sender, instance, created, *args, **kwargs):
|
||||
def populate_streams_on_account_create(sender, instance, created, *args, **kwargs):
|
||||
""" build a user's feeds when they join """
|
||||
if not created or not instance.local:
|
||||
return
|
||||
|
|
|
@ -6,7 +6,7 @@ from django import forms
|
|||
from django.forms import ModelForm, PasswordInput, widgets
|
||||
from django.forms.widgets import Textarea
|
||||
from django.utils import timezone
|
||||
from django.utils.translation import gettext as _
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from bookwyrm import models
|
||||
|
||||
|
|
|
@ -25,6 +25,16 @@ html {
|
|||
min-width: 75% !important;
|
||||
}
|
||||
|
||||
/* --- "disabled" for non-buttons --- */
|
||||
.is-disabled {
|
||||
background-color: #dbdbdb;
|
||||
border-color: #dbdbdb;
|
||||
box-shadow: none;
|
||||
color: #7a7a7a;
|
||||
opacity: 0.5;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
/* --- SHELVING --- */
|
||||
|
||||
/** @todo Replace icons with SVG symbols.
|
||||
|
@ -80,52 +90,34 @@ html {
|
|||
}
|
||||
}
|
||||
|
||||
/* --- STARS --- */
|
||||
.rate-stars button.icon {
|
||||
background: none;
|
||||
border: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
display: inline;
|
||||
/** Stars in a review form
|
||||
*
|
||||
* Specificity makes hovering taking over checked inputs.
|
||||
*
|
||||
* \e9d9: filled star
|
||||
* \e9d7: empty star;
|
||||
******************************************************************************/
|
||||
|
||||
.form-rate-stars {
|
||||
width: max-content;
|
||||
}
|
||||
|
||||
.rate-stars:hover .icon::before {
|
||||
/* All stars are visually filled by default. */
|
||||
.form-rate-stars .icon::before {
|
||||
content: '\e9d9';
|
||||
}
|
||||
|
||||
.rate-stars form:hover ~ form .icon::before {
|
||||
/* Icons directly following inputs that follow the checked input are emptied. */
|
||||
.form-rate-stars input:checked ~ input + .icon::before {
|
||||
content: '\e9d7';
|
||||
}
|
||||
|
||||
/** stars in a review form
|
||||
*
|
||||
* @todo Simplify the logic for those icons.
|
||||
*/
|
||||
.form-rate-stars input + .icon.icon::before {
|
||||
content: '\e9d9';
|
||||
}
|
||||
|
||||
/* When a label is hovered, repeat the fill-all-then-empty-following pattern. */
|
||||
.form-rate-stars:hover .icon.icon::before {
|
||||
content: '\e9d9';
|
||||
}
|
||||
|
||||
.form-rate-stars input:checked + .icon.icon::before {
|
||||
content: '\e9d9';
|
||||
}
|
||||
|
||||
.form-rate-stars input:checked + * ~ .icon.icon::before {
|
||||
content: '\e9d7';
|
||||
}
|
||||
|
||||
.form-rate-stars:hover label.icon.icon::before {
|
||||
content: '\e9d9';
|
||||
}
|
||||
|
||||
.form-rate-stars label.icon:hover::before {
|
||||
content: '\e9d9';
|
||||
}
|
||||
|
||||
.form-rate-stars label.icon:hover ~ label.icon.icon::before {
|
||||
.form-rate-stars .icon:hover ~ .icon::before {
|
||||
content: '\e9d7';
|
||||
}
|
||||
|
||||
|
|
|
@ -1,18 +1,10 @@
|
|||
""" Handle user activity """
|
||||
from django.db import transaction
|
||||
from django.utils import timezone
|
||||
|
||||
from bookwyrm import models
|
||||
from bookwyrm.sanitize_html import InputHtmlParser
|
||||
|
||||
|
||||
def delete_status(status):
|
||||
""" replace the status with a tombstone """
|
||||
status.deleted = True
|
||||
status.deleted_date = timezone.now()
|
||||
status.save()
|
||||
|
||||
|
||||
def create_generated_note(user, content, mention_books=None, privacy="public"):
|
||||
""" a note created by the app about user activity """
|
||||
# sanitize input html
|
||||
|
|
|
@ -122,12 +122,18 @@
|
|||
<p class="help is-danger">{{ error | escape }}</p>
|
||||
{% endfor %}
|
||||
|
||||
<p class="mb-2"><label class="label" for="id_first_published_date">{% trans "First published date:" %}</label> {{ form.first_published_date }} </p>
|
||||
<p class="mb-2">
|
||||
<label class="label" for="id_first_published_date">{% trans "First published date:" %}</label>
|
||||
<input type="date" name="first_published_date" class="input" id="id_first_published_date"{% if book.first_published_date %} value="{{ book.first_published_date|date:'Y-m-d' }}"{% endif %}>
|
||||
</p>
|
||||
{% for error in form.first_published_date.errors %}
|
||||
<p class="help is-danger">{{ error | escape }}</p>
|
||||
{% endfor %}
|
||||
|
||||
<p class="mb-2"><label class="label" for="id_published_date">{% trans "Published date:" %}</label> {{ form.published_date }} </p>
|
||||
<p class="mb-2">
|
||||
<label class="label" for="id_published_date">{% trans "Published date:" %}</label>
|
||||
<input type="date" name="published_date" class="input" id="id_published_date"{% if book.published_date %} value="{{ book.published_date|date:'Y-m-d' }}"{% endif %}>
|
||||
</p>
|
||||
{% for error in form.published_date.errors %}
|
||||
<p class="help is-danger">{{ error | escape }}</p>
|
||||
{% endfor %}
|
||||
|
|
34
bookwyrm/templates/compose.html
Normal file
34
bookwyrm/templates/compose.html
Normal file
|
@ -0,0 +1,34 @@
|
|||
{% extends 'layout.html' %}
|
||||
{% load i18n %}
|
||||
{% load bookwyrm_tags %}
|
||||
|
||||
{% block title %}{% trans "Compose status" %}{% endblock %}
|
||||
{% block content %}
|
||||
<header class="block content">
|
||||
<h1>{% trans "Compose status" %}</h1>
|
||||
</header>
|
||||
|
||||
{% with 0|uuid as uuid %}
|
||||
<div class="box columns">
|
||||
{% if book %}
|
||||
<div class="column is-one-third">
|
||||
<div class="block">
|
||||
<a href="{{ book.local_path }}">{% include 'snippets/book_cover.html' with book=book %}</a>
|
||||
</div>
|
||||
<h3 class="title is-6">{% include 'snippets/book_titleby.html' with book=book %}</h3>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="column is-two-thirds">
|
||||
{% if draft.reply_parent %}
|
||||
{% include 'snippets/status/status.html' with status=draft.reply_parent no_interact=True %}
|
||||
{% endif %}
|
||||
|
||||
{% if not draft %}
|
||||
{% include 'snippets/create_status.html' %}
|
||||
{% else %}
|
||||
{% include 'snippets/create_status_form.html' %}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endwith %}
|
||||
{% endblock %}
|
|
@ -12,6 +12,7 @@
|
|||
{% if not suggested_books %}
|
||||
<p>{% trans "There are no books here right now! Try searching for a book to get started" %}</p>
|
||||
{% else %}
|
||||
{% with active_book=request.GET.book %}
|
||||
<div class="tab-group">
|
||||
<div class="tabs is-small">
|
||||
<ul role="tablist">
|
||||
|
@ -28,8 +29,14 @@
|
|||
<div class="tabs is-small is-toggle">
|
||||
<ul>
|
||||
{% for book in shelf.books %}
|
||||
<li{% if shelf_counter == 1 and forloop.first %} class="is-active"{% endif %}>
|
||||
<a href="#book-{{ book.id }}" id="tab-book-{{ book.id }}" role="tab" aria-label="{{ book.title }}" aria-selected="{% if shelf_counter == 1 and forloop.first %}true{% else %}false{% endif %}" aria-controls="book-{{ book.id }}">
|
||||
<li class="{% if active_book == book.id|stringformat:'d' %}is-active{% elif not active_book and shelf_counter == 1 and forloop.first %}is-active{% endif %}">
|
||||
<a
|
||||
href="{{ request.path }}?book={{ book.id }}"
|
||||
id="tab-book-{{ book.id }}"
|
||||
role="tab"
|
||||
aria-label="{{ book.title }}"
|
||||
aria-selected="{% if active_book == book.id|stringformat:'d' %}true{% elif shelf_counter == 1 and forloop.first %}true{% else %}false{% endif %}"
|
||||
aria-controls="book-{{ book.id }}">
|
||||
{% include 'snippets/book_cover.html' with book=book size="medium" %}
|
||||
</a>
|
||||
</li>
|
||||
|
@ -45,7 +52,13 @@
|
|||
{% for shelf in suggested_books %}
|
||||
{% with shelf_counter=forloop.counter %}
|
||||
{% for book in shelf.books %}
|
||||
<div class="suggested-tabs card" role="tabpanel" id="book-{{ book.id }}"{% if shelf_counter != 1 or not forloop.first %} hidden{% endif %} aria-labelledby="tab-book-{{ book.id }}">
|
||||
<div
|
||||
class="suggested-tabs card"
|
||||
role="tabpanel"
|
||||
id="book-{{ book.id }}"
|
||||
{% if active_book and active_book == book.id|stringformat:'d' %}{% elif not active_book and shelf_counter == 1 and forloop.first %}{% else %} hidden{% endif %}
|
||||
aria-labelledby="tab-book-{{ book.id }}">
|
||||
|
||||
<div class="card-header">
|
||||
<div class="card-header-title">
|
||||
<div>
|
||||
|
@ -66,6 +79,7 @@
|
|||
{% endwith %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endwith %}
|
||||
{% endif %}
|
||||
|
||||
{% if goal %}
|
||||
|
|
|
@ -57,7 +57,7 @@
|
|||
{% for book in goal.books %}
|
||||
<div class="column is-one-fifth">
|
||||
<div class="is-clipped">
|
||||
<a href="{{ book.local_path }}">{% include 'snippets/book_cover.html' with book=book.book %}</a>
|
||||
<a href="{{ book.book.local_path }}">{% include 'snippets/book_cover.html' with book=book.book %}</a>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
|
|
|
@ -28,13 +28,17 @@
|
|||
|
||||
{% include 'settings/invite_request_filters.html' %}
|
||||
|
||||
<table class="table is-striped">
|
||||
<table class="table is-striped is-fullwidth">
|
||||
{% url 'settings-invite-requests' as url %}
|
||||
<tr>
|
||||
<th>
|
||||
{% trans "Date" as text %}
|
||||
{% trans "Date requested" as text %}
|
||||
{% include 'snippets/table-sort-header.html' with field="created_date" sort=sort text=text %}
|
||||
</th>
|
||||
<th>
|
||||
{% trans "Date accepted" as text %}
|
||||
{% include 'snippets/table-sort-header.html' with field="invite__invitees__created_date" sort=sort text=text %}
|
||||
</th>
|
||||
<th>{% trans "Email" %}</th>
|
||||
<th>
|
||||
{% trans "Status" as text %}
|
||||
|
@ -48,6 +52,7 @@
|
|||
{% for req in requests %}
|
||||
<tr>
|
||||
<td>{{ req.created_date | naturaltime }}</td>
|
||||
<td>{{ req.invite.invitees.first.created_date | naturaltime }}</td>
|
||||
<td>{{ req.email }}</td>
|
||||
<td>
|
||||
{% if req.invite.times_used %}
|
||||
|
@ -58,7 +63,7 @@
|
|||
{% trans "Requested" %}
|
||||
{% endif %}
|
||||
</td>
|
||||
<td class="field is-grouped">
|
||||
<td><div class="field is-grouped">
|
||||
{# no invite OR invite not yet used #}
|
||||
{% if not req.invite.times_used %}
|
||||
<form name="send-invite" method="post">
|
||||
|
@ -93,7 +98,7 @@
|
|||
{% endif %}
|
||||
</form>
|
||||
{% endif %}
|
||||
</td>
|
||||
</div></td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
|
|
|
@ -1,5 +1,12 @@
|
|||
{% load i18n %}
|
||||
<div class="control{% if not parent_status.content_warning %} hidden{% endif %}" id="spoilers-{{ uuid }}">
|
||||
<div class="control{% if not parent_status.content_warning and not draft.content_warning %} hidden{% endif %}" id="spoilers-{{ uuid }}">
|
||||
<label class="is-sr-only" for="id_content_warning-{{ uuid }}">{% trans "Spoiler alert:" %}</label>
|
||||
<input type="text" name="content_warning" maxlength="255" class="input" id="id_content_warning-{{ uuid }}" placeholder="{% trans 'Spoilers ahead!' %}"{% if parent_status.content_warning %} value="{{ parent_status.content_warning }}"{% endif %}>
|
||||
<input
|
||||
type="text"
|
||||
name="content_warning"
|
||||
maxlength="255"
|
||||
class="input"
|
||||
id="id_content_warning-{{ uuid }}"
|
||||
placeholder="{% trans 'Spoilers ahead!' %}"
|
||||
value="{% firstof draft.content_warning parent_status.content_warning '' %}">
|
||||
</div>
|
||||
|
|
|
@ -2,36 +2,62 @@
|
|||
{% load i18n %}
|
||||
{% load bookwyrm_tags %}
|
||||
|
||||
{% with status_type=request.GET.status_type %}
|
||||
<div class="tab-group">
|
||||
<div class="tabs is-boxed" role="tablist">
|
||||
<ul>
|
||||
<li class="is-active">
|
||||
<a href="#review-{{ book.id }}" id="tab-review-{{ book.id }}" role="tab" aria-selected="true" aria-controls="review-{{ book.id }}" data-category="tab-option-{{ book.id }}">{% trans "Review" %}</a>
|
||||
<li class="{% if status_type == 'review' or not status_type %}is-active{% endif %}">
|
||||
<a
|
||||
href="{{ request.path }}?status_type=review&book={{ book.id }}"
|
||||
id="tab-review-{{ book.id }}"
|
||||
role="tab"
|
||||
aria-selected="{% if status_type == 'review' or not status_type %}true{% else %}false{% endif %}"
|
||||
aria-controls="review-{{ book.id }}"
|
||||
data-category="tab-option-{{ book.id }}">
|
||||
{% trans "Review" %}
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#comment-{{ book.id}}" id="tab-comment-{{ book.id }}" role="tab" aria-selected="false" aria-controls="comment-{{ book.id}}" data-category="tab-option-{{ book.id }}">{% trans "Comment" %}</a>
|
||||
<li class="{% if status_type == 'comment' %}is-active{% endif %}">
|
||||
<a
|
||||
href="{{ request.path }}?status_type=comment&book={{ book.id}}"
|
||||
id="tab-comment-{{ book.id }}"
|
||||
role="tab"
|
||||
aria-selected="{% if status_type == 'comment' %}true{% else %}false{% endif %}"
|
||||
aria-controls="comment-{{ book.id}}"
|
||||
data-category="tab-option-{{ book.id }}">
|
||||
{% trans "Comment" %}
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#quote-{{ book.id }}" id="tab-quote-{{ book.id }}" role="tab" aria-selected="false" aria-controls="quote-{{ book.id }}" data-category="tab-option-{{ book.id }}">{% trans "Quote" %}</a>
|
||||
<li class="{% if status_type == 'quote' %}is-active{% endif %}">
|
||||
<a
|
||||
href="{{ request.path }}?status_type=quote&book={{ book.id }}"
|
||||
id="tab-quote-{{ book.id }}"
|
||||
role="tab"
|
||||
aria-selected="{% if status_type == 'quote' %}true{% else %}false{% endif %}"
|
||||
aria-controls="quote-{{ book.id }}"
|
||||
data-category="tab-option-{{ book.id }}">
|
||||
{% trans "Quote" %}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="tab-option-{{ book.id }}" id="review-{{ book.id }}" role="tabpanel" aria-labelledby="tab-review-{{ book.id }}">
|
||||
<div class="tab-option-{{ book.id }}" id="review-{{ book.id }}" role="tabpanel" aria-labelledby="tab-review-{{ book.id }}" {% if status_type and status_type != "review" %}hidden{% endif %}>
|
||||
{% with 0|uuid as uuid %}
|
||||
{% include 'snippets/create_status_form.html' with type='review' %}
|
||||
{% endwith %}
|
||||
</div>
|
||||
|
||||
<div class="tab-option-{{ book.id }}" id="comment-{{ book.id }}" role="tabpanel" aria-labelledby="tab-comment-{{ book.id }}" hidden>
|
||||
<div class="tab-option-{{ book.id }}" id="comment-{{ book.id }}" role="tabpanel" aria-labelledby="tab-comment-{{ book.id }}" {% if status_type != "comment" %}hidden{% endif %}>
|
||||
{% with 0|uuid as uuid %}
|
||||
{% include 'snippets/create_status_form.html' with type="comment" placeholder="Some thoughts on '"|add:book.title|add:"'" %}
|
||||
{% endwith %}
|
||||
</div>
|
||||
|
||||
<div class="tab-option-{{ book.id }}" id="quote-{{ book.id }}" role="tabpanel" aria-labelledby="tab-quote-{{ book.id }}" hidden>
|
||||
<div class="tab-option-{{ book.id }}" id="quote-{{ book.id }}" role="tabpanel" aria-labelledby="tab-quote-{{ book.id }}" {% if status_type != "quote" %}hidden{% endif %}>
|
||||
{% with 0|uuid as uuid %}
|
||||
{% include 'snippets/create_status_form.html' with type="quotation" placeholder="An excerpt from '"|add:book.title|add:"'" %}
|
||||
{% endwith %}
|
||||
</div>
|
||||
</div>
|
||||
{% endwith %}
|
||||
|
|
|
@ -4,11 +4,11 @@
|
|||
{% csrf_token %}
|
||||
<input type="hidden" name="book" value="{{ book.id }}">
|
||||
<input type="hidden" name="user" value="{{ request.user.id }}">
|
||||
<input type="hidden" name="reply_parent" value="{{ reply_parent.id }}">
|
||||
<input type="hidden" name="reply_parent" value="{% firstof draft.reply_parent.id reply_parent.id %}">
|
||||
{% if type == 'review' %}
|
||||
<div class="control">
|
||||
<label class="label" for="id_name_{{ book.id }}_{{ type }}">{% trans "Title" %}:</label>
|
||||
<input type="text" name="name" maxlength="255" class="input" required="" id="id_name_{{ book.id }}_{{ type }}" placeholder="My {{ type }} of '{{ book.title }}'">
|
||||
<input type="text" name="name" maxlength="255" class="input" required="" id="id_name_{{ book.id }}_{{ type }}" placeholder="My {{ type }} of '{{ book.title }}'" value="{% firstof draft.name ''%}">
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="control">
|
||||
|
@ -27,31 +27,23 @@
|
|||
{% if type == 'review' %}
|
||||
<fieldset>
|
||||
<legend class="is-sr-only">{% trans "Rating" %}</legend>
|
||||
<div class="field is-grouped stars form-rate-stars">
|
||||
<label class="is-sr-only" for="no-rating-{{ book.id }}">{% trans "No rating" %}</label>
|
||||
<input class="is-sr-only" type="radio" name="rating" value="" id="no-rating-{{ book.id }}" checked>
|
||||
{% for i in '12345'|make_list %}
|
||||
<input class="is-sr-only" id="book{{book.id}}-star-{{ forloop.counter }}" type="radio" name="rating" value="{{ forloop.counter }}">
|
||||
<label class="icon icon-star-empty" for="book{{book.id}}-star-{{ forloop.counter }}">
|
||||
<span class="is-sr-only">{{ forloop.counter }} star{{ forloop.counter | pluralize }}</span>
|
||||
</label>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
{% include 'snippets/form_rate_stars.html' with book=book type=type|default:'summary' default_rating=draft.rating %}
|
||||
</fieldset>
|
||||
{% endif %}
|
||||
|
||||
{% if type == 'quotation' %}
|
||||
<textarea name="quote" class="textarea" id="id_quote_{{ book.id }}_{{ type }}" placeholder="{{ placeholder }}" required></textarea>
|
||||
<textarea name="quote" class="textarea" id="id_quote_{{ book.id }}_{{ type }}" placeholder="{{ placeholder }}" required>{{ draft.quote|default:'' }}</textarea>
|
||||
{% else %}
|
||||
{% include 'snippets/content_warning_field.html' with parent_status=status %}
|
||||
<textarea name="content" class="textarea" id="id_content_{{ type }}-{{ book.id }}{{reply_parent.id}}" placeholder="{{ placeholder }}" {% if type == 'reply' %} aria-label="Reply"{% endif %} required>{% if reply_parent %}{{ reply_parent|mentions:request.user }}{% endif %}{% if mentions %}@{{ mentions|username }} {% endif %}</textarea>
|
||||
<textarea name="content" class="textarea" id="id_content_{{ type }}-{{ book.id }}{{reply_parent.id}}" placeholder="{{ placeholder }}" {% if type == 'reply' %} aria-label="Reply"{% endif %} required>{% if reply_parent %}{{ reply_parent|mentions:request.user }}{% endif %}{% if mentions %}@{{ mentions|username }} {% endif %}{{ draft.content|default:'' }}</textarea>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% if type == 'quotation' %}
|
||||
<div class="control">
|
||||
<label class="label" for="id_content_quote-{{ book.id }}">{% trans "Comment" %}:</label>
|
||||
{% include 'snippets/content_warning_field.html' with parent_status=status %}
|
||||
<textarea name="content" class="textarea is-small" id="id_content_quote-{{ book.id }}"></textarea>
|
||||
<textarea name="content" class="textarea is-small" id="id_content_quote-{{ book.id }}">{{ draft.content|default:'' }}</textarea>
|
||||
</div>
|
||||
{% elif type == 'comment' %}
|
||||
<div class="control">
|
||||
|
@ -64,12 +56,12 @@
|
|||
<label class="label" for="progress-{{ uuid }}">{% trans "Progress:" %}</label>
|
||||
<div class="field has-addons mb-0">
|
||||
<div class="control">
|
||||
<input aria-label="{% if readthrough.progress_mode == 'PG' %}Current page{% else %}Percent read{% endif %}" class="input" type="number" min="0" name="progress" size="3" value="{{ readthrough.progress|default:'' }}" id="progress-{{ uuid }}">
|
||||
<input aria-label="{% if draft.progress_mode == 'PG' or readthrough.progress_mode == 'PG' %}Current page{% else %}Percent read{% endif %}" class="input" type="number" min="0" name="progress" size="3" value="{% firstof draft.progress readthrough.progress '' %}" id="progress-{{ uuid }}">
|
||||
</div>
|
||||
<div class="control select">
|
||||
<select name="progress_mode" aria-label="Progress mode">
|
||||
<option value="PG" {% if readthrough.progress_mode == 'PG' %}selected{% endif %}>{% trans "pages" %}</option>
|
||||
<option value="PCT" {% if readthrough.progress_mode == 'PCT' %}selected{% endif %}>{% trans "percent" %}</option>
|
||||
<option value="PG" {% if draft.progress_mode == 'PG' or readthrough.progress_mode == 'PG' %}selected{% endif %}>{% trans "pages" %}</option>
|
||||
<option value="PCT" {% if draft.progress_mode == 'PCT' or readthrough.progress_mode == 'PCT' %}selected{% endif %}>{% trans "percent" %}</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -81,21 +73,26 @@
|
|||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
<input type="checkbox" class="hidden" name="sensitive" id="id_show_spoilers-{{ uuid }}" {% if status.content_warning %}checked{% endif %} aria-hidden="true">
|
||||
<input type="checkbox" class="hidden" name="sensitive" id="id_show_spoilers-{{ uuid }}" {% if draft.content_warning or status.content_warning %}checked{% endif %} aria-hidden="true">
|
||||
{# bottom bar #}
|
||||
<div class="columns pt-1">
|
||||
<div class="field has-addons column">
|
||||
<div class="control">
|
||||
{% trans "Include spoiler alert" as button_text %}
|
||||
{% include 'snippets/toggle/toggle_button.html' with text=button_text icon="warning is-size-4" controls_text="spoilers" controls_uid=uuid focus="id_content_warning" checkbox="id_show_spoilers" class="toggle-button" pressed=status.content_warning %}
|
||||
{% firstof draft.content_warning status.content_warning as pressed %}
|
||||
{% include 'snippets/toggle/toggle_button.html' with text=button_text icon="warning is-size-4" controls_text="spoilers" controls_uid=uuid focus="id_content_warning" checkbox="id_show_spoilers" class="toggle-button" pressed=pressed %}
|
||||
</div>
|
||||
<div class="control">
|
||||
{% if type == 'direct' %}
|
||||
<input type="hidden" name="privacy" value="direct">
|
||||
<button type="button" class="button" aria-label="Privacy" disabled>{% trans "Private" %}</button>
|
||||
{% else %}
|
||||
{% if draft %}
|
||||
{% include 'snippets/privacy_select.html' with current=draft.privacy %}
|
||||
{% else %}
|
||||
{% include 'snippets/privacy_select.html' with current=reply_parent.privacy %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="column is-narrow">
|
||||
|
|
54
bookwyrm/templates/snippets/form_rate_stars.html
Normal file
54
bookwyrm/templates/snippets/form_rate_stars.html
Normal file
|
@ -0,0 +1,54 @@
|
|||
{% spaceless %}
|
||||
{% load i18n %}
|
||||
{% load bookwyrm_tags %}
|
||||
|
||||
<div class="
|
||||
field is-grouped
|
||||
stars form-rate-stars
|
||||
{% if classes %}{{classes}}{% endif%}
|
||||
">
|
||||
<input
|
||||
id="{{ type|slugify }}-{{ book.id }}-no-rating"
|
||||
class="is-sr-only"
|
||||
type="radio"
|
||||
name="rating"
|
||||
value="0"
|
||||
{% if default_rating == 0 or not default_rating %}checked{% endif %}
|
||||
>
|
||||
|
||||
<label class="is-sr-only" for="{{ type|slugify }}-{{ book.id }}-no-rating">
|
||||
{% trans "No rating" %}
|
||||
</label>
|
||||
|
||||
{% for i in '12345'|make_list %}
|
||||
<input
|
||||
id="{{ type|slugify }}-book{{ book.id }}-star-{{ forloop.counter }}"
|
||||
class="is-sr-only"
|
||||
type="radio"
|
||||
name="rating"
|
||||
value="{{ forloop.counter }}"
|
||||
{% if default_rating == forloop.counter %}checked{% endif %}
|
||||
/>
|
||||
|
||||
<label
|
||||
class="
|
||||
icon
|
||||
{% if forloop.counter <= default_rating %}
|
||||
icon-star-full
|
||||
{% else %}
|
||||
icon-star-empty
|
||||
{% endif %}
|
||||
"
|
||||
for="{{ type|slugify }}-book{{ book.id }}-star-{{ forloop.counter }}"
|
||||
>
|
||||
<span class="is-sr-only">
|
||||
{% blocktranslate trimmed count rating=forloop.counter %}
|
||||
{{ rating }} star
|
||||
{% plural %}
|
||||
{{ rating }} stars
|
||||
{% endblocktranslate %}
|
||||
</span>
|
||||
</label>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endspaceless %}
|
|
@ -1,12 +1,26 @@
|
|||
{% load i18n %}
|
||||
<nav class="pagination" aria-label="pagination">
|
||||
<a class="pagination-previous" {% if page.has_previous %}href="{{ path }}?{% for k, v in request.GET.items %}{% if k != 'page' %}{{ k }}={{ v }}&{% endif %}{% endfor %}page={{ page.previous_page_number }}{{ anchor }}" {% else %}disabled{% endif %}>
|
||||
<span class="icon icon-arrow-left"></span>
|
||||
<a
|
||||
class="pagination-previous {% if not page.has_previous %}is-disabled{% endif %}"
|
||||
{% if page.has_previous %}
|
||||
href="{{ path }}?{% for k, v in request.GET.items %}{% if k != 'page' %}{{ k }}={{ v }}&{% endif %}{% endfor %}page={{ page.previous_page_number }}{{ anchor }}"
|
||||
{% else %}
|
||||
aria-hidden="true"
|
||||
{% endif %}>
|
||||
|
||||
<span class="icon icon-arrow-left" aria-hidden="true"></span>
|
||||
{% trans "Previous" %}
|
||||
</a>
|
||||
|
||||
<a class="pagination-next" {% if page.has_next %}href="{{ path }}?{% for k, v in request.GET.items %}{% if k != 'page' %}{{ k }}={{ v }}&{% endif %}{% endfor %}page={{ page.next_page_number }}{{ anchor }}"{% else %} disabled{% endif %}>
|
||||
<a
|
||||
class="pagination-next {% if not page.has_next %}is-disabled{% endif %}"
|
||||
{% if page.has_next %}
|
||||
href="{{ path }}?{% for k, v in request.GET.items %}{% if k != 'page' %}{{ k }}={{ v }}&{% endif %}{% endfor %}page={{ page.next_page_number }}{{ anchor }}"
|
||||
{% else %}
|
||||
aria-hidden="true"
|
||||
{% endif %}>
|
||||
|
||||
{% trans "Next" %}
|
||||
<span class="icon icon-arrow-right"></span>
|
||||
<span class="icon icon-arrow-right" aria-hidden="true"></span>
|
||||
</a>
|
||||
</nav>
|
||||
|
|
|
@ -8,18 +8,8 @@
|
|||
<input type="hidden" name="user" value="{{ request.user.id }}">
|
||||
<input type="hidden" name="book" value="{{ book.id }}">
|
||||
<input type="hidden" name="privacy" value="public">
|
||||
<input type="hidden" name="rating" value="{{ forloop.counter }}">
|
||||
|
||||
<div class="field is-grouped stars form-rate-stars mb-1 has-text-warning-dark">
|
||||
<label class="is-sr-only" for="rating-no-rating-{{ book.id }}">{% trans "No rating" %}</label>
|
||||
<input class="is-sr-only" type="radio" name="rating" value="" id="rating-no-rating-{{ book.id }}" checked>
|
||||
{% for i in '12345'|make_list %}
|
||||
<input class="is-sr-only" id="rating-book{{book.id}}-star-{{ forloop.counter }}" type="radio" name="rating" value="{{ forloop.counter }}" {% if book|user_rating:user == forloop.counter %}checked{% endif %}>
|
||||
<label class="icon icon-star-empty" for="rating-book{{book.id}}-star-{{ forloop.counter }}">
|
||||
<span class="is-sr-only">{{ forloop.counter }} star{{ forloop.counter | pluralize }}</span>
|
||||
</label>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% include 'snippets/form_rate_stars.html' with book=book classes='mb-1 has-text-warning-dark' default_rating=book|user_rating:request.user %}
|
||||
|
||||
<div class="field has-addons hidden">
|
||||
<div class="control">
|
||||
|
|
|
@ -1,8 +1,27 @@
|
|||
{% spaceless %}
|
||||
{% load i18n %}
|
||||
|
||||
<p class="stars">
|
||||
<span class="is-sr-only">{% if rating %}{{ rating|floatformat }} star{{ rating|floatformat | pluralize }}{% else %}{% trans "No rating" %}{% endif %}</span>
|
||||
{% for i in '12345'|make_list %}
|
||||
<span class="icon is-small mr-1 icon-star-{% if rating >= forloop.counter %}full{% elif rating|floatformat:0 >= forloop.counter|floatformat:0 %}half{% else %}empty{% endif %}" aria-hidden="true">
|
||||
<span class="is-sr-only">
|
||||
{% if rating %}
|
||||
{% blocktranslate trimmed with rating=rating|floatformat count counter=rating|length %}
|
||||
{{ rating }} star
|
||||
{% plural %}
|
||||
{{ rating }} stars
|
||||
{% endblocktranslate %}
|
||||
{% else %}
|
||||
{% trans "No rating" %}
|
||||
{% endif %}
|
||||
</span>
|
||||
|
||||
{% for i in '12345'|make_list %}
|
||||
<span
|
||||
class="
|
||||
icon is-small mr-1
|
||||
icon-star-{% if rating >= forloop.counter %}full{% elif rating|floatformat:0 >= forloop.counter|floatformat:0 %}half{% else %}empty{% endif %}
|
||||
"
|
||||
aria-hidden="true"
|
||||
></span>
|
||||
{% endfor %}
|
||||
</p>
|
||||
{% endspaceless %}
|
||||
|
|
|
@ -27,7 +27,8 @@
|
|||
{% trans "Delete status" %}
|
||||
</button>
|
||||
</form>
|
||||
|
||||
{% elif no_interact %}
|
||||
{# nothing here #}
|
||||
{% elif request.user.is_authenticated %}
|
||||
<div class="field has-addons">
|
||||
<div class="control">
|
||||
|
|
|
@ -19,6 +19,16 @@
|
|||
</button>
|
||||
</form>
|
||||
</li>
|
||||
{% if status.status_type != 'GeneratedNote' and status.status_type != 'Rating' %}
|
||||
<li role="menuitem">
|
||||
<form class="dropdown-item pt-0 pb-0" name="delete-{{status.id}}" action="{% url 'redraft' status.id %}" method="post">
|
||||
{% csrf_token %}
|
||||
<button class="button is-danger is-light is-fullwidth is-small" type="submit">
|
||||
{% trans "Delete & re-draft" %}
|
||||
</button>
|
||||
</form>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
{# things you can do to other people's statuses #}
|
||||
<li role="menuitem">
|
||||
|
|
|
@ -40,6 +40,7 @@ class StatusViews(TestCase):
|
|||
remote_id="https://example.com/book/1",
|
||||
parent_work=work,
|
||||
)
|
||||
models.SiteSettings.objects.create()
|
||||
|
||||
def test_handle_status(self, _):
|
||||
""" create a status """
|
||||
|
@ -166,6 +167,61 @@ class StatusViews(TestCase):
|
|||
self.assertFalse(self.remote_user in reply.mention_users.all())
|
||||
self.assertTrue(self.local_user in reply.mention_users.all())
|
||||
|
||||
def test_delete_and_redraft(self, _):
|
||||
""" delete and re-draft a status """
|
||||
view = views.DeleteAndRedraft.as_view()
|
||||
request = self.factory.post("")
|
||||
request.user = self.local_user
|
||||
with patch("bookwyrm.activitystreams.ActivityStream.add_status"):
|
||||
status = models.Comment.objects.create(
|
||||
content="hi", book=self.book, user=self.local_user
|
||||
)
|
||||
|
||||
with patch("bookwyrm.activitystreams.ActivityStream.remove_status") as mock:
|
||||
result = view(request, status.id)
|
||||
self.assertTrue(mock.called)
|
||||
result.render()
|
||||
|
||||
# make sure it was deleted
|
||||
status.refresh_from_db()
|
||||
self.assertTrue(status.deleted)
|
||||
|
||||
def test_delete_and_redraft_invalid_status_type_rating(self, _):
|
||||
""" you can't redraft generated statuses """
|
||||
view = views.DeleteAndRedraft.as_view()
|
||||
request = self.factory.post("")
|
||||
request.user = self.local_user
|
||||
with patch("bookwyrm.activitystreams.ActivityStream.add_status"):
|
||||
status = models.ReviewRating.objects.create(
|
||||
book=self.book, rating=2.0, user=self.local_user
|
||||
)
|
||||
|
||||
with patch("bookwyrm.activitystreams.ActivityStream.remove_status") as mock:
|
||||
result = view(request, status.id)
|
||||
self.assertFalse(mock.called)
|
||||
self.assertEqual(result.status_code, 400)
|
||||
|
||||
status.refresh_from_db()
|
||||
self.assertFalse(status.deleted)
|
||||
|
||||
def test_delete_and_redraft_invalid_status_type_generated_note(self, _):
|
||||
""" you can't redraft generated statuses """
|
||||
view = views.DeleteAndRedraft.as_view()
|
||||
request = self.factory.post("")
|
||||
request.user = self.local_user
|
||||
with patch("bookwyrm.activitystreams.ActivityStream.add_status"):
|
||||
status = models.GeneratedNote.objects.create(
|
||||
content="hi", user=self.local_user
|
||||
)
|
||||
|
||||
with patch("bookwyrm.activitystreams.ActivityStream.remove_status") as mock:
|
||||
result = view(request, status.id)
|
||||
self.assertFalse(mock.called)
|
||||
self.assertEqual(result.status_code, 400)
|
||||
|
||||
status.refresh_from_db()
|
||||
self.assertFalse(status.deleted)
|
||||
|
||||
def test_find_mentions(self, _):
|
||||
""" detect and look up @ mentions of users """
|
||||
user = models.User.objects.create_user(
|
||||
|
|
|
@ -197,11 +197,31 @@ urlpatterns = [
|
|||
re_path(r"^block/(?P<user_id>\d+)/?$", views.Block.as_view()),
|
||||
re_path(r"^unblock/(?P<user_id>\d+)/?$", views.unblock),
|
||||
# statuses
|
||||
re_path(r"%s(.json)?/?$" % status_path, views.Status.as_view()),
|
||||
re_path(r"%s/activity/?$" % status_path, views.Status.as_view()),
|
||||
re_path(r"%s/replies(.json)?/?$" % status_path, views.Replies.as_view()),
|
||||
re_path(r"^post/(?P<status_type>\w+)/?$", views.CreateStatus.as_view()),
|
||||
re_path(r"^delete-status/(?P<status_id>\d+)/?$", views.DeleteStatus.as_view()),
|
||||
re_path(r"%s(.json)?/?$" % status_path, views.Status.as_view(), name="status"),
|
||||
re_path(r"%s/activity/?$" % status_path, views.Status.as_view(), name="status"),
|
||||
re_path(
|
||||
r"%s/replies(.json)?/?$" % status_path, views.Replies.as_view(), name="replies"
|
||||
),
|
||||
re_path(
|
||||
r"^post/?$",
|
||||
views.CreateStatus.as_view(),
|
||||
name="create-status",
|
||||
),
|
||||
re_path(
|
||||
r"^post/(?P<status_type>\w+)/?$",
|
||||
views.CreateStatus.as_view(),
|
||||
name="create-status",
|
||||
),
|
||||
re_path(
|
||||
r"^delete-status/(?P<status_id>\d+)/?$",
|
||||
views.DeleteStatus.as_view(),
|
||||
name="delete-status",
|
||||
),
|
||||
re_path(
|
||||
r"^redraft-status/(?P<status_id>\d+)/?$",
|
||||
views.DeleteAndRedraft.as_view(),
|
||||
name="redraft",
|
||||
),
|
||||
# interact
|
||||
re_path(r"^favorite/(?P<status_id>\d+)/?$", views.Favorite.as_view()),
|
||||
re_path(r"^unfavorite/(?P<status_id>\d+)/?$", views.Unfavorite.as_view()),
|
||||
|
|
|
@ -31,7 +31,7 @@ from .shelf import Shelf
|
|||
from .shelf import create_shelf, delete_shelf
|
||||
from .shelf import shelve, unshelve
|
||||
from .site import Site
|
||||
from .status import CreateStatus, DeleteStatus
|
||||
from .status import CreateStatus, DeleteStatus, DeleteAndRedraft
|
||||
from .tag import Tag, AddTag, RemoveTag
|
||||
from .updates import get_notification_count, get_unread_status_count
|
||||
from .user import User, EditUser, Followers, Following
|
||||
|
|
|
@ -99,7 +99,11 @@ class ManageInviteRequests(View):
|
|||
page = 1
|
||||
|
||||
sort = request.GET.get("sort")
|
||||
sort_fields = ["created_date", "invite__times_used"]
|
||||
sort_fields = [
|
||||
"created_date",
|
||||
"invite__times_used",
|
||||
"invite__invitees__created_date",
|
||||
]
|
||||
if not sort in sort_fields + ["-{:s}".format(f) for f in sort_fields]:
|
||||
sort = "-created_date"
|
||||
|
||||
|
@ -115,7 +119,7 @@ class ManageInviteRequests(View):
|
|||
if "requested" in status_filters:
|
||||
filters.append({"invite__isnull": True})
|
||||
if "sent" in status_filters:
|
||||
filters.append({"invite__isnull": False})
|
||||
filters.append({"invite__isnull": False, "invite__times_used": 0})
|
||||
if "accepted" in status_filters:
|
||||
filters.append({"invite__isnull": False, "invite__times_used__gte": 1})
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@ import re
|
|||
from django.contrib.auth.decorators import login_required
|
||||
from django.http import HttpResponseBadRequest
|
||||
from django.shortcuts import get_object_or_404, redirect
|
||||
from django.template.response import TemplateResponse
|
||||
from django.utils.decorators import method_decorator
|
||||
from django.views import View
|
||||
from markdown import markdown
|
||||
|
@ -10,7 +11,6 @@ from markdown import markdown
|
|||
from bookwyrm import forms, models
|
||||
from bookwyrm.sanitize_html import InputHtmlParser
|
||||
from bookwyrm.settings import DOMAIN
|
||||
from bookwyrm.status import delete_status
|
||||
from bookwyrm.utils import regex
|
||||
from .helpers import handle_remote_webfinger
|
||||
from .reading import edit_readthrough
|
||||
|
@ -21,6 +21,12 @@ from .reading import edit_readthrough
|
|||
class CreateStatus(View):
|
||||
""" the view for *posting* """
|
||||
|
||||
def get(self, request):
|
||||
""" compose view (used for delete-and-redraft """
|
||||
book = get_object_or_404(models.Edition, id=request.GET.get("book"))
|
||||
data = {"book": book}
|
||||
return TemplateResponse(request, "compose.html", data)
|
||||
|
||||
def post(self, request, status_type):
|
||||
""" create status of whatever type """
|
||||
status_type = status_type[0].upper() + status_type[1:]
|
||||
|
@ -69,9 +75,10 @@ class CreateStatus(View):
|
|||
# update a readthorugh, if needed
|
||||
edit_readthrough(request)
|
||||
|
||||
return redirect(request.headers.get("Referer", "/"))
|
||||
return redirect("/")
|
||||
|
||||
|
||||
@method_decorator(login_required, name="dispatch")
|
||||
class DeleteStatus(View):
|
||||
""" tombstone that bad boy """
|
||||
|
||||
|
@ -84,10 +91,44 @@ class DeleteStatus(View):
|
|||
return HttpResponseBadRequest()
|
||||
|
||||
# perform deletion
|
||||
delete_status(status)
|
||||
status.delete()
|
||||
return redirect(request.headers.get("Referer", "/"))
|
||||
|
||||
|
||||
@method_decorator(login_required, name="dispatch")
|
||||
class DeleteAndRedraft(View):
|
||||
""" delete a status but let the user re-create it """
|
||||
|
||||
def post(self, request, status_id):
|
||||
""" delete and tombstone a status """
|
||||
status = get_object_or_404(
|
||||
models.Status.objects.select_subclasses(), id=status_id
|
||||
)
|
||||
if isinstance(status, (models.GeneratedNote, models.ReviewRating)):
|
||||
return HttpResponseBadRequest()
|
||||
|
||||
# don't let people redraft other people's statuses
|
||||
if status.user != request.user:
|
||||
return HttpResponseBadRequest()
|
||||
|
||||
status_type = status.status_type.lower()
|
||||
if status.reply_parent:
|
||||
status_type = "reply"
|
||||
|
||||
data = {
|
||||
"draft": status,
|
||||
"type": status_type,
|
||||
}
|
||||
if hasattr(status, "book"):
|
||||
data["book"] = status.book
|
||||
elif status.mention_books:
|
||||
data["book"] = status.mention_books.first()
|
||||
|
||||
# perform deletion
|
||||
status.delete()
|
||||
return TemplateResponse(request, "compose.html", data)
|
||||
|
||||
|
||||
def find_mentions(content):
|
||||
""" detect @mentions in raw status content """
|
||||
if not content:
|
||||
|
|
2
bw-dev
2
bw-dev
|
@ -76,7 +76,7 @@ case "$CMD" in
|
|||
docker-compose exec web python manage.py collectstatic --no-input
|
||||
docker-compose restart
|
||||
;;
|
||||
populate_feeds)
|
||||
populate_streams)
|
||||
execweb python manage.py populate_streams
|
||||
;;
|
||||
*)
|
||||
|
|
Binary file not shown.
|
@ -8,8 +8,8 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: 0.1.1\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2021-04-01 13:14-0700\n"
|
||||
"PO-Revision-Date: 2021-03-02 12:37+0100\n"
|
||||
"POT-Creation-Date: 2021-04-04 13:04+0000\n"
|
||||
"PO-Revision-Date: 2021-04-04 14:43+0100\n"
|
||||
"Last-Translator: Fabien Basmaison <contact@arkhi.org>\n"
|
||||
"Language-Team: Mouse Reeve <LL@li.org>\n"
|
||||
"Language: fr_FR\n"
|
||||
|
@ -59,7 +59,7 @@ msgstr ""
|
|||
msgid "%(value)s is not a valid username"
|
||||
msgstr ""
|
||||
|
||||
#: bookwyrm/models/fields.py:165 bookwyrm/templates/layout.html:157
|
||||
#: bookwyrm/models/fields.py:165 bookwyrm/templates/layout.html:152
|
||||
#, fuzzy
|
||||
#| msgid "Username:"
|
||||
msgid "username"
|
||||
|
@ -185,7 +185,7 @@ msgstr "Description :"
|
|||
#: bookwyrm/templates/edit_author.html:78 bookwyrm/templates/lists/form.html:42
|
||||
#: bookwyrm/templates/preferences/edit_user.html:70
|
||||
#: bookwyrm/templates/settings/site.html:93
|
||||
#: bookwyrm/templates/snippets/readthrough.html:65
|
||||
#: bookwyrm/templates/snippets/readthrough.html:75
|
||||
#: bookwyrm/templates/snippets/shelve_button/finish_reading_modal.html:42
|
||||
#: bookwyrm/templates/snippets/shelve_button/progress_update_modal.html:42
|
||||
#: bookwyrm/templates/snippets/shelve_button/start_reading_modal.html:34
|
||||
|
@ -199,7 +199,7 @@ msgstr "Enregistrer"
|
|||
#: bookwyrm/templates/moderation/report_modal.html:32
|
||||
#: bookwyrm/templates/snippets/delete_readthrough_modal.html:17
|
||||
#: bookwyrm/templates/snippets/goal_form.html:32
|
||||
#: bookwyrm/templates/snippets/readthrough.html:66
|
||||
#: bookwyrm/templates/snippets/readthrough.html:76
|
||||
#: bookwyrm/templates/snippets/shelve_button/finish_reading_modal.html:43
|
||||
#: bookwyrm/templates/snippets/shelve_button/progress_update_modal.html:43
|
||||
#: bookwyrm/templates/snippets/shelve_button/start_reading_modal.html:35
|
||||
|
@ -537,7 +537,7 @@ msgstr "Fédéré"
|
|||
|
||||
#: bookwyrm/templates/directory/directory.html:6
|
||||
#: bookwyrm/templates/directory/directory.html:11
|
||||
#: bookwyrm/templates/layout.html:97
|
||||
#: bookwyrm/templates/layout.html:92
|
||||
msgid "Directory"
|
||||
msgstr ""
|
||||
|
||||
|
@ -1082,7 +1082,7 @@ msgid "%(username)s's %(year)s Books"
|
|||
msgstr "Livres de %(username)s en %(year)s"
|
||||
|
||||
#: bookwyrm/templates/import.html:5 bookwyrm/templates/import.html:9
|
||||
#: bookwyrm/templates/layout.html:102
|
||||
#: bookwyrm/templates/layout.html:97
|
||||
msgid "Import Books"
|
||||
msgstr "Importer des livres"
|
||||
|
||||
|
@ -1223,18 +1223,13 @@ msgstr "Menu de navigation principal "
|
|||
msgid "Feed"
|
||||
msgstr "Fil d’actualité"
|
||||
|
||||
#: bookwyrm/templates/layout.html:92
|
||||
#: bookwyrm/templates/preferences/preferences_layout.html:14
|
||||
msgid "Profile"
|
||||
msgstr "Profil"
|
||||
|
||||
#: bookwyrm/templates/layout.html:107
|
||||
#: bookwyrm/templates/layout.html:102
|
||||
#, fuzzy
|
||||
#| msgid "Instance Settings"
|
||||
msgid "Settings"
|
||||
msgstr "Paramètres de l’instance"
|
||||
|
||||
#: bookwyrm/templates/layout.html:116
|
||||
#: bookwyrm/templates/layout.html:111
|
||||
#: bookwyrm/templates/settings/admin_layout.html:24
|
||||
#: bookwyrm/templates/settings/manage_invite_requests.html:15
|
||||
#: bookwyrm/templates/settings/manage_invites.html:3
|
||||
|
@ -1242,59 +1237,59 @@ msgstr "Paramètres de l’instance"
|
|||
msgid "Invites"
|
||||
msgstr "Invitations"
|
||||
|
||||
#: bookwyrm/templates/layout.html:123
|
||||
#: bookwyrm/templates/layout.html:118
|
||||
msgid "Admin"
|
||||
msgstr ""
|
||||
|
||||
#: bookwyrm/templates/layout.html:130
|
||||
#: bookwyrm/templates/layout.html:125
|
||||
msgid "Log out"
|
||||
msgstr "Se déconnecter"
|
||||
|
||||
#: bookwyrm/templates/layout.html:138 bookwyrm/templates/layout.html:139
|
||||
#: bookwyrm/templates/layout.html:133 bookwyrm/templates/layout.html:134
|
||||
#: bookwyrm/templates/notifications.html:6
|
||||
#: bookwyrm/templates/notifications.html:10
|
||||
msgid "Notifications"
|
||||
msgstr "Notifications"
|
||||
|
||||
#: bookwyrm/templates/layout.html:156 bookwyrm/templates/layout.html:160
|
||||
#: bookwyrm/templates/layout.html:151 bookwyrm/templates/layout.html:155
|
||||
#: bookwyrm/templates/login.html:17
|
||||
#: bookwyrm/templates/snippets/register_form.html:4
|
||||
msgid "Username:"
|
||||
msgstr "Nom d’utilisateur :"
|
||||
|
||||
#: bookwyrm/templates/layout.html:161
|
||||
#: bookwyrm/templates/layout.html:156
|
||||
#, fuzzy
|
||||
#| msgid "Password:"
|
||||
msgid "password"
|
||||
msgstr "Mot de passe :"
|
||||
|
||||
#: bookwyrm/templates/layout.html:162 bookwyrm/templates/login.html:36
|
||||
#: bookwyrm/templates/layout.html:157 bookwyrm/templates/login.html:36
|
||||
msgid "Forgot your password?"
|
||||
msgstr "Mot de passe oublié ?"
|
||||
|
||||
#: bookwyrm/templates/layout.html:165 bookwyrm/templates/login.html:10
|
||||
#: bookwyrm/templates/layout.html:160 bookwyrm/templates/login.html:10
|
||||
#: bookwyrm/templates/login.html:33
|
||||
msgid "Log in"
|
||||
msgstr "Se connecter"
|
||||
|
||||
#: bookwyrm/templates/layout.html:173
|
||||
#: bookwyrm/templates/layout.html:168
|
||||
msgid "Join"
|
||||
msgstr ""
|
||||
|
||||
#: bookwyrm/templates/layout.html:196
|
||||
#: bookwyrm/templates/layout.html:191
|
||||
msgid "About this server"
|
||||
msgstr "À propos de ce serveur"
|
||||
|
||||
#: bookwyrm/templates/layout.html:200
|
||||
#: bookwyrm/templates/layout.html:195
|
||||
msgid "Contact site admin"
|
||||
msgstr "Contacter l’administrateur du site"
|
||||
|
||||
#: bookwyrm/templates/layout.html:207
|
||||
#: bookwyrm/templates/layout.html:202
|
||||
#, python-format
|
||||
msgid "Support %(site_name)s on <a href=\"%(support_link)s\" target=\"_blank\">%(support_title)s</a>"
|
||||
msgstr ""
|
||||
|
||||
#: bookwyrm/templates/layout.html:211
|
||||
#: bookwyrm/templates/layout.html:206
|
||||
msgid "BookWyrm is open source software. You can contribute or report issues on <a href=\"https://github.com/mouse-reeve/bookwyrm\">GitHub</a>."
|
||||
msgstr "Bookwyrm est un logiciel libre. Vous pouvez contribuer ou faire des rapports de bogues via <a href=\"https://github.com/mouse-reeve/bookwyrm\">GitHub</a>."
|
||||
|
||||
|
@ -1384,7 +1379,7 @@ msgid "Added by <a href=\"%(user_path)s\">%(username)s</a>"
|
|||
msgstr "Messages directs avec <a href=\"%(path)s\">%(username)s</a>"
|
||||
|
||||
#: bookwyrm/templates/lists/list.html:41
|
||||
#: bookwyrm/templates/snippets/shelf_selector.html:28
|
||||
#: bookwyrm/templates/snippets/shelf_selector.html:26
|
||||
msgid "Remove"
|
||||
msgstr "Supprimer"
|
||||
|
||||
|
@ -1473,7 +1468,7 @@ msgstr ""
|
|||
|
||||
#: bookwyrm/templates/moderation/report.html:54
|
||||
#: bookwyrm/templates/snippets/create_status.html:12
|
||||
#: bookwyrm/templates/snippets/create_status_form.html:52
|
||||
#: bookwyrm/templates/snippets/create_status_form.html:44
|
||||
msgid "Comment"
|
||||
msgstr "Commentaire"
|
||||
|
||||
|
@ -1730,6 +1725,10 @@ msgstr ""
|
|||
msgid "Account"
|
||||
msgstr "Compte"
|
||||
|
||||
#: bookwyrm/templates/preferences/preferences_layout.html:14
|
||||
msgid "Profile"
|
||||
msgstr "Profil"
|
||||
|
||||
#: bookwyrm/templates/preferences/preferences_layout.html:20
|
||||
msgid "Relationships"
|
||||
msgstr "Relations"
|
||||
|
@ -1888,7 +1887,8 @@ msgid "Software"
|
|||
msgstr "Logiciel"
|
||||
|
||||
#: bookwyrm/templates/settings/federation.html:24
|
||||
#: bookwyrm/templates/settings/manage_invite_requests.html:33
|
||||
#: bookwyrm/templates/settings/manage_invite_requests.html:40
|
||||
#: bookwyrm/templates/settings/status_filter.html:5
|
||||
#: bookwyrm/templates/settings/user_admin.html:32
|
||||
msgid "Status"
|
||||
msgstr "Statut"
|
||||
|
@ -1906,61 +1906,64 @@ msgstr "Invitations"
|
|||
msgid "Ignored Invite Requests"
|
||||
msgstr ""
|
||||
|
||||
#: bookwyrm/templates/settings/manage_invite_requests.html:31
|
||||
#: bookwyrm/templates/settings/manage_invite_requests.html:35
|
||||
msgid "Date"
|
||||
msgstr ""
|
||||
|
||||
#: bookwyrm/templates/settings/manage_invite_requests.html:32
|
||||
#: bookwyrm/templates/settings/manage_invite_requests.html:38
|
||||
msgid "Email"
|
||||
msgstr ""
|
||||
|
||||
#: bookwyrm/templates/settings/manage_invite_requests.html:34
|
||||
#: bookwyrm/templates/settings/manage_invite_requests.html:43
|
||||
#, fuzzy
|
||||
#| msgid "Notifications"
|
||||
msgid "Action"
|
||||
msgstr "Notifications"
|
||||
|
||||
#: bookwyrm/templates/settings/manage_invite_requests.html:37
|
||||
#: bookwyrm/templates/settings/manage_invite_requests.html:46
|
||||
#, fuzzy
|
||||
#| msgid "Follow Requests"
|
||||
msgid "No requests"
|
||||
msgstr "Demandes d’abonnement"
|
||||
|
||||
#: bookwyrm/templates/settings/manage_invite_requests.html:45
|
||||
#: bookwyrm/templates/settings/manage_invite_requests.html:54
|
||||
#: bookwyrm/templates/settings/status_filter.html:16
|
||||
#, fuzzy
|
||||
#| msgid "Accept"
|
||||
msgid "Accepted"
|
||||
msgstr "Accepter"
|
||||
|
||||
#: bookwyrm/templates/settings/manage_invite_requests.html:47
|
||||
#: bookwyrm/templates/settings/manage_invite_requests.html:56
|
||||
#: bookwyrm/templates/settings/status_filter.html:12
|
||||
msgid "Sent"
|
||||
msgstr ""
|
||||
|
||||
#: bookwyrm/templates/settings/manage_invite_requests.html:49
|
||||
#: bookwyrm/templates/settings/manage_invite_requests.html:58
|
||||
#: bookwyrm/templates/settings/status_filter.html:8
|
||||
msgid "Requested"
|
||||
msgstr ""
|
||||
|
||||
#: bookwyrm/templates/settings/manage_invite_requests.html:57
|
||||
#: bookwyrm/templates/settings/manage_invite_requests.html:68
|
||||
msgid "Send invite"
|
||||
msgstr ""
|
||||
|
||||
#: bookwyrm/templates/settings/manage_invite_requests.html:59
|
||||
#: bookwyrm/templates/settings/manage_invite_requests.html:70
|
||||
msgid "Re-send invite"
|
||||
msgstr ""
|
||||
|
||||
#: bookwyrm/templates/settings/manage_invite_requests.html:70
|
||||
#: bookwyrm/templates/settings/manage_invite_requests.html:90
|
||||
msgid "Ignore"
|
||||
msgstr ""
|
||||
|
||||
#: bookwyrm/templates/settings/manage_invite_requests.html:72
|
||||
msgid "Un-gnore"
|
||||
#: bookwyrm/templates/settings/manage_invite_requests.html:92
|
||||
msgid "Un-ignore"
|
||||
msgstr ""
|
||||
|
||||
#: bookwyrm/templates/settings/manage_invite_requests.html:83
|
||||
#: bookwyrm/templates/settings/manage_invite_requests.html:103
|
||||
msgid "Back to pending requests"
|
||||
msgstr ""
|
||||
|
||||
#: bookwyrm/templates/settings/manage_invite_requests.html:85
|
||||
#: bookwyrm/templates/settings/manage_invite_requests.html:105
|
||||
msgid "View ignored requests"
|
||||
msgstr ""
|
||||
|
||||
|
@ -2161,47 +2164,41 @@ msgstr "Critique"
|
|||
msgid "Rating"
|
||||
msgstr "Note"
|
||||
|
||||
#: bookwyrm/templates/snippets/create_status_form.html:31
|
||||
#: bookwyrm/templates/snippets/rate_action.html:14
|
||||
#: bookwyrm/templates/snippets/stars.html:3
|
||||
msgid "No rating"
|
||||
msgstr "Aucune note"
|
||||
|
||||
#: bookwyrm/templates/snippets/create_status_form.html:64
|
||||
#: bookwyrm/templates/snippets/create_status_form.html:56
|
||||
#: bookwyrm/templates/snippets/shelve_button/progress_update_modal.html:16
|
||||
msgid "Progress:"
|
||||
msgstr "Progression :"
|
||||
|
||||
#: bookwyrm/templates/snippets/create_status_form.html:71
|
||||
#: bookwyrm/templates/snippets/create_status_form.html:63
|
||||
#: bookwyrm/templates/snippets/readthrough_form.html:22
|
||||
#: bookwyrm/templates/snippets/shelve_button/progress_update_modal.html:30
|
||||
msgid "pages"
|
||||
msgstr "pages"
|
||||
|
||||
#: bookwyrm/templates/snippets/create_status_form.html:72
|
||||
#: bookwyrm/templates/snippets/create_status_form.html:64
|
||||
#: bookwyrm/templates/snippets/readthrough_form.html:23
|
||||
#: bookwyrm/templates/snippets/shelve_button/progress_update_modal.html:31
|
||||
msgid "percent"
|
||||
msgstr "pourcent"
|
||||
|
||||
#: bookwyrm/templates/snippets/create_status_form.html:77
|
||||
#: bookwyrm/templates/snippets/create_status_form.html:69
|
||||
#: bookwyrm/templates/snippets/shelve_button/progress_update_modal.html:36
|
||||
#, python-format
|
||||
msgid "of %(pages)s pages"
|
||||
msgstr "sur %(pages)s pages"
|
||||
|
||||
#: bookwyrm/templates/snippets/create_status_form.html:89
|
||||
#: bookwyrm/templates/snippets/create_status_form.html:81
|
||||
msgid "Include spoiler alert"
|
||||
msgstr "Afficher une alerte spoiler"
|
||||
|
||||
#: bookwyrm/templates/snippets/create_status_form.html:95
|
||||
#: bookwyrm/templates/snippets/create_status_form.html:87
|
||||
#: bookwyrm/templates/snippets/privacy-icons.html:15
|
||||
#: bookwyrm/templates/snippets/privacy-icons.html:16
|
||||
#: bookwyrm/templates/snippets/privacy_select.html:19
|
||||
msgid "Private"
|
||||
msgstr "Privé"
|
||||
|
||||
#: bookwyrm/templates/snippets/create_status_form.html:102
|
||||
#: bookwyrm/templates/snippets/create_status_form.html:94
|
||||
msgid "Post"
|
||||
msgstr "Publier"
|
||||
|
||||
|
@ -2241,11 +2238,11 @@ msgstr "Replier"
|
|||
msgid "Hide filters"
|
||||
msgstr ""
|
||||
|
||||
#: bookwyrm/templates/snippets/filters_panel/filters_panel.html:19
|
||||
#: bookwyrm/templates/snippets/filters_panel/filters_panel.html:22
|
||||
msgid "Apply filters"
|
||||
msgstr ""
|
||||
|
||||
#: bookwyrm/templates/snippets/filters_panel/filters_panel.html:23
|
||||
#: bookwyrm/templates/snippets/filters_panel/filters_panel.html:26
|
||||
#, fuzzy
|
||||
#| msgid "Clear search"
|
||||
msgid "Clear filters"
|
||||
|
@ -2269,6 +2266,19 @@ msgstr "Se désabonner"
|
|||
msgid "Accept"
|
||||
msgstr "Accepter"
|
||||
|
||||
#: bookwyrm/templates/snippets/form_rate_stars.html:20
|
||||
#: bookwyrm/templates/snippets/stars.html:13
|
||||
msgid "No rating"
|
||||
msgstr "Aucune note"
|
||||
|
||||
#: bookwyrm/templates/snippets/form_rate_stars.html:45
|
||||
#: bookwyrm/templates/snippets/stars.html:7
|
||||
#, python-format
|
||||
msgid "%(rating)s star"
|
||||
msgid_plural "%(rating)s stars"
|
||||
msgstr[0] "%(rating)s étoile"
|
||||
msgstr[1] "%(rating)s étoiles"
|
||||
|
||||
#: bookwyrm/templates/snippets/generated_status/goal.html:1
|
||||
#, python-format
|
||||
msgid "set a goal to read %(counter)s book in %(year)s"
|
||||
|
@ -2343,11 +2353,23 @@ msgstr "Vous avez lu <a href=\"%(path)s\">%(read_count)s sur %(goal_count)s livr
|
|||
msgid "%(username)s has read <a href=\"%(path)s\">%(read_count)s of %(goal_count)s books</a>."
|
||||
msgstr "%(username)s a lu <a href=\"%(path)s\">%(read_count)s sur %(goal_count)s livres</a>."
|
||||
|
||||
#: bookwyrm/templates/snippets/pagination.html:7
|
||||
#: bookwyrm/templates/snippets/page_text.html:4
|
||||
#, fuzzy, python-format
|
||||
#| msgid "of %(pages)s pages"
|
||||
msgid "page %(page)s of %(total_pages)s"
|
||||
msgstr "sur %(pages)s pages"
|
||||
|
||||
#: bookwyrm/templates/snippets/page_text.html:6
|
||||
#, fuzzy, python-format
|
||||
#| msgid "of %(book.pages)s pages"
|
||||
msgid "page %(page)s"
|
||||
msgstr "sur %(book.pages)s pages"
|
||||
|
||||
#: bookwyrm/templates/snippets/pagination.html:5
|
||||
msgid "Previous"
|
||||
msgstr "Précédente"
|
||||
|
||||
#: bookwyrm/templates/snippets/pagination.html:15
|
||||
#: bookwyrm/templates/snippets/pagination.html:9
|
||||
msgid "Next"
|
||||
msgstr "Suivante"
|
||||
|
||||
|
@ -2380,7 +2402,7 @@ msgstr "Abonnements"
|
|||
msgid "Leave a rating"
|
||||
msgstr "Laisser une note"
|
||||
|
||||
#: bookwyrm/templates/snippets/rate_action.html:29
|
||||
#: bookwyrm/templates/snippets/rate_action.html:19
|
||||
msgid "Rate"
|
||||
msgstr "Noter"
|
||||
|
||||
|
@ -2388,28 +2410,28 @@ msgstr "Noter"
|
|||
msgid "Progress Updates:"
|
||||
msgstr "Progression :"
|
||||
|
||||
#: bookwyrm/templates/snippets/readthrough.html:12
|
||||
#: bookwyrm/templates/snippets/readthrough.html:14
|
||||
msgid "finished"
|
||||
msgstr "terminé"
|
||||
|
||||
#: bookwyrm/templates/snippets/readthrough.html:15
|
||||
#: bookwyrm/templates/snippets/readthrough.html:25
|
||||
msgid "Show all updates"
|
||||
msgstr "Montrer toutes les progressions"
|
||||
|
||||
#: bookwyrm/templates/snippets/readthrough.html:31
|
||||
#: bookwyrm/templates/snippets/readthrough.html:41
|
||||
msgid "Delete this progress update"
|
||||
msgstr "Supprimer cette mise à jour"
|
||||
|
||||
#: bookwyrm/templates/snippets/readthrough.html:41
|
||||
#: bookwyrm/templates/snippets/readthrough.html:51
|
||||
msgid "started"
|
||||
msgstr "commencé"
|
||||
|
||||
#: bookwyrm/templates/snippets/readthrough.html:47
|
||||
#: bookwyrm/templates/snippets/readthrough.html:61
|
||||
#: bookwyrm/templates/snippets/readthrough.html:57
|
||||
#: bookwyrm/templates/snippets/readthrough.html:71
|
||||
msgid "Edit read dates"
|
||||
msgstr "Modifier les date de lecture"
|
||||
|
||||
#: bookwyrm/templates/snippets/readthrough.html:51
|
||||
#: bookwyrm/templates/snippets/readthrough.html:61
|
||||
#, fuzzy
|
||||
#| msgid "Delete these read dates?"
|
||||
msgid "Delete these read dates"
|
||||
|
@ -2696,11 +2718,11 @@ msgstr "Commencé"
|
|||
msgid "Finished"
|
||||
msgstr "Terminé"
|
||||
|
||||
#: bookwyrm/templates/user/shelf.html:127
|
||||
#: bookwyrm/templates/user/shelf.html:129
|
||||
msgid "This shelf is empty."
|
||||
msgstr "Cette étagère est vide"
|
||||
|
||||
#: bookwyrm/templates/user/shelf.html:133
|
||||
#: bookwyrm/templates/user/shelf.html:135
|
||||
msgid "Delete shelf"
|
||||
msgstr "Supprimer l’étagère"
|
||||
|
||||
|
@ -2781,7 +2803,7 @@ msgstr ""
|
|||
#~ msgid "Getting Started"
|
||||
#~ msgstr "Commencé"
|
||||
|
||||
#, fuzzy, python-format
|
||||
#, fuzzy
|
||||
#~| msgid "No users found for \"%(query)s\""
|
||||
#~ msgid "No users were found for \"%(query)s\""
|
||||
#~ msgstr "Aucun compte trouvé pour « %(query)s »"
|
||||
|
@ -2795,7 +2817,7 @@ msgstr ""
|
|||
#~ msgid "Your lists"
|
||||
#~ msgstr "Vos listes"
|
||||
|
||||
#, fuzzy, python-format
|
||||
#, fuzzy
|
||||
#~| msgid "See all %(size)s"
|
||||
#~ msgid "See all %(size)s lists"
|
||||
#~ msgstr "Voir les %(size)s"
|
||||
|
@ -2821,14 +2843,12 @@ msgstr ""
|
|||
#~ msgid "Your Shelves"
|
||||
#~ msgstr "Vos étagères"
|
||||
|
||||
#, python-format
|
||||
#~ msgid "%(username)s: Shelves"
|
||||
#~ msgstr "%(username)s : Étagères"
|
||||
|
||||
#~ msgid "Shelves"
|
||||
#~ msgstr "Étagères"
|
||||
|
||||
#, python-format
|
||||
#~ msgid "See all %(shelf_count)s shelves"
|
||||
#~ msgstr "Voir les %(shelf_count)s étagères"
|
||||
|
||||
|
|
Binary file not shown.
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue