forked from mirrors/bookwyrm
handles list privacy in display
This commit is contained in:
parent
69c2b192a4
commit
d73a1b4ec1
7 changed files with 79 additions and 58 deletions
|
@ -1,4 +1,4 @@
|
|||
# Generated by Django 3.0.7 on 2021-01-31 05:00
|
||||
# Generated by Django 3.0.7 on 2021-01-31 16:14
|
||||
|
||||
import bookwyrm.models.base_model
|
||||
import bookwyrm.models.fields
|
||||
|
@ -24,7 +24,7 @@ class Migration(migrations.Migration):
|
|||
('name', bookwyrm.models.fields.CharField(max_length=100)),
|
||||
('description', bookwyrm.models.fields.TextField(blank=True, null=True)),
|
||||
('privacy', bookwyrm.models.fields.CharField(choices=[('public', 'Public'), ('unlisted', 'Unlisted'), ('followers', 'Followers'), ('direct', 'Direct')], default='public', max_length=255)),
|
||||
('curation', bookwyrm.models.fields.CharField(choices=[('closed', 'Closed'), ('open', 'Open'), ('moderated', 'Moderated')], default='closed', max_length=255)),
|
||||
('curation', bookwyrm.models.fields.CharField(choices=[('closed', 'Closed'), ('open', 'Open'), ('curated', 'Curated')], default='closed', max_length=255)),
|
||||
],
|
||||
options={
|
||||
'abstract': False,
|
|
@ -11,7 +11,7 @@ from . import fields
|
|||
CurationType = models.TextChoices('Curation', [
|
||||
'closed',
|
||||
'open',
|
||||
'moderated',
|
||||
'curated',
|
||||
])
|
||||
|
||||
class List(OrderedCollectionMixin, BookWyrmModel):
|
||||
|
|
2
bookwyrm/templates/lists/list-item.html
Normal file
2
bookwyrm/templates/lists/list-item.html
Normal file
|
@ -0,0 +1,2 @@
|
|||
<h4><a href="{{ list.local_path }}">{{ list.name }}</a> {% include 'snippets/privacy-icons.html' with item=list %}</h4>
|
||||
{% include 'snippets/trimmed_text.html' with full=list.description %}
|
|
@ -6,18 +6,18 @@
|
|||
</header>
|
||||
|
||||
{% if request.user.is_authenticated %}
|
||||
<section class="block">
|
||||
<section class="block content">
|
||||
<header class="columns">
|
||||
<div class="column">
|
||||
<h2 class="title is-3">Your lists</h2>
|
||||
<h2 class="title">Your lists</h2>
|
||||
</div>
|
||||
<div class="column is-narrow">
|
||||
{% include 'snippets/toggle/open_button.html' with controls_text="create-list" icon="plus" text="Create new list" %}
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<form name="create-list" method="post" action="{% url 'lists' %}" class="box hiddenx" id="create-list">
|
||||
<h3 class="title is-4">Create list</h3>
|
||||
<form name="create-list" method="post" action="{% url 'lists' %}" class="box hidden" id="create-list">
|
||||
<h3 class="title">Create list</h3>
|
||||
{% csrf_token %}
|
||||
<input type="hidden" name="user" value="{{ request.user.id }}">
|
||||
|
||||
|
@ -68,7 +68,7 @@
|
|||
<ul>
|
||||
{% for list in request.user.list_set.all %}
|
||||
<li>
|
||||
<a href="{{ list.local_path }}">{{ list.name }}</a>
|
||||
{% include 'lists/list-item.html' with list=list %}
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
|
@ -77,12 +77,12 @@
|
|||
{% endif %}
|
||||
|
||||
{% if lists.exists %}
|
||||
<section class="block">
|
||||
<h2 class="title is-2">Recent Lists</h2>
|
||||
<section class="block content">
|
||||
<h2 class="title">Recent Lists</h2>
|
||||
<ul>
|
||||
{% for list in lists %}
|
||||
<li>
|
||||
<a href="{{ list.local_path }}">{{ list.name }}</a>
|
||||
{% include 'lists/list-item.html' with list=list %}
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
|
|
|
@ -1,24 +1,26 @@
|
|||
{% load bookwyrm_tags %}
|
||||
{% with 0|uuid as uuid %}
|
||||
{% if full %}
|
||||
{% with full|to_markdown|safe as full %}
|
||||
|
||||
{% with full|to_markdown|safe|truncatewords_html:60 as trimmed %}
|
||||
{% if trimmed != full %}
|
||||
<div id="hide-full-{{ uuid }}">
|
||||
<blockquote class="content" id="trimmed-{{ uuid }}"><span dir="auto">{{ trimmed }}</span>
|
||||
<div class="content" id="trimmed-{{ uuid }}"><span dir="auto">{{ trimmed }}</span>
|
||||
{% include 'snippets/toggle/open_button.html' with text="show more" controls_text="full" controls_uid=uuid class="is-small" %}
|
||||
</blockquote>
|
||||
</div>
|
||||
</div>
|
||||
<div id="full-{{ uuid }}" class="hidden">
|
||||
<blockquote class="content"><span dir="auto">{{ full | to_markdown | safe }}</span>
|
||||
<div class="content"><span dir="auto">{{ full }}</span>
|
||||
{% include 'snippets/toggle/close_button.html' with text="show less" controls_text="full" controls_uid=uuid class="is-small" %}
|
||||
</blockquote>
|
||||
</div>
|
||||
</div>
|
||||
{% else %}
|
||||
<blockquote class="content"><span dir="auto">{{ full | to_markdown | safe }}</span></blockquote>
|
||||
<div class="content"><span dir="auto">{{ full }}</span></div>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
|
||||
{% endwith %}
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
|
||||
|
|
|
@ -59,11 +59,55 @@ def object_visible_to_user(viewer, obj):
|
|||
return True
|
||||
return False
|
||||
|
||||
|
||||
def privacy_filter(viewer, queryset, privacy_levels, following_only=False):
|
||||
''' filter objects that have "user" and "privacy" fields '''
|
||||
# exclude blocks from both directions
|
||||
if not viewer.is_anonymous:
|
||||
blocked = models.User.objects.filter(id__in=viewer.blocks.all()).all()
|
||||
queryset = queryset.exclude(
|
||||
Q(user__in=blocked) | Q(user__blocks=viewer))
|
||||
|
||||
# you can't see followers only or direct messages if you're not logged in
|
||||
if viewer.is_anonymous:
|
||||
privacy_levels = [p for p in privacy_levels if \
|
||||
not p in ['followers', 'direct']]
|
||||
|
||||
# filter to only privided privacy levels
|
||||
queryset = queryset.filter(privacy__in=privacy_levels)
|
||||
|
||||
# only include statuses the user follows
|
||||
if following_only:
|
||||
queryset = queryset.exclude(
|
||||
~Q(# remove everythign except
|
||||
Q(user__in=viewer.following.all()) | # user following
|
||||
Q(user=viewer) |# is self
|
||||
Q(mention_users=viewer)# mentions user
|
||||
),
|
||||
)
|
||||
# exclude followers-only statuses the user doesn't follow
|
||||
elif 'followers' in privacy_levels:
|
||||
queryset = queryset.exclude(
|
||||
~Q(# user isn't following and it isn't their own status
|
||||
Q(user__in=viewer.following.all()) | Q(user=viewer)
|
||||
),
|
||||
privacy='followers' # and the status is followers only
|
||||
)
|
||||
|
||||
# exclude direct messages not intended for the user
|
||||
if 'direct' in privacy_levels:
|
||||
queryset = queryset.exclude(
|
||||
~Q(
|
||||
Q(user=viewer) | Q(mention_users=viewer)
|
||||
), privacy='direct'
|
||||
)
|
||||
return queryset
|
||||
|
||||
|
||||
def get_activity_feed(
|
||||
user, privacy, local_only=False, following_only=False,
|
||||
queryset=models.Status.objects):
|
||||
''' get a filtered queryset of statuses '''
|
||||
privacy = privacy if isinstance(privacy, list) else [privacy]
|
||||
# if we're looking at Status, we need this. We don't if it's Comment
|
||||
if hasattr(queryset, 'select_subclasses'):
|
||||
queryset = queryset.select_subclasses()
|
||||
|
@ -71,44 +115,10 @@ def get_activity_feed(
|
|||
# exclude deleted
|
||||
queryset = queryset.exclude(deleted=True).order_by('-published_date')
|
||||
|
||||
# exclude blocks from both directions
|
||||
if not user.is_anonymous:
|
||||
blocked = models.User.objects.filter(id__in=user.blocks.all()).all()
|
||||
queryset = queryset.exclude(
|
||||
Q(user__in=blocked) | Q(user__blocks=user))
|
||||
|
||||
# you can't see followers only or direct messages if you're not logged in
|
||||
if user.is_anonymous:
|
||||
privacy = [p for p in privacy if not p in ['followers', 'direct']]
|
||||
|
||||
# filter to only privided privacy levels
|
||||
queryset = queryset.filter(privacy__in=privacy)
|
||||
|
||||
# only include statuses the user follows
|
||||
if following_only:
|
||||
queryset = queryset.exclude(
|
||||
~Q(# remove everythign except
|
||||
Q(user__in=user.following.all()) | # user follwoing
|
||||
Q(user=user) |# is self
|
||||
Q(mention_users=user)# mentions user
|
||||
),
|
||||
)
|
||||
# exclude followers-only statuses the user doesn't follow
|
||||
elif 'followers' in privacy:
|
||||
queryset = queryset.exclude(
|
||||
~Q(# user isn't following and it isn't their own status
|
||||
Q(user__in=user.following.all()) | Q(user=user)
|
||||
),
|
||||
privacy='followers' # and the status is followers only
|
||||
)
|
||||
|
||||
# exclude direct messages not intended for the user
|
||||
if 'direct' in privacy:
|
||||
queryset = queryset.exclude(
|
||||
~Q(
|
||||
Q(user=user) | Q(mention_users=user)
|
||||
), privacy='direct'
|
||||
)
|
||||
# apply privacy filters
|
||||
privacy = privacy if isinstance(privacy, list) else [privacy]
|
||||
queryset = privacy_filter(
|
||||
user, queryset, privacy, following_only=following_only)
|
||||
|
||||
# filter for only local status
|
||||
if local_only:
|
||||
|
|
|
@ -9,7 +9,7 @@ from django.views import View
|
|||
|
||||
from bookwyrm import forms, models
|
||||
from bookwyrm.activitypub import ActivitypubResponse
|
||||
from .helpers import is_api_request, object_visible_to_user
|
||||
from .helpers import is_api_request, object_visible_to_user, privacy_filter
|
||||
|
||||
|
||||
# pylint: disable=no-self-use
|
||||
|
@ -18,7 +18,10 @@ class Lists(View):
|
|||
def get(self, request):
|
||||
''' display a book list '''
|
||||
user = request.user if request.user.is_authenticated else None
|
||||
lists = models.List.objects.filter(~Q(user=user)).all()
|
||||
lists = models.List.objects.filter(
|
||||
~Q(user=user),
|
||||
).all()
|
||||
lists = privacy_filter(request.user, lists, ['public', 'followers'])
|
||||
data = {
|
||||
'title': 'Lists',
|
||||
'lists': lists,
|
||||
|
@ -30,7 +33,11 @@ class Lists(View):
|
|||
# pylint: disable=unused-argument
|
||||
def post(self, request):
|
||||
''' create a book_list '''
|
||||
book_list = None
|
||||
form = forms.ListForm(request.POST)
|
||||
if not form.is_valid():
|
||||
print(form.errors)
|
||||
return redirect('lists')
|
||||
book_list = form.save()
|
||||
return redirect(book_list.local_path)
|
||||
|
||||
|
||||
|
|
Loading…
Reference in a new issue