Merge branch 'main' into production

This commit is contained in:
Mouse Reeve 2021-03-18 09:24:55 -07:00
commit a868e6c6fd
16 changed files with 85 additions and 39 deletions

View file

@ -75,7 +75,7 @@ class ActivityObject:
for field in fields(self):
try:
value = kwargs[field.name]
if value in (None, MISSING):
if value in (None, MISSING, {}):
raise KeyError()
try:
is_subclass = issubclass(field.type, ActivityObject)

View file

@ -24,7 +24,7 @@ class Person(ActivityObject):
outbox: str
followers: str
publicKey: PublicKey
endpoints: Dict
endpoints: Dict = None
name: str = None
summary: str = None
icon: Image = field(default_factory=lambda: {})

View file

@ -115,7 +115,14 @@ class StatusForm(CustomForm):
class EditUserForm(CustomForm):
class Meta:
model = models.User
fields = ["avatar", "name", "email", "summary", "manually_approves_followers"]
fields = [
"avatar",
"name",
"email",
"summary",
"manually_approves_followers",
"show_goal",
]
help_texts = {f: None for f in fields}

View file

@ -0,0 +1,18 @@
# Generated by Django 3.0.7 on 2021-03-18 15:51
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("bookwyrm", "0051_auto_20210316_1950"),
]
operations = [
migrations.AddField(
model_name="user",
name="show_goal",
field=models.BooleanField(default=True),
),
]

View file

@ -73,7 +73,7 @@ class ActivitypubFieldMixin:
raise
value = getattr(data, "actor")
formatted = self.field_from_activity(value)
if formatted is None or formatted is MISSING:
if formatted is None or formatted is MISSING or formatted == {}:
return
setattr(instance, self.name, formatted)
@ -101,7 +101,7 @@ class ActivitypubFieldMixin:
def field_from_activity(self, value):
""" formatter to convert activitypub into a model value """
if hasattr(self, "activitypub_wrapper"):
if value and hasattr(self, "activitypub_wrapper"):
value = value.get(self.activitypub_wrapper)
return value

View file

@ -102,6 +102,7 @@ class User(OrderedCollectionPageMixin, AbstractUser):
updated_date = models.DateTimeField(auto_now=True)
last_active_date = models.DateTimeField(auto_now=True)
manually_approves_followers = fields.BooleanField(default=False)
show_goal = models.BooleanField(default=True)
name_field = "username"

View file

@ -0,0 +1,27 @@
// set javascript listeners
window.onload = function() {
// display based on localstorage vars
document.querySelectorAll('[data-hide]')
.forEach(t => setDisplay(t));
// update localstorage
Array.from(document.getElementsByClassName('set-display'))
.forEach(t => t.onclick = updateDisplay);
};
function updateDisplay(e) {
// used in set reading goal
var key = e.target.getAttribute('data-id');
var value = e.target.getAttribute('data-value');
window.localStorage.setItem(key, value);
document.querySelectorAll('[data-hide="' + key + '"]')
.forEach(t => setDisplay(t));
}
function setDisplay(el) {
// used in set reading goal
var key = el.getAttribute('data-hide');
var value = window.localStorage.getItem(key);
addRemoveClass(el, 'hidden', value);
}

View file

