Merge branch 'main' into production

This commit is contained in:
Mouse Reeve 2021-02-23 20:21:47 -08:00
commit 396cb30c3a
54 changed files with 360 additions and 221 deletions

View file

@ -216,10 +216,6 @@ def get_data(url):
raise ConnectorException() raise ConnectorException()
if not resp.ok: if not resp.ok:
try:
resp.raise_for_status()
except requests.exceptions.HTTPError as e:
logger.exception(e)
raise ConnectorException() raise ConnectorException()
try: try:
data = resp.json() data = resp.json()

View file

@ -282,7 +282,7 @@ class OrderedCollectionPageMixin(ObjectMixin):
def to_ordered_collection(self, queryset, \ def to_ordered_collection(self, queryset, \
remote_id=None, page=False, collection_only=False, **kwargs): remote_id=None, page=False, collection_only=False, **kwargs):
''' an ordered collection of whatevers ''' 'pure=pure, '' an ordered collection of whatevers '''
if not queryset.ordered: if not queryset.ordered:
raise RuntimeError('queryset must be ordered') raise RuntimeError('queryset must be ordered')
@ -472,7 +472,7 @@ def sign_and_send(sender, data, destination):
# pylint: disable=unused-argument # pylint: disable=unused-argument
def to_ordered_collection_page( def to_ordered_collection_page(
queryset, remote_id, id_only=False, page=1, **kwargs): queryset, remote_id, id_only=False, page=1, pure=False, **kwargs):
''' serialize and pagiante a queryset ''' ''' serialize and pagiante a queryset '''
paginated = Paginator(queryset, PAGE_LENGTH) paginated = Paginator(queryset, PAGE_LENGTH)
@ -480,7 +480,7 @@ def to_ordered_collection_page(
if id_only: if id_only:
items = [s.remote_id for s in activity_page.object_list] items = [s.remote_id for s in activity_page.object_list]
else: else:
items = [s.to_activity() for s in activity_page.object_list] items = [s.to_activity(pure=pure) for s in activity_page.object_list]
prev_page = next_page = None prev_page = next_page = None
if activity_page.has_next(): if activity_page.has_next():

View file

@ -9,7 +9,7 @@ from django.db import models
from django.utils import timezone from django.utils import timezone
from bookwyrm import activitypub from bookwyrm import activitypub
from bookwyrm.connectors import get_data from bookwyrm.connectors import get_data, ConnectorException
from bookwyrm.models.shelf import Shelf from bookwyrm.models.shelf import Shelf
from bookwyrm.models.status import Status, Review from bookwyrm.models.status import Status, Review
from bookwyrm.settings import DOMAIN from bookwyrm.settings import DOMAIN
@ -112,6 +112,16 @@ class User(OrderedCollectionPageMixin, AbstractUser):
activity_serializer = activitypub.Person activity_serializer = activitypub.Person
@classmethod
def viewer_aware_objects(cls, viewer):
''' the user queryset filtered for the context of the logged in user '''
queryset = cls.objects.filter(is_active=True)
if viewer.is_authenticated:
queryset = queryset.exclude(
blocks=viewer
)
return queryset
def to_outbox(self, filter_type=None, **kwargs): def to_outbox(self, filter_type=None, **kwargs):
''' an ordered collection of statuses ''' ''' an ordered collection of statuses '''
if filter_type: if filter_type:
@ -319,7 +329,7 @@ def set_remote_server(user_id):
actor_parts = urlparse(user.remote_id) actor_parts = urlparse(user.remote_id)
user.federated_server = \ user.federated_server = \
get_or_create_remote_server(actor_parts.netloc) get_or_create_remote_server(actor_parts.netloc)
user.save() user.save(broadcast=False)
if user.bookwyrm_user: if user.bookwyrm_user:
get_remote_reviews.delay(user.outbox) get_remote_reviews.delay(user.outbox)
@ -333,19 +343,24 @@ def get_or_create_remote_server(domain):
except FederatedServer.DoesNotExist: except FederatedServer.DoesNotExist:
pass pass
try:
data = get_data('https://%s/.well-known/nodeinfo' % domain) data = get_data('https://%s/.well-known/nodeinfo' % domain)
try: try:
nodeinfo_url = data.get('links')[0].get('href') nodeinfo_url = data.get('links')[0].get('href')
except (TypeError, KeyError): except (TypeError, KeyError):
return None raise ConnectorException()
data = get_data(nodeinfo_url) data = get_data(nodeinfo_url)
application_type = data.get('software', {}).get('name')
application_version = data.get('software', {}).get('version')
except ConnectorException:
application_type = application_version = None
server = FederatedServer.objects.create( server = FederatedServer.objects.create(
server_name=domain, server_name=domain,
application_type=data['software']['name'], application_type=application_type,
application_version=data['software']['version'], application_version=application_version,
) )
return server return server

View file

@ -100,9 +100,6 @@
.cover-container.is-medium { .cover-container.is-medium {
height: 100px; height: 100px;
} }
.cover-container.is-small {
height: 70px;
}
} }
.cover-container.is-medium .no-cover div { .cover-container.is-medium .no-cover div {

View file

@ -1,16 +0,0 @@
{% extends 'layout.html' %}
{% block content %}
<div class="columns">
<div class="column block">
{% include 'snippets/about.html' %}
</div>
<div class="column block">
<h2 class="title">Code of Conduct</h2>
<div class="content">
{{ site.code_of_conduct | safe }}
</div>
</div>
</div>
{% endblock %}

View file

@ -2,7 +2,7 @@
{% load bookwyrm_tags %} {% load bookwyrm_tags %}
{% block content %} {% block content %}
<div class="block"> <div class="block">
<div class="columns"> <div class="columns is-mobile">
<div class="column"> <div class="column">
<h1 class="title">{{ author.name }}</h1> <h1 class="title">{{ author.name }}</h1>
</div> </div>

View file

@ -4,7 +4,7 @@
{% block content %} {% block content %}
<div class="block"> <div class="block">
<div class="columns"> <div class="columns is-mobile">
<div class="column"> <div class="column">
<h1 class="title"> <h1 class="title">
{{ book.title }}{% if book.subtitle %}: {{ book.title }}{% if book.subtitle %}:
@ -42,26 +42,10 @@
<h3 class="title is-6 mb-1">Add cover</h3> <h3 class="title is-6 mb-1">Add cover</h3>
<form name="add-cover" method="POST" action="/upload-cover/{{ book.id }}" enctype="multipart/form-data"> <form name="add-cover" method="POST" action="/upload-cover/{{ book.id }}" enctype="multipart/form-data">
{% csrf_token %} {% csrf_token %}
<div class="field has-addons"> <label class="label">
<div class="control"> <input type="file" name="cover" accept="image/*" enctype="multipart/form-data" id="id_cover" required>
<div class="file is-small mb-1">
<label class="file-label">
<input class="file-input" type="file" name="cover" accept="image/*" enctype="multipart/form-data" id="id_cover" required>
<span class="file-cta">
<span class="file-icon">
<i class="fas fa-upload"></i>
</span>
<span class="file-label">
Choose file...
</span>
</span>
</label> </label>
</div>
</div>
<div class="control">
<button class="button is-small is-primary" type="submit">Add</button> <button class="button is-small is-primary" type="submit">Add</button>
</div>
</div>
</form> </form>
</div> </div>
{% endif %} {% endif %}
@ -242,7 +226,7 @@
<div class="block" id="reviews"> <div class="block" id="reviews">
{% for review in reviews %} {% for review in reviews %}
<div class="block"> <div class="block">
{% include 'snippets/status.html' with status=review hide_book=True depth=1 %} {% include 'snippets/status/status.html' with status=review hide_book=True depth=1 %}
</div> </div>
{% endfor %} {% endfor %}

View file

@ -0,0 +1,22 @@
{% extends 'layout.html' %}
{% block content %}
<header class="block has-text-centered">
<h1 class="title">{{ site.name }}</h1>
<h2 class="subtitle">{{ site.instance_tagline }}</h2>
</header>
{% include 'discover/icons.html' %}
<section class="block">
{% include 'snippets/about.html' %}
</section>
<div class="block">
<h2 class="title">Code of Conduct</h2>
<div class="content">
{{ site.code_of_conduct | safe }}
</div>
</div>
{% endblock %}

View file

@ -1,33 +1,14 @@
{% extends 'layout.html' %} {% extends 'layout.html' %}
{% block content %} {% block content %}
{% if not request.user.is_authenticated %}
<header class="block has-text-centered"> <header class="block has-text-centered">
<h1 class="title">{{ site.name }}</h1> <h1 class="title">{{ site.name }}</h1>
<h2 class="subtitle">{{ site.instance_tagline }}</h2> <h2 class="subtitle">{{ site.instance_tagline }}</h2>
</header> </header>
<section class="level is-mobile"> {% include 'discover/icons.html' %}
<div class="level-item has-text-centered">
<div>
<p class="title has-text-weight-normal"><span class="icon icon-graphic-paperplane"></span></p>
<p class="heading">Decentralized</p>
</div>
</div>
<div class="level-item has-text-centered">
<div>
<p class="title has-text-weight-normal"><span class="icon icon-graphic-heart"></span></p>
<p class="heading">Friendly</p>
</div>
</div>
<div class="level-item has-text-centered">
<div>
<p class="title has-text-weight-normal"><span class="icon icon-graphic-banknote"></span></p>
<p class="heading">Anti-Corporate</p>
</div>
</div>
</section>
{% if not request.user.is_authenticated %}
<section class="tile is-ancestor"> <section class="tile is-ancestor">
<div class="tile is-7 is-parent"> <div class="tile is-7 is-parent">
<div class="tile is-child box"> <div class="tile is-child box">
@ -49,10 +30,6 @@
</div> </div>
</section> </section>
{% else %}
<div class="block">
<h1 class="title has-text-centered">Discover</h1>
</div>
{% endif %} {% endif %}
<div class="block is-hidden-tablet"> <div class="block is-hidden-tablet">
@ -63,18 +40,18 @@
<div class="tile is-vertical"> <div class="tile is-vertical">
<div class="tile is-parent"> <div class="tile is-parent">
<div class="tile is-child box has-background-white-ter"> <div class="tile is-child box has-background-white-ter">
{% include 'snippets/discover/large-book.html' with book=books.0 %} {% include 'discover/large-book.html' with book=books.0 %}
</div> </div>
</div> </div>
<div class="tile"> <div class="tile">
<div class="tile is-parent is-6"> <div class="tile is-parent is-6">
<div class="tile is-child box has-background-white-ter"> <div class="tile is-child box has-background-white-ter">
{% include 'snippets/discover/small-book.html' with book=books.1 %} {% include 'discover/small-book.html' with book=books.1 %}
</div> </div>
</div> </div>
<div class="tile is-parent is-6"> <div class="tile is-parent is-6">
<div class="tile is-child box has-background-white-ter"> <div class="tile is-child box has-background-white-ter">
{% include 'snippets/discover/small-book.html' with book=books.2 %} {% include 'discover/small-book.html' with book=books.2 %}
</div> </div>
</div> </div>
</div> </div>
@ -83,18 +60,18 @@
<div class="tile"> <div class="tile">
<div class="tile is-parent is-6"> <div class="tile is-parent is-6">
<div class="tile is-child box has-background-white-ter"> <div class="tile is-child box has-background-white-ter">
{% include 'snippets/discover/small-book.html' with book=books.3 %} {% include 'discover/small-book.html' with book=books.3 %}
</div> </div>
</div> </div>
<div class="tile is-parent is-6"> <div class="tile is-parent is-6">
<div class="tile is-child box has-background-white-ter"> <div class="tile is-child box has-background-white-ter">
{% include 'snippets/discover/small-book.html' with book=books.4 %} {% include 'discover/small-book.html' with book=books.4 %}
</div> </div>
</div> </div>
</div> </div>
<div class="tile is-parent"> <div class="tile is-parent">
<div class="tile is-child box has-background-white-ter"> <div class="tile is-child box has-background-white-ter">
{% include 'snippets/discover/large-book.html' with book=books.5 %} {% include 'discover/large-book.html' with book=books.5 %}
</div> </div>
</div> </div>
</div> </div>

View file

@ -0,0 +1,21 @@
<section class="level is-mobile">
<div class="level-item has-text-centered">
<div>
<p class="title has-text-weight-normal"><span class="icon icon-graphic-paperplane"></span></p>
<p class="heading">Decentralized</p>
</div>
</div>
<div class="level-item has-text-centered">
<div>
<p class="title has-text-weight-normal"><span class="icon icon-graphic-heart"></span></p>
<p class="heading">Friendly</p>
</div>
</div>
<div class="level-item has-text-centered">
<div>
<p class="title has-text-weight-normal"><span class="icon icon-graphic-banknote"></span></p>
<p class="heading">Anti-Corporate</p>
</div>
</div>
</section>

View file

@ -2,7 +2,7 @@
{% if book %} {% if book %}
<div class="columns"> <div class="columns">
<div class="column is-narrow"> <div class="column is-narrow">
{% include 'snippets/book_cover.html' with book=book size="large" %} <a href="{{ book.local_path }}">{% include 'snippets/book_cover.html' with book=book size="large" %}</a>
{% include 'snippets/stars.html' with rating=ratings|dict_key:book.id %} {% include 'snippets/stars.html' with rating=ratings|dict_key:book.id %}
</div> </div>
<div class="column"> <div class="column">

View file

@ -1,6 +1,6 @@
{% load bookwyrm_tags %} {% load bookwyrm_tags %}
{% if book %} {% if book %}
{% include 'snippets/book_cover.html' with book=book %} <a href="{{ book.local_path }}">{% include 'snippets/book_cover.html' with book=book %}</a>
{% if ratings %} {% if ratings %}
{% include 'snippets/stars.html' with rating=ratings|dict_key:book.id %} {% include 'snippets/stars.html' with rating=ratings|dict_key:book.id %}
{% endif %} {% endif %}

View file

@ -16,7 +16,7 @@
{% endif %} {% endif %}
{% for activity in activities %} {% for activity in activities %}
<div class="block"> <div class="block">
{% include 'snippets/status.html' with status=activity %} {% include 'snippets/status/status.html' with status=activity %}
</div> </div>
{% endfor %} {% endfor %}

View file

@ -32,7 +32,7 @@
{% endif %} {% endif %}
{% for activity in activities %} {% for activity in activities %}
<div class="block"> <div class="block">
{% include 'snippets/status.html' with status=activity %} {% include 'snippets/status/status.html' with status=activity %}
</div> </div>
{% endfor %} {% endfor %}

View file

@ -8,7 +8,7 @@
{% endwith %} {% endwith %}
{% endif %} {% endif %}
{% include 'snippets/status.html' with status=status main=is_root %} {% include 'snippets/status/status.html' with status=status main=is_root %}
{% if depth <= max_depth and direction >= 0 %} {% if depth <= max_depth and direction >= 0 %}
{% for reply in status|replies %} {% for reply in status|replies %}

View file

@ -19,7 +19,7 @@
{% for item in items %} {% for item in items %}
<li class="block pb-3"> <li class="block pb-3">
<div class="card"> <div class="card">
<div class="card-content columns p-0 mb-0"> <div class="card-content columns p-0 mb-0 is-mobile">
<div class="column is-narrow pt-0 pb-0"> <div class="column is-narrow pt-0 pb-0">
<a href="{{ item.book.local_path }}">{% include 'snippets/book_cover.html' with book=item.book size="medium" %}</a> <a href="{{ item.book.local_path }}">{% include 'snippets/book_cover.html' with book=item.book size="medium" %}</a>
</div> </div>
@ -73,7 +73,7 @@
{% endif %} {% endif %}
{% for book in suggested_books %} {% for book in suggested_books %}
{% if book %} {% if book %}
<div class="block columns"> <div class="block columns is-mobile">
<div class="column is-narrow"> <div class="column is-narrow">
<a href="{{ book.local_path }}">{% include 'snippets/book_cover.html' with book=book size="small" %}</a> <a href="{{ book.local_path }}">{% include 'snippets/book_cover.html' with book=book size="small" %}</a>
</div> </div>

View file

@ -2,7 +2,7 @@
{% load bookwyrm_tags %} {% load bookwyrm_tags %}
{% block content %} {% block content %}
<header class="columns content"> <header class="columns content is-mobile">
<div class="column"> <div class="column">
<h1 class="title">{{ list.name }} <span class="subtitle">{% include 'snippets/privacy-icons.html' with item=list %}</span></h1> <h1 class="title">{{ list.name }} <span class="subtitle">{% include 'snippets/privacy-icons.html' with item=list %}</span></h1>
<p class="subtitle help">Created {% if list.curation != 'open' %} and curated{% endif %} by {% include 'snippets/username.html' with user=list.user %}</p> <p class="subtitle help">Created {% if list.curation != 'open' %} and curated{% endif %} by {% include 'snippets/username.html' with user=list.user %}</p>

View file

@ -5,7 +5,7 @@
<h1 class="title">Lists</h1> <h1 class="title">Lists</h1>
</header> </header>
{% if request.user.is_authenticated and not lists.has_previous %} {% if request.user.is_authenticated and not lists.has_previous %}
<header class="block columns"> <header class="block columns is-mobile">
<div class="column"> <div class="column">
<h2 class="title">Your lists</h2> <h2 class="title">Your lists</h2>
</div> </div>

View file

@ -2,28 +2,6 @@
{% block header %}Invites{% endblock %} {% block header %}Invites{% endblock %}
{% load humanize %} {% load humanize %}
{% block panel %} {% block panel %}
<section class="block">
<table class="table is-striped">
<tr>
<th>Link</th>
<th>Expires</th>
<th>Max uses</th>
<th>Times used</th>
</tr>
{% if not invites %}
<tr><td colspan="4">No active invites</td></tr>
{% endif %}
{% for invite in invites %}
<tr>
<td><a href="{{ invite.link }}">{{ invite.link }}</td>
<td>{{ invite.expiry|naturaltime }}</td>
<td>{{ invite.use_limit }}</td>
<td>{{ invite.times_used }}</td>
</tr>
{% endfor %}
</table>
</section>
<section class="block"> <section class="block">
<h2 class="title is-4">Generate New Invite</h2> <h2 class="title is-4">Generate New Invite</h2>
@ -47,4 +25,27 @@
<button class="button is-primary" type="submit">Create Invite</button> <button class="button is-primary" type="submit">Create Invite</button>
</form> </form>
</section> </section>
<section class="block">
<table class="table is-striped">
<tr>
<th>Link</th>
<th>Expires</th>
<th>Max uses</th>
<th>Times used</th>
</tr>
{% if not invites %}
<tr><td colspan="4">No active invites</td></tr>
{% endif %}
{% for invite in invites %}
<tr>
<td><a href="{{ invite.link }}">{{ invite.link }}</td>
<td>{{ invite.expiry|naturaltime }}</td>
<td>{{ invite.use_limit }}</td>
<td>{{ invite.times_used }}</td>
</tr>
{% endfor %}
</table>
{% include 'snippets/pagination.html' with page=invites path=request.path %}
</section>
{% endblock %} {% endblock %}

View file

@ -11,7 +11,7 @@
</form> </form>
<form name="unboost" action="/unboost/{{ status.id }}" method="post" class="interaction boost-{{ status.id }}-{{ uuid }} active {% if not request.user|boosted:status %}hidden{% endif %}" data-id="boost-{{ status.id }}-{{ uuid }}"> <form name="unboost" action="/unboost/{{ status.id }}" method="post" class="interaction boost-{{ status.id }}-{{ uuid }} active {% if not request.user|boosted:status %}hidden{% endif %}" data-id="boost-{{ status.id }}-{{ uuid }}">
{% csrf_token %} {% csrf_token %}
<button class="button is-small is-success" type="submit"> <button class="button is-small is-primary" type="submit">
<span class="icon icon-boost" title="Un-boost status"> <span class="icon icon-boost" title="Un-boost status">
<span class="is-sr-only">Un-boost status</span> <span class="is-sr-only">Un-boost status</span>
</span> </span>

View file

@ -10,7 +10,7 @@
</form> </form>
<form name="unfavorite" action="/unfavorite/{{ status.id }}" method="POST" class="interaction fav-{{ status.id }}-{{ uuid }} active {% if not request.user|liked:status %}hidden{% endif %}" data-id="fav-{{ status.id }}-{{ uuid }}"> <form name="unfavorite" action="/unfavorite/{{ status.id }}" method="POST" class="interaction fav-{{ status.id }}-{{ uuid }} active {% if not request.user|liked:status %}hidden{% endif %}" data-id="fav-{{ status.id }}-{{ uuid }}">
{% csrf_token %} {% csrf_token %}
<button class="button is-success is-small" type="submit"> <button class="button is-primary is-small" type="submit">
<span class="icon icon-heart" title="Un-like status"> <span class="icon icon-heart" title="Un-like status">
<span class="is-sr-only">Un-like status</span> <span class="is-sr-only">Un-like status</span>
</span> </span>

View file

@ -5,8 +5,12 @@
Follow request already sent. Follow request already sent.
</div> </div>
{% elif user in request.user.blocks.all %}
{% include 'snippets/block_button.html' %}
{% else %} {% else %}
<div class="field has-addons">
<div class="control">
<form action="/follow/" method="POST" class="interaction follow-{{ user.id }} {% if request.user in user.followers.all %}hidden{%endif %}" data-id="follow-{{ user.id }}"> <form action="/follow/" method="POST" class="interaction follow-{{ user.id }} {% if request.user in user.followers.all %}hidden{%endif %}" data-id="follow-{{ user.id }}">
{% csrf_token %} {% csrf_token %}
<input type="hidden" name="user" value="{{ user.username }}"> <input type="hidden" name="user" value="{{ user.username }}">
@ -21,4 +25,9 @@ Follow request already sent.
<input type="hidden" name="user" value="{{ user.username }}"> <input type="hidden" name="user" value="{{ user.username }}">
<button class="button is-small is-danger is-light" type="submit">Unfollow</button> <button class="button is-small is-danger is-light" type="submit">Unfollow</button>
</form> </form>
</div>
<div class="control">
{% include 'snippets/user_options.html' with user=user class="is-small" %}
</div>
</div>
{% endif %} {% endif %}

View file

@ -9,7 +9,7 @@
<input type="hidden" name="privacy" value="public"> <input type="hidden" name="privacy" value="public">
<input type="hidden" name="rating" value="{{ forloop.counter }}"> <input type="hidden" name="rating" value="{{ forloop.counter }}">
<div class="field is-grouped stars form-rate-stars mb-1"> <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 }}">No rating</label> <label class="is-sr-only" for="rating-no-rating-{{ book.id }}">No rating</label>
<input class="is-sr-only" type="radio" name="rating" value="" id="rating-no-rating-{{ book.id }}" checked> <input class="is-sr-only" type="radio" name="rating" value="" id="rating-no-rating-{{ book.id }}" checked>
{% for i in '12345'|make_list %} {% for i in '12345'|make_list %}

View file

@ -1,6 +1,7 @@
{% load humanize %} {% load humanize %}
{% load bookwyrm_tags %} {% load bookwyrm_tags %}
{% if books|length > 0 %} {% if books|length > 0 %}
<div class="table-container">
<table class="table is-striped is-fullwidth"> <table class="table is-striped is-fullwidth">
<tr class="book-preview"> <tr class="book-preview">
@ -74,6 +75,7 @@
</tr> </tr>
{% endfor %} {% endfor %}
</table> </table>
</div>
{% else %} {% else %}
<p>This shelf is empty.</p> <p>This shelf is empty.</p>
{% if shelf.editable %} {% if shelf.editable %}

View file

@ -1,7 +1,7 @@
<p class="stars"> <p class="stars">
<span class="is-sr-only">{% if rating %}{{ rating|floatformat }} star{{ rating|floatformat | pluralize }}{% else %}No rating{% endif %}</span> <span class="is-sr-only">{% if rating %}{{ rating|floatformat }} star{{ rating|floatformat | pluralize }}{% else %}No rating{% endif %}</span>
{% for i in '12345'|make_list %} {% for i in '12345'|make_list %}
<span class="icon icon-star-{% if rating >= forloop.counter %}full{% elif rating|floatformat:0 >= forloop.counter|floatformat:0 %}half{% else %}empty{% endif %}" aria-hidden="true"> <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> </span>
{% endfor %} {% endfor %}
</p> </p>

View file

@ -3,6 +3,7 @@
<div class="column is-narrow"> <div class="column is-narrow">
<div> <div>
<a href="{{ book.local_path }}">{% include 'snippets/book_cover.html' with book=book %}</a> <a href="{{ book.local_path }}">{% include 'snippets/book_cover.html' with book=book %}</a>
{% include 'snippets/stars.html' with rating=book|rating:request.user %}
{% include 'snippets/shelve_button/shelve_button.html' with book=book %} {% include 'snippets/shelve_button/shelve_button.html' with book=book %}
</div> </div>
</div> </div>

View file

@ -4,8 +4,8 @@
{% include 'snippets/avatar.html' with user=status.user %} {% include 'snippets/avatar.html' with user=status.user %}
{% include 'snippets/username.html' with user=status.user %} {% include 'snippets/username.html' with user=status.user %}
boosted boosted
{% include 'snippets/status_body.html' with status=status|boosted_status %} {% include 'snippets/status/status_body.html' with status=status|boosted_status %}
{% else %} {% else %}
{% include 'snippets/status_body.html' with status=status %} {% include 'snippets/status/status_body.html' with status=status %}
{% endif %} {% endif %}
{% endif %} {% endif %}

View file

@ -5,13 +5,13 @@
{% block card-header %} {% block card-header %}
<h3 class="card-header-title has-background-white-ter is-block"> <h3 class="card-header-title has-background-white-ter is-block">
{% include 'snippets/status_header.html' with status=status %} {% include 'snippets/status/status_header.html' with status=status %}
</h3> </h3>
{% endblock %} {% endblock %}
{% block card-content %} {% block card-content %}
{% include 'snippets/status_content.html' with status=status %} {% include 'snippets/status/status_content.html' with status=status %}
{% endblock %} {% endblock %}
@ -55,7 +55,7 @@
<a href="{{ status.remote_id }}">{{ status.published_date | post_date }}</a> <a href="{{ status.remote_id }}">{{ status.published_date | post_date }}</a>
</div> </div>
<div class="card-footer-item"> <div class="card-footer-item">
{% include 'snippets/status_options.html' with class="is-small" right=True %} {% include 'snippets/status/status_options.html' with class="is-small" right=True %}
</div> </div>
{% endblock %} {% endblock %}

View file

@ -54,9 +54,9 @@
{% if status.book or status.mention_books.count %} {% if status.book or status.mention_books.count %}
<div class="{% if status.status_type != 'GeneratedNote' %}box has-background-white-bis{% endif %}"> <div class="{% if status.status_type != 'GeneratedNote' %}box has-background-white-bis{% endif %}">
{% if status.book %} {% if status.book %}
{% include 'snippets/book_preview.html' with book=status.book %} {% include 'snippets/status/book_preview.html' with book=status.book %}
{% elif status.mention_books.count %} {% elif status.mention_books.count %}
{% include 'snippets/book_preview.html' with book=status.mention_books.first %} {% include 'snippets/status/book_preview.html' with book=status.mention_books.first %}
{% endif %} {% endif %}
</div> </div>
{% endif %} {% endif %}

View file

@ -15,19 +15,15 @@
<div class="block"> <div class="block">
<h2 class="title">Followers</h2> <h2 class="title">Followers</h2>
{% for followers in followers %} {% for followers in followers %}
<div class="block"> <div class="block columns">
<div class="field is-grouped"> <div class="column">
<div class="control">
{% include 'snippets/avatar.html' with user=followers %} {% include 'snippets/avatar.html' with user=followers %}
</div>
<div class="control">
{% include 'snippets/username.html' with user=followers show_full=True %} {% include 'snippets/username.html' with user=followers show_full=True %}
</div> </div>
<div class="control"> <div class="column is-narrow">
{% include 'snippets/follow_button.html' with user=followers %} {% include 'snippets/follow_button.html' with user=followers %}
</div> </div>
</div> </div>
</div>
{% endfor %} {% endfor %}
{% if not followers.count %} {% if not followers.count %}
<div>{{ user|username }} has no followers</div> <div>{{ user|username }} has no followers</div>