@ -23,14 +23,6 @@ window.onload = function() {
Array.from(document.getElementsByClassName('pulldown-menu'))
.forEach(t => t.onclick = toggleMenu);
// display based on localstorage vars
document.querySelectorAll('[data-hide]')
.forEach(t => setDisplay(t));
// update localstorage
Array.from(document.getElementsByClassName('set-display'))
.forEach(t => t.onclick = updateDisplay);
// hidden submit button in a form
document.querySelectorAll('.hidden-form input')
.forEach(t => t.onchange = revealForm);
@ -78,24 +70,6 @@ function revealForm(e) {
}
function updateDisplay(e) {
// used in set reading goal
var key = e.target.getAttribute('data-id');
var value = e.target.getAttribute('data-value');
window.localStorage.setItem(key, value);
document.querySelectorAll('[data-hide="' + key + '"]')
.forEach(t => setDisplay(t));
}
function setDisplay(el) {
// used in set reading goal
var key = el.getAttribute('data-hide');
var value = window.localStorage.getItem(key);
addRemoveClass(el, 'hidden', value);
}
function toggleAction(e) {
var el = e.currentTarget;
var pressed = el.getAttribute('aria-pressed') == 'false';

View file

@ -19,9 +19,9 @@
</div>
{# announcements and system messages #}
{% if not goal and tab == 'home' %}
{% if request.user.show_goal and not goal and tab == 'home' %}
{% now 'Y' as year %}
<section class="block hidden" aria-title="{% trans 'Announcements' %}" data-hide="hide-{{ year }}-reading-goal">
<section class="block">
{% include 'snippets/goal_card.html' with year=year %}
<hr>
</section>

View file

@ -41,6 +41,12 @@
<p class="help is-danger">{{ error | escape }}</p>
{% endfor %}
</div>
<div class="block">
<label class="checkbox label" for="id_show_goal">
{% trans "Show set reading goal prompt in feed:" %}
{{ form.show_goal }}
</label>
</div>
<div class="block">
<label class="checkbox label" for="id_manually_approves_followers">
{% trans "Manually approve followers:" %}

View file

@ -17,8 +17,9 @@
{% endblock %}
{% block card-footer %}
<div class="card-footer-item is-flex-direction-column">
<button class="button is-danger is-light is-block set-display" data-id="hide-{{ year }}-reading-goal" data-value="true">{% trans "Dismiss message" %}</button>
<form class="card-footer-item is-flex-direction-column" method="post" action="{% url 'hide-goal' %}">
{% csrf_token %}
<button type="submit" class="button is-danger is-light is-block set-display" >{% trans "Dismiss message" %}</button>
<p class="help">{% blocktrans with path=request.user.local_path %}You can set or change your reading goal any time from your <a href="{{ path }}">profile page</a>{% endblocktrans %}</p>
</div>
</form>
{% endblock %}

View file

@ -35,7 +35,7 @@
{% endif %}
{% if status.content and status.status_type != 'GeneratedNote' and status.status_type != 'Announce' %}
{% include 'snippets/trimmed_text.html' with full=status.content|safe %}
{% include 'snippets/trimmed_text.html' with full=status.content|safe no_trim=status.content_warning %}
{% endif %}
{% if status.attachments.exists %}
<div class="block">

View file

@ -6,7 +6,7 @@
{% with full|to_markdown|safe as full %}
{% with full|to_markdown|safe|truncatewords_html:60 as trimmed %}
{% if trimmed != full %}
{% if not no_trim and trimmed != full %}
<div id="hide-full-{{ uuid }}">
<div class="content" id="trimmed-{{ uuid }}">
<div dir="auto">{{ trimmed }}</div>

View file

@ -109,11 +109,13 @@ urlpatterns = [
),
re_path(r"%s/shelves/?$" % user_path, views.user_shelves_page, name="user-shelves"),
re_path(r"%s/lists/?$" % user_path, views.UserLists.as_view(), name="user-lists"),
# goals
re_path(
r"%s/goal/(?P<year>\d{4})/?$" % user_path,
views.Goal.as_view(),
name="user-goal",
),
re_path(r"^hide-goal/?$", views.hide_goal, name="hide-goal"),
# lists
re_path(r"^list/?$", views.Lists.as_view(), name="lists"),
re_path(r"^list/(?P<list_id>\d+)(.json)?/?$", views.List.as_view(), name="list"),

View file

@ -9,7 +9,7 @@ from .federation import Federation
from .feed import DirectMessage, Feed, Replies, Status
from .follow import follow, unfollow
from .follow import accept_follow_request, delete_follow_request
from .goal import Goal
from .goal import Goal, hide_goal
from .import_data import Import, ImportStatus
from .inbox import Inbox
from .interaction import Favorite, Unfavorite, Boost, Unboost

View file

@ -6,6 +6,7 @@ from django.template.loader import get_template
from django.template.response import TemplateResponse
from django.utils.decorators import method_decorator
from django.views import View
from django.views.decorators.http import require_POST
from bookwyrm import forms, models
from bookwyrm.status import create_generated_note
@ -65,3 +66,12 @@ class Goal(View):
)
return redirect(request.headers.get("Referer", "/"))
@require_POST
@login_required
def hide_goal(request):
""" don't keep bugging people to set a goal """
request.user.show_goal = False
request.user.save(broadcast=False)
return redirect(request.headers.get("Referer", "/"))