View file

@ -15,19 +15,15 @@
<div class="block"> <div class="block">
<h2 class="title">Following</h2> <h2 class="title">Following</h2>
{% for follower in user.following.all %} {% for follower in user.following.all %}
<div class="block"> <div class="block columns">
<div class="field is-grouped"> <div class="column">
<div class="control">
{% include 'snippets/avatar.html' with user=follower %} {% include 'snippets/avatar.html' with user=follower %}
</div>
<div class="control">
{% include 'snippets/username.html' with user=follower show_full=True %} {% include 'snippets/username.html' with user=follower show_full=True %}
</div> </div>
<div class="control"> <div class="column">
{% include 'snippets/follow_button.html' with user=follower %} {% include 'snippets/follow_button.html' with user=follower %}
</div> </div>
</div> </div>
</div>
{% endfor %} {% endfor %}
{% if not following.count %} {% if not following.count %}
<div>{{ user|username }} isn't following any users</div> <div>{{ user|username }} isn't following any users</div>

View file

@ -1,7 +1,7 @@
{% extends 'user/user_layout.html' %} {% extends 'user/user_layout.html' %}
{% block header %} {% block header %}
<div class="columns"> <div class="columns is-mobile">
<div class="column"> <div class="column">
<h1 class="title"> <h1 class="title">
{% if is_self %}Your {% if is_self %}Your

View file

@ -38,7 +38,7 @@
{% include 'user/create_shelf_form.html' with controls_text='create-shelf-form' %} {% include 'user/create_shelf_form.html' with controls_text='create-shelf-form' %}
</div> </div>
<div class="block columns"> <div class="block columns is-mobile">
<div class="column"> <div class="column">
<h2 class="title is-3"> <h2 class="title is-3">
{{ shelf.name }} {{ shelf.name }}

View file

@ -1,7 +1,7 @@
{% extends 'user/user_layout.html' %} {% extends 'user/user_layout.html' %}
{% block header %} {% block header %}
<div class="columns"> <div class="columns is-mobile">
<div class="column"> <div class="column">
<h1 class="title">User profile</h1> <h1 class="title">User profile</h1>
</div> </div>
@ -54,7 +54,7 @@
{% endif %} {% endif %}
<div> <div>
<div class="columns"> <div class="columns is-mobile">
<h2 class="title column">User Activity</h2> <h2 class="title column">User Activity</h2>
<div class="column is-narrow"> <div class="column is-narrow">
<a class="icon icon-rss" target="_blank" href="{{ user.local_path }}/rss"> <a class="icon icon-rss" target="_blank" href="{{ user.local_path }}/rss">
@ -64,7 +64,7 @@
</div> </div>
{% for activity in activities %} {% for activity in activities %}
<div class="block" id="feed"> <div class="block" id="feed">
{% include 'snippets/status.html' with status=activity %} {% include 'snippets/status/status.html' with status=activity %}
</div> </div>
{% endfor %} {% endfor %}
{% if not activities %} {% if not activities %}

View file

@ -43,14 +43,7 @@
</div> </div>
</div> </div>
{% if not is_self and request.user.is_authenticated %} {% if not is_self and request.user.is_authenticated %}
<div class="field has-addons">
<div class="control">
{% include 'snippets/follow_button.html' with user=user %} {% include 'snippets/follow_button.html' with user=user %}
</div>
<div class="control">
{% include 'snippets/user_options.html' with user=user class="is-small" %}
</div>
</div>
{% endif %} {% endif %}
{% if is_self and user.follower_requests.all %} {% if is_self and user.follower_requests.all %}

View file

@ -1,16 +1,18 @@
''' testing models ''' ''' testing models '''
from unittest.mock import patch from unittest.mock import patch
from django.test import TestCase from django.test import TestCase
import responses
from bookwyrm import models from bookwyrm import models
from bookwyrm.settings import DOMAIN from bookwyrm.settings import DOMAIN
# pylint: disable=missing-class-docstring
# pylint: disable=missing-function-docstring
class User(TestCase): class User(TestCase):
def setUp(self): def setUp(self):
self.user = models.User.objects.create_user( self.user = models.User.objects.create_user(
'mouse@%s' % DOMAIN, 'mouse@mouse.mouse', 'mouseword', 'mouse@%s' % DOMAIN, 'mouse@mouse.mouse', 'mouseword',
local=True, localname='mouse', name='hi') local=True, localname='mouse', name='hi', bookwyrm_user=False)
def test_computed_fields(self): def test_computed_fields(self):
''' username instead of id here ''' ''' username instead of id here '''
@ -28,7 +30,7 @@ class User(TestCase):
with patch('bookwyrm.models.user.set_remote_server.delay'): with patch('bookwyrm.models.user.set_remote_server.delay'):
user = models.User.objects.create_user( user = models.User.objects.create_user(
'rat', 'rat@rat.rat', 'ratword', local=False, 'rat', 'rat@rat.rat', 'ratword', local=False,
remote_id='https://example.com/dfjkg') remote_id='https://example.com/dfjkg', bookwyrm_user=False)
self.assertEqual(user.username, 'rat@example.com') self.assertEqual(user.username, 'rat@example.com')
@ -62,7 +64,7 @@ class User(TestCase):
self.assertEqual(activity['name'], self.user.name) self.assertEqual(activity['name'], self.user.name)
self.assertEqual(activity['inbox'], self.user.inbox) self.assertEqual(activity['inbox'], self.user.inbox)
self.assertEqual(activity['outbox'], self.user.outbox) self.assertEqual(activity['outbox'], self.user.outbox)
self.assertEqual(activity['bookwyrmUser'], True) self.assertEqual(activity['bookwyrmUser'], False)
self.assertEqual(activity['discoverable'], True) self.assertEqual(activity['discoverable'], True)
self.assertEqual(activity['type'], 'Person') self.assertEqual(activity['type'], 'Person')
@ -71,3 +73,83 @@ class User(TestCase):
self.assertEqual(activity['type'], 'OrderedCollection') self.assertEqual(activity['type'], 'OrderedCollection')
self.assertEqual(activity['id'], self.user.outbox) self.assertEqual(activity['id'], self.user.outbox)
self.assertEqual(activity['totalItems'], 0) self.assertEqual(activity['totalItems'], 0)
def test_set_remote_server(self):
server = models.FederatedServer.objects.create(
server_name=DOMAIN,
application_type='test type',
application_version=3
)
models.user.set_remote_server(self.user.id)
self.user.refresh_from_db()
self.assertEqual(self.user.federated_server, server)
@responses.activate
def test_get_or_create_remote_server(self):
responses.add(
responses.GET,
'https://%s/.well-known/nodeinfo' % DOMAIN,
json={'links': [{'href': 'http://www.example.com'}, {}]}
)
responses.add(
responses.GET,
'http://www.example.com',
json={'software': {'name': 'hi', 'version': '2'}},
)
server = models.user.get_or_create_remote_server(DOMAIN)
self.assertEqual(server.server_name, DOMAIN)
self.assertEqual(server.application_type, 'hi')
self.assertEqual(server.application_version, '2')
@responses.activate
def test_get_or_create_remote_server_no_wellknown(self):
responses.add(
responses.GET,
'https://%s/.well-known/nodeinfo' % DOMAIN,
status=404
)
server = models.user.get_or_create_remote_server(DOMAIN)
self.assertEqual(server.server_name, DOMAIN)
self.assertIsNone(server.application_type)
self.assertIsNone(server.application_version)
@responses.activate
def test_get_or_create_remote_server_no_links(self):
responses.add(
responses.GET,
'https://%s/.well-known/nodeinfo' % DOMAIN,
json={'links': [{'href': 'http://www.example.com'}, {}]}
)
responses.add(
responses.GET,
'http://www.example.com',
status=404
)
server = models.user.get_or_create_remote_server(DOMAIN)
self.assertEqual(server.server_name, DOMAIN)
self.assertIsNone(server.application_type)
self.assertIsNone(server.application_version)
@responses.activate
def test_get_or_create_remote_server_unknown_format(self):
responses.add(
responses.GET,
'https://%s/.well-known/nodeinfo' % DOMAIN,
json={'links': [{'href': 'http://www.example.com'}, {}]}
)
responses.add(
responses.GET,
'http://www.example.com',
json={'fish': 'salmon'}
)
server = models.user.get_or_create_remote_server(DOMAIN)
self.assertEqual(server.server_name, DOMAIN)
self.assertIsNone(server.application_type)
self.assertIsNone(server.application_version)

View file

@ -56,12 +56,14 @@ class ViewsHelpers(TestCase):
def test_get_user_from_username(self): def test_get_user_from_username(self):
''' works for either localname or username ''' ''' works for either localname or username '''
self.assertEqual( self.assertEqual(
views.helpers.get_user_from_username('mouse'), self.local_user) views.helpers.get_user_from_username(
self.local_user, 'mouse'), self.local_user)
self.assertEqual( self.assertEqual(
views.helpers.get_user_from_username( views.helpers.get_user_from_username(
'mouse@local.com'), self.local_user) self.local_user, 'mouse@local.com'), self.local_user)
with self.assertRaises(models.User.DoesNotExist): with self.assertRaises(models.User.DoesNotExist):
views.helpers.get_user_from_username('mojfse@example.com') views.helpers.get_user_from_username(
self.local_user, 'mojfse@example.com')
def test_is_api_request(self): def test_is_api_request(self):
@ -188,18 +190,18 @@ class ViewsHelpers(TestCase):
def test_is_bookwyrm_request(self): def test_is_bookwyrm_request(self):
''' checks if a request came from a bookwyrm instance ''' ''' checks if a request came from a bookwyrm instance '''
request = self.factory.get('', {'q': 'Test Book'}) request = self.factory.get('', {'q': 'Test Book'})
self.assertFalse(views.helpers.is_bookworm_request(request)) self.assertFalse(views.helpers.is_bookwyrm_request(request))
request = self.factory.get( request = self.factory.get(
'', {'q': 'Test Book'}, '', {'q': 'Test Book'},
HTTP_USER_AGENT=\ HTTP_USER_AGENT=\
"http.rb/4.4.1 (Mastodon/3.3.0; +https://mastodon.social/)" "http.rb/4.4.1 (Mastodon/3.3.0; +https://mastodon.social/)"
) )
self.assertFalse(views.helpers.is_bookworm_request(request)) self.assertFalse(views.helpers.is_bookwyrm_request(request))
request = self.factory.get( request = self.factory.get(
'', {'q': 'Test Book'}, HTTP_USER_AGENT=USER_AGENT) '', {'q': 'Test Book'}, HTTP_USER_AGENT=USER_AGENT)
self.assertTrue(views.helpers.is_bookworm_request(request)) self.assertTrue(views.helpers.is_bookwyrm_request(request))
def test_existing_user(self): def test_existing_user(self):

View file

@ -7,6 +7,7 @@ from django.test import TestCase
from django.test.client import RequestFactory from django.test.client import RequestFactory
from bookwyrm import models, views from bookwyrm import models, views
from bookwyrm.settings import USER_AGENT
# pylint: disable=too-many-public-methods # pylint: disable=too-many-public-methods
@ -90,3 +91,39 @@ class OutboxView(TestCase):
data = json.loads(result.content) data = json.loads(result.content)
self.assertEqual(data['type'], 'OrderedCollection') self.assertEqual(data['type'], 'OrderedCollection')
self.assertEqual(data['totalItems'], 1) self.assertEqual(data['totalItems'], 1)
def test_outbox_bookwyrm_request_true(self):
''' should differentiate between bookwyrm and outside requests '''
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
models.Review.objects.create(
name='hi',
content='look at this',
user=self.local_user,
book=self.book,
privacy='public',
)
request = self.factory.get('', {'page': 1}, HTTP_USER_AGENT=USER_AGENT)
result = views.Outbox.as_view()(request, 'mouse')
data = json.loads(result.content)
self.assertEqual(len(data['orderedItems']), 1)
self.assertEqual(data['orderedItems'][0]['type'], 'Review')
def test_outbox_bookwyrm_request_false(self):
''' should differentiate between bookwyrm and outside requests '''
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
models.Review.objects.create(
name='hi',
content='look at this',
user=self.local_user,
book=self.book,
privacy='public',
)
request = self.factory.get('', {'page': 1})
result = views.Outbox.as_view()(request, 'mouse')
data = json.loads(result.content)
self.assertEqual(len(data['orderedItems']), 1)
self.assertEqual(data['orderedItems'][0]['type'], 'Article')

View file

@ -41,6 +41,7 @@ class RssFeedView(TestCase):
''' load an rss feed ''' ''' load an rss feed '''
view = rss_feed.RssFeed() view = rss_feed.RssFeed()
request = self.factory.get('/user/rss_user/rss') request = self.factory.get('/user/rss_user/rss')
request.user = self.user
with patch("bookwyrm.models.SiteSettings.objects.get") as site: with patch("bookwyrm.models.SiteSettings.objects.get") as site:
site.return_value = self.site site.return_value = self.site
result = view(request, username=self.user.username) result = view(request, username=self.user.username)

View file

@ -13,7 +13,7 @@ from bookwyrm.activitypub import ActivitypubResponse
from bookwyrm.settings import PAGE_LENGTH from bookwyrm.settings import PAGE_LENGTH
from .helpers import get_activity_feed from .helpers import get_activity_feed
from .helpers import get_user_from_username from .helpers import get_user_from_username
from .helpers import is_api_request, is_bookworm_request, object_visible_to_user from .helpers import is_api_request, is_bookwyrm_request, object_visible_to_user
# pylint: disable= no-self-use # pylint: disable= no-self-use
@ -65,7 +65,7 @@ class DirectMessage(View):
user = None user = None
if username: if username:
try: try:
user = get_user_from_username(username) user = get_user_from_username(request.user, username)
except models.User.DoesNotExist: except models.User.DoesNotExist:
pass pass
if user: if user:
@ -91,7 +91,7 @@ class Status(View):
def get(self, request, username, status_id): def get(self, request, username, status_id):
''' display a particular status (and replies, etc) ''' ''' display a particular status (and replies, etc) '''
try: try:
user = get_user_from_username(username) user = get_user_from_username(request.user, username)
status = models.Status.objects.select_subclasses().get( status = models.Status.objects.select_subclasses().get(
id=status_id, deleted=False) id=status_id, deleted=False)
except ValueError: except ValueError:
@ -107,7 +107,7 @@ class Status(View):
if is_api_request(request): if is_api_request(request):
return ActivitypubResponse( return ActivitypubResponse(
status.to_activity(pure=not is_bookworm_request(request))) status.to_activity(pure=not is_bookwyrm_request(request)))
data = {**feed_page_data(request.user), **{ data = {**feed_page_data(request.user), **{
'title': 'Status by %s' % user.username, 'title': 'Status by %s' % user.username,

View file

@ -13,7 +13,7 @@ def follow(request):
''' follow another user, here or abroad ''' ''' follow another user, here or abroad '''
username = request.POST['user'] username = request.POST['user']
try: try:
to_follow = get_user_from_username(username) to_follow = get_user_from_username(request.user, username)
except models.User.DoesNotExist: except models.User.DoesNotExist:
return HttpResponseBadRequest() return HttpResponseBadRequest()
@ -33,7 +33,7 @@ def unfollow(request):
''' unfollow a user ''' ''' unfollow a user '''
username = request.POST['user'] username = request.POST['user']
try: try:
to_unfollow = get_user_from_username(username) to_unfollow = get_user_from_username(request.user, username)
except models.User.DoesNotExist: except models.User.DoesNotExist:
return HttpResponseBadRequest() return HttpResponseBadRequest()
@ -52,7 +52,7 @@ def accept_follow_request(request):
''' a user accepts a follow request ''' ''' a user accepts a follow request '''
username = request.POST['user'] username = request.POST['user']
try: try:
requester = get_user_from_username(username) requester = get_user_from_username(request.user, username)
except models.User.DoesNotExist: except models.User.DoesNotExist:
return HttpResponseBadRequest() return HttpResponseBadRequest()
@ -75,7 +75,7 @@ def delete_follow_request(request):
''' a user rejects a follow request ''' ''' a user rejects a follow request '''
username = request.POST['user'] username = request.POST['user']
try: try:
requester = get_user_from_username(username) requester = get_user_from_username(request.user, username)
except models.User.DoesNotExist: except models.User.DoesNotExist:
return HttpResponseBadRequest() return HttpResponseBadRequest()

View file

@ -18,7 +18,7 @@ class Goal(View):
''' track books for the year ''' ''' track books for the year '''
def get(self, request, username, year): def get(self, request, username, year):
''' reading goal page ''' ''' reading goal page '''
user = get_user_from_username(username) user = get_user_from_username(request.user, username)
year = int(year) year = int(year)
goal = models.AnnualGoal.objects.filter( goal = models.AnnualGoal.objects.filter(
year=year, user=user year=year, user=user
@ -42,7 +42,7 @@ class Goal(View):
def post(self, request, username, year): def post(self, request, username, year):
''' update or create an annual goal ''' ''' update or create an annual goal '''
user = get_user_from_username(username) user = get_user_from_username(request.user, username)
if user != request.user: if user != request.user:
return HttpResponseNotFound() return HttpResponseNotFound()

View file

@ -9,13 +9,13 @@ from bookwyrm.status import create_generated_note
from bookwyrm.utils import regex from bookwyrm.utils import regex
def get_user_from_username(username): def get_user_from_username(viewer, username):
''' helper function to resolve a localname or a username to a user ''' ''' helper function to resolve a localname or a username to a user '''
# raises DoesNotExist if user is now found # raises DoesNotExist if user is now found
try: try:
return models.User.objects.get(localname=username) return models.User.viewer_aware_objects(viewer).get(localname=username)
except models.User.DoesNotExist: except models.User.DoesNotExist:
return models.User.objects.get(username=username) return models.User.viewer_aware_objects(viewer).get(username=username)
def is_api_request(request): def is_api_request(request):
@ -24,8 +24,8 @@ def is_api_request(request):
request.path[-5:] == '.json' request.path[-5:] == '.json'
def is_bookworm_request(request): def is_bookwyrm_request(request):
''' check if the request is coming from another bookworm instance ''' ''' check if the request is coming from another bookwyrm instance '''
user_agent = request.headers.get('User-Agent') user_agent = request.headers.get('User-Agent')
if user_agent is None or \ if user_agent is None or \
re.search(regex.bookwyrm_user_agent, user_agent) is None: re.search(regex.bookwyrm_user_agent, user_agent) is None:

View file

@ -1,5 +1,6 @@
''' invites when registration is closed ''' ''' invites when registration is closed '''
from django.contrib.auth.decorators import login_required, permission_required from django.contrib.auth.decorators import login_required, permission_required
from django.core.paginator import Paginator
from django.http import HttpResponseBadRequest from django.http import HttpResponseBadRequest
from django.shortcuts import get_object_or_404, redirect from django.shortcuts import get_object_or_404, redirect
from django.template.response import TemplateResponse from django.template.response import TemplateResponse
@ -7,6 +8,7 @@ from django.utils.decorators import method_decorator
from django.views import View from django.views import View
from bookwyrm import forms, models from bookwyrm import forms, models
from bookwyrm.settings import PAGE_LENGTH
# pylint: disable= no-self-use # pylint: disable= no-self-use
@ -18,10 +20,18 @@ class ManageInvites(View):
''' create invites ''' ''' create invites '''
def get(self, request): def get(self, request):
''' invite management page ''' ''' invite management page '''
try:
page = int(request.GET.get('page', 1))
except ValueError:
page = 1
paginated = Paginator(models.SiteInvite.objects.filter(
user=request.user
).order_by('-created_date'), PAGE_LENGTH)
data = { data = {
'title': 'Invitations', 'title': 'Invitations',
'invites': models.SiteInvite.objects.filter( 'invites': paginated.page(page),
user=request.user).order_by('-created_date'),
'form': forms.CreateInviteForm(), 'form': forms.CreateInviteForm(),
} }
return TemplateResponse(request, 'settings/manage_invites.html', data) return TemplateResponse(request, 'settings/manage_invites.html', data)
@ -36,7 +46,15 @@ class ManageInvites(View):
invite.user = request.user invite.user = request.user
invite.save() invite.save()
return redirect('/settings/invites') paginated = Paginator(models.SiteInvite.objects.filter(
user=request.user
).order_by('-created_date'), PAGE_LENGTH)
data = {
'title': 'Invitations',
'invites': paginated.page(1),
'form': form
}
return TemplateResponse(request, 'settings/manage_invites.html', data)
class Invite(View): class Invite(View):

View file

@ -16,7 +16,7 @@ class About(View):
data = { data = {
'title': 'About', 'title': 'About',
} }
return TemplateResponse(request, 'about.html', data) return TemplateResponse(request, 'discover/about.html', data)
class Home(View): class Home(View):
''' discover page or home feed depending on auth ''' ''' discover page or home feed depending on auth '''
@ -56,4 +56,4 @@ class Discover(View):
'books': list(set(books)), 'books': list(set(books)),
'ratings': ratings 'ratings': ratings
} }
return TemplateResponse(request, 'discover.html', data) return TemplateResponse(request, 'discover/discover.html', data)

View file

@ -65,7 +65,7 @@ class UserLists(View):
page = int(request.GET.get('page', 1)) page = int(request.GET.get('page', 1))
except ValueError: except ValueError:
page = 1 page = 1
user = get_user_from_username(username) user = get_user_from_username(request.user, username)
lists = models.List.objects.filter(user=user).all() lists = models.List.objects.filter(user=user).all()
lists = privacy_filter( lists = privacy_filter(
request.user, lists, ['public', 'followers', 'unlisted']) request.user, lists, ['public', 'followers', 'unlisted'])

View file

@ -4,6 +4,7 @@ from django.shortcuts import get_object_or_404
from django.views import View from django.views import View
from bookwyrm import activitypub, models from bookwyrm import activitypub, models
from .helpers import is_bookwyrm_request
# pylint: disable= no-self-use # pylint: disable= no-self-use
@ -17,6 +18,10 @@ class Outbox(View):
filter_type = None filter_type = None
return JsonResponse( return JsonResponse(
user.to_outbox(**request.GET, filter_type=filter_type), user.to_outbox(
**request.GET,
filter_type=filter_type,
pure=not is_bookwyrm_request(request)
),
encoder=activitypub.ActivityEncoder encoder=activitypub.ActivityEncoder
) )

View file

@ -11,7 +11,7 @@ class RssFeed(Feed):
def get_object(self, request, username): def get_object(self, request, username):
''' the user who's posts get serialized ''' ''' the user who's posts get serialized '''
return get_user_from_username(username) return get_user_from_username(request.user, username)
def link(self, obj): def link(self, obj):

View file

@ -33,7 +33,7 @@ class Search(View):
handle_remote_webfinger(query) handle_remote_webfinger(query)
# do a user search # do a user search
user_results = models.User.objects.annotate( user_results = models.User.viewer_aware_objects(request.user).annotate(
similarity=Greatest( similarity=Greatest(
TrigramSimilarity('username', query), TrigramSimilarity('username', query),
TrigramSimilarity('localname', query), TrigramSimilarity('localname', query),

View file

@ -19,7 +19,7 @@ class Shelf(View):
def get(self, request, username, shelf_identifier): def get(self, request, username, shelf_identifier):
''' display a shelf ''' ''' display a shelf '''
try: try:
user = get_user_from_username(username) user = get_user_from_username(request.user, username)
except models.User.DoesNotExist: except models.User.DoesNotExist:
return HttpResponseNotFound() return HttpResponseNotFound()

View file

@ -26,7 +26,7 @@ class User(View):
def get(self, request, username): def get(self, request, username):
''' profile page for a user ''' ''' profile page for a user '''
try: try:
user = get_user_from_username(username) user = get_user_from_username(request.user, username)
except models.User.DoesNotExist: except models.User.DoesNotExist:
return HttpResponseNotFound() return HttpResponseNotFound()
@ -96,7 +96,7 @@ class Followers(View):
def get(self, request, username): def get(self, request, username):
''' list of followers ''' ''' list of followers '''
try: try:
user = get_user_from_username(username) user = get_user_from_username(request.user, username)
except models.User.DoesNotExist: except models.User.DoesNotExist:
return HttpResponseNotFound() return HttpResponseNotFound()
@ -121,7 +121,7 @@ class Following(View):
def get(self, request, username): def get(self, request, username):
''' list of followers ''' ''' list of followers '''
try: try:
user = get_user_from_username(username) user = get_user_from_username(request.user, username)
except models.User.DoesNotExist: except models.User.DoesNotExist:
return HttpResponseNotFound() return HttpResponseNotFound()