bug fixes and tweaks after initial user testing

This commit is contained in:
rimu 2024-01-05 14:09:46 +13:00
parent cb185648d2
commit 39ca00cb8e
27 changed files with 112 additions and 74 deletions

View file

@ -5,11 +5,11 @@ The following are the goals for a 1.0 release, good enough for production use. I
### Basic functionality
- ✅ log in, register, reset password
- ✅ browse and subscribe to communities
- ✅ browse and join communities
- ✅ post in local community
- ✅ comment on posts in local community
- ✅ vote
- sort posts by hotness algo
- sort posts by hotness algo
- ✅ markdown
- ✅ logging and debugging support
@ -30,7 +30,7 @@ The following are the goals for a 1.0 release, good enough for production use. I
### Moderation
- community moderation
- blocking - users, communities, domains, instances. bi-directional.
- blocking - users, communities, domains, instances. bi-directional.
- import/export of block lists
### Onboarding

View file

@ -385,10 +385,11 @@ def admin_user_edit(user_id):
profile_file = request.files['profile_file']
if profile_file and profile_file.filename != '':
# remove old avatar
file = File.query.get(user.avatar_id)
file.delete_from_disk()
user.avatar_id = None
db.session.delete(file)
if user.avatar_id:
file = File.query.get(user.avatar_id)
file.delete_from_disk()
user.avatar_id = None
db.session.delete(file)
# add new avatar
file = save_icon_file(profile_file, 'users')
@ -397,10 +398,11 @@ def admin_user_edit(user_id):
banner_file = request.files['banner_file']
if banner_file and banner_file.filename != '':
# remove old cover
file = File.query.get(user.cover_id)
file.delete_from_disk()
user.cover_id = None
db.session.delete(file)
if user.cover_id:
file = File.query.get(user.cover_id)
file.delete_from_disk()
user.cover_id = None
db.session.delete(file)
# add new cover
file = save_banner_file(banner_file, 'users')

View file

@ -104,7 +104,7 @@ def register():
if current_app.config['MODE'] == 'development':
current_app.logger.info('Verify account:' + url_for('auth.verify_email', token=user.verification_token, _external=True))
flash(_('Great, you are now a registered user! Choose some communities to subscribe to. Use the topic filter to narrow things down.'))
flash(_('Great, you are now a registered user! Choose some communities to join. Use the topic filter to narrow things down.'))
resp = make_response(redirect(url_for('main.list_communities')))
if user_ip_banned():

View file

@ -222,9 +222,9 @@ def subscribe(actor):
success = post_request(community.ap_inbox_url, follow, current_user.private_key,
current_user.profile_id() + '#main-key')
if success:
flash('Your request to subscribe has been sent to ' + community.title)
flash('Your request to join has been sent to ' + community.title)
else:
flash('There was a problem while trying to subscribe.', 'error')
flash('There was a problem while trying to join.', 'error')
else: # for local communities, joining is instant
banned = CommunityBan.query.filter_by(user_id=current_user.id, community_id=community.id).first()
if banned:
@ -232,7 +232,7 @@ def subscribe(actor):
member = CommunityMember(user_id=current_user.id, community_id=community.id)
db.session.add(member)
db.session.commit()
flash('You are subscribed to ' + community.title)
flash('You joined ' + community.title)
referrer = request.headers.get('Referer', None)
if referrer is not None:
return redirect(referrer)
@ -278,14 +278,14 @@ def unsubscribe(actor):
activity.result = 'success'
db.session.commit()
if not success:
flash('There was a problem while trying to subscribe', 'error')
flash('There was a problem while trying to join', 'error')
if proceed:
db.session.query(CommunityMember).filter_by(user_id=current_user.id, community_id=community.id).delete()
db.session.query(CommunityJoinRequest).filter_by(user_id=current_user.id, community_id=community.id).delete()
db.session.commit()
flash('You are unsubscribed from ' + community.title)
flash('You are left ' + community.title)
cache.delete_memoized(community_membership, current_user, community)
else:

View file

@ -163,8 +163,11 @@ def list_local_communities():
@bp.route('/communities/subscribed', methods=['GET'])
def list_subscribed_communities():
verification_warning()
communities = Community.query.filter_by(banned=False).join(CommunityMember).filter(CommunityMember.user_id == current_user.id).all()
return render_template('list_communities.html', communities=communities, title=_('Subscribed communities'),
if current_user.is_authenticated:
communities = Community.query.filter_by(banned=False).join(CommunityMember).filter(CommunityMember.user_id == current_user.id).all()
else:
communities = []
return render_template('list_communities.html', communities=communities, title=_('Joined communities'),
SUBSCRIPTION_PENDING=SUBSCRIPTION_PENDING, SUBSCRIPTION_MEMBER=SUBSCRIPTION_MEMBER)

View file

@ -87,6 +87,15 @@ function setupConfirmFirst() {
event.preventDefault(); // As the user clicked "Cancel" in the dialog, prevent the default action.
}
});
});
const go_back = document.querySelectorAll('.go_back');
go_back.forEach(element => {
element.addEventListener("click", function(event) {
history.back();
event.preventDefault();
return false;
});
})
}

View file

@ -454,6 +454,7 @@ nav.navbar {
max-height: 30px;
min-width: 20px;
min-height: 20px;
vertical-align: text-top;
}
.community_icon_big {

View file

@ -120,6 +120,7 @@ nav.navbar {
max-height: 30px;
min-width: 20px;
min-height: 20px;
vertical-align: text-top;
}
.community_icon_big {

View file

@ -73,7 +73,7 @@
{% block navbar %}
<nav class="navbar navbar-expand-lg navbar-light bg-light fixed-top">
<div class="container-lg">
<a class="navbar-brand" href="/" target="_blank"><img src="/static/images/logo2.png" alt="Logo" width="50" height="50" />{{ g.site.name }}</a>
<a class="navbar-brand" href="/"><img src="/static/images/logo2.png" alt="Logo" width="50" height="50" />{{ g.site.name }}</a>
<button id="navbar-toggler" class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>

View file

@ -75,8 +75,21 @@
<h2>{{ community.title }}</h2>
</div>
<div class="card-body">
<p>{{ community.description|safe }}</p>
<p>{{ community.rules|safe }}</p>
<p>{{ community.description_html|safe if community.description_html else '' }}</p>
<p>{{ community.rules_html|safe if community.rules_html else '' }}</p>
{% if len(mods) > 0 and not community.private_mods %}
<h3>Moderators</h3>
<ul class="moderator_list">
{% for mod in mods %}
<li>{{ render_username(mod) }}</li>
{% endfor %}
</ul>
{% endif %}
{% if rss_feed %}
<p class="mt-4">
<a class="no-underline" href="{{ rss_feed }}" rel="nofollow"><span class="fe fe-rss"></span> RSS feed</a>
</p>
{% endif %}
</div>
</div>
</div>

View file

@ -25,9 +25,9 @@
<a href="/c/{{ new_community.link() }}">{{ new_community.title }}@{{ new_community.ap_domain }}</a>
</p>
<p> {% if subscribed %}
<a class="btn btn-primary mt-4" href="/community/{{ new_community.link() }}/unsubscribe">{{ _('Unsubscribe') }}</a>
<a class="btn btn-primary mt-4" href="/community/{{ new_community.link() }}/unsubscribe">{{ _('Leave') }}</a>
{% else %}
<a class="btn btn-primary mt-4" href="/community/{{ new_community.link() }}/subscribe">{{ _('Subscribe') }}</a>
<a class="btn btn-primary mt-4" href="/community/{{ new_community.link() }}/subscribe">{{ _('Join') }}</a>
{% endif %}
</p>
</div>

View file

@ -64,11 +64,11 @@
<div class="row">
<div class="col-6">
{% if current_user.is_authenticated and community_membership(current_user, community) == SUBSCRIPTION_MEMBER %}
<a class="w-100 btn btn-primary" href="/community/{{ community.link() }}/unsubscribe">{{ _('Unsubscribe') }}</a>
<a class="w-100 btn btn-primary" href="/community/{{ community.link() }}/unsubscribe">{{ _('Leave') }}</a>
{% elif current_user.is_authenticated and community_membership(current_user, community) == SUBSCRIPTION_PENDING %}
<a class="w-100 btn btn-outline-secondary" href="/community/{{ community.link() }}/unsubscribe">{{ _('Pending') }}</a>
{% else %}
<a class="w-100 btn btn-primary" href="/community/{{ community.link() }}/subscribe">{{ _('Subscribe') }}</a>
<a class="w-100 btn btn-primary" href="/community/{{ community.link() }}/subscribe">{{ _('Join') }}</a>
{% endif %}
</div>
<div class="col-6">

View file

@ -1,3 +1,4 @@
<p><a href="https://piefed.social/"><img src="https://piefed.social/static/images/logo2.png" style="max-width: 100%; margin-bottom: 20px;" width="50" height="50" alt="PieFed logo" /></a></p>
<p>Hi {{ user.display_name() }},</p>
<p>
To reset your password

View file

@ -1,3 +1,4 @@
<p><a href="https://piefed.social/"><img src="https://piefed.social/static/images/logo2.png" style="max-width: 100%; margin-bottom: 20px;" width="50" height="50" alt="PieFed logo" /></a></p>
<p>Hi {{ user.display_name() }},</p>
<p>
To verify your email address

View file

@ -1,4 +1,4 @@
<p><a href="https://piefed.social/"><img src="https://piefed.social/images/PyFedi-logo.png" style="max-width: 100%; margin-bottom: 20px;" width="250" height="48" alt="PieFed logo" /></a></p>
<p><a href="https://piefed.social/"><img src="https://piefed.social/static/images/logo2.png" style="max-width: 100%; margin-bottom: 20px;" width="50" height="50" alt="PieFed logo" /></a></p>
<p>Hello {{ first_name }} and welcome!</p>
<p>I'm Rimu, the founder of PieFed and I'd like to personally thank you for signing up.</p>
<p>As this software is still being developed I need your feedback and ideas for how to improve it. You will notice

View file

@ -9,7 +9,7 @@
</div>
<div class="card-body">
<p>{{ _('The page your browser tried to load could not be found.') }}</p>
<p><a href="#">{{ _('Back') }}</a></p>
<p><a href="#" class="go_back">{{ _('Back') }}</a></p>
</div>
</div>
</div>

View file

@ -8,8 +8,8 @@
<h3 class="card-title">{{ _('An unexpected error has occurred') }}</h3>
</div>
<div class="card-body">
<p>{{ _('Sorry for the inconvenience! Please let us know about this, so we can repair it and make ChoreBuster better for everyone.') }}</p>
<p><a href="#">{{ _('Back') }}</a></p>
<p>{{ _('Sorry for the inconvenience! Please let us know about this, so we can repair it and make PieFed better for everyone.') }}</p>
<p><a href="#" class="go_back">{{ _('Back') }}</a></p>
</div>
</div>
</div>

View file

@ -9,7 +9,7 @@
{% for post in posts %}
{% include 'post/_post_teaser.html' %}
{% else %}
<p>{{ _('No posts yet. Subscribe to some communities to see more.') }}</p>
<p>{{ _('No posts yet. Join some communities to see more.') }}</p>
<p><a class="btn btn-primary" href="/communities">{{ _('Explore communities') }}</a></p>
{% endfor %}
</div>

View file

@ -12,7 +12,7 @@
{{ _('Local') }}
</a>
<a href="/communities/subscribed" class="btn {{ 'btn-primary' if request.path == '/communities/subscribed' else 'btn-outline-secondary' }}">
{{ _('Subscribed') }}
{{ _('Joined') }}
</a>
{% if topics %}
<span class="mt-1 pl-4">
@ -25,7 +25,7 @@
</select>
</form>
</span>
{% endif %}
{% endif %}
</div>
</div>
@ -34,41 +34,42 @@
<a href="{{ url_for('community.add_local') }}" class="btn btn-outline-secondary">{{ _('Create local') }}</a>
<a href="{{ url_for('community.add_remote') }}" class="btn btn-outline-secondary">{{ _('Add remote') }}</a>
</div>
<form method="get" action="/communities">
<!-- <form method="get" action="/communities">
<input name='search' type="search" placeholder="Find a community" class="form-control" value="{{ search }}" />
</form>
</form> -->
</div>
</div>
{% if len(communities) > 0 %}
<div class="table-responsive-md">
<div class="table-responsive-md mt-4">
<table class="communities_table table table-striped table-hover w-100">
<thead>
<tr>
<th scope="col"> </th>
<th scope="col" colspan="2">{{ _('Community') }}</th>
<th scope="col">{{ _('Posts') }}</th>
<th scope="col">{{ _('Comments') }}</th>
<th scope="col">{{ _('Active') }}</th>
<th scope="col">{{ _('Actions') }}</th>
</tr>
</thead>
<tbody>
{% for community in communities %}
<tr class="">
<td width="70">{% if current_user.is_authenticated %}
{% if community_membership(current_user, community) in [SUBSCRIPTION_MEMBER, SUBSCRIPTION_OWNER] %}
<a class="btn btn-primary btn-sm" href="/community/{{ community.link() }}/unsubscribe">{{ _('Leave') }}</a>
{% elif community_membership(current_user, community) == SUBSCRIPTION_PENDING %}
<a class="btn btn-outline-secondary btn-sm" href="/community/{{ community.link() }}/unsubscribe">{{ _('Pending') }}</a>
{% else %}
<a class="btn btn-primary btn-sm" href="/community/{{ community.link() }}/subscribe">{{ _('Join') }}</a>
{% endif %}
{% else %}
<a class="btn btn-primary btn-sm" href="/community/{{ community.link() }}/subscribe">{{ _('Join') }}</a>
{% endif %}</td>
<td width="46"><a href="/c/{{ community.link() }}"><img src="{{ community.icon_image('tiny') }}" class="community_icon rounded-circle" loading="lazy" /></a></td>
<td scope="row" class="pl-0"><a href="/c/{{ community.link() }}">{{ community.display_name() }}</a></td>
<td>{{ community.post_count }}</td>
<td>{{ community.post_reply_count }}</td>
<td>{{ moment(community.last_active).fromNow(refresh=True) }}</td>
<td>{% if current_user.is_authenticated %}
{% if community_membership(current_user, community) in [SUBSCRIPTION_MEMBER, SUBSCRIPTION_OWNER] %}
<a class="btn btn-primary btn-sm" href="/community/{{ community.link() }}/unsubscribe">Unsubscribe</a>
{% elif community_membership(current_user, community) == SUBSCRIPTION_PENDING %}
<a class="btn btn-outline-secondary btn-sm" href="/community/{{ community.link() }}/unsubscribe">Pending</a>
{% else %}
<a class="btn btn-primary btn-sm" href="/community/{{ community.link() }}/subscribe">Subscribe</a>
{% endif %}
{% endif %}
</td>
</tr>
{% endfor %}
</tbody>

View file

@ -14,7 +14,7 @@
</div>
<h1 class="mt-2 post_title">{{ post.title }}</h1>
{% if post.url %}
<p><small><a href="{{ post.url }}" rel="nofollow ugc">{{ post.url|shorten_url }}
<p><small><a href="{{ post.url }}" rel="nofollow ugc" target="_blank">{{ post.url|shorten_url }}
<img src="/static/images/external_link_black.svg" class="external_link_icon" alt="External link" />
</a></small></p>
{% endif %}
@ -28,7 +28,7 @@
<a href="{{ post.image.view_url() }}" rel="nofollow ugc"><img src="{{ post.image.view_url() }}" alt="{{ post.image.alt_text }}"
width="{{ post.image.width }}" height="{{ post.image.height }}" /></a>
{% else %}
<a href="{{ post.url }}" rel="nofollow ugc"><img src="{{ post.url }}" style="max-width: 100%; height: auto;" /></a>
<a href="{{ post.url }}" rel="nofollow ugc" target="_blank"><img src="{{ post.url }}" style="max-width: 100%; height: auto;" /></a>
{% endif %}
</div>
</div>
@ -48,7 +48,7 @@
<h1 class="mt-2 post_title">{{ post.title }}</h1>
{% if post.type == POST_TYPE_LINK and post.image_id and not (post.url and 'youtube.com' in post.url) %}
<div class="url_thumbnail">
<a href="{{ post.url }}"><img src="{{ post.image.thumbnail_url() }}" alt="{{ post.image.alt_text }}"
<a href="{{ post.url }}" target="_blank"><img src="{{ post.image.thumbnail_url() }}" alt="{{ post.image.alt_text }}"
width="{{ post.image.thumbnail_width }}" height="{{ post.image.thumbnail_height }}" /></a>
</div>
{% endif %}
@ -59,7 +59,7 @@
{% if post.edited_at %} edited {{ moment(post.edited_at).fromNow() }}{% endif %}</small>
</p>
{% if post.type == POST_TYPE_LINK %}
<p><small><a href="{{ post.url }}" rel="nofollow ugc">{{ post.url|shorten_url }}
<p><small><a href="{{ post.url }}" rel="nofollow ugc" target="_blank">{{ post.url|shorten_url }}
<img src="/static/images/external_link_black.svg" class="external_link_icon" alt="External link" /></a>
</small></p>
{% if 'youtube.com' in post.url %}
@ -67,12 +67,12 @@
{% endif %}
{% elif post.type == POST_TYPE_IMAGE %}
<div class="post_image">
<a href="{{ post.image.view_url() }}"><img src="{{ post.image.view_url() }}" alt="{{ post.image.alt_text }}"
<a href="{{ post.image.view_url() }}" target="_blank"><img src="{{ post.image.view_url() }}" alt="{{ post.image.alt_text }}"
width="{{ post.image.width }}" height="{{ post.image.height }}" /></a>
</div>
{% else %}
{% if post.image_id and not (post.url and 'youtube.com' in post.url) %}
<a href="{{ post.image.view_url() }}"><img src="{{ post.image.thumbnail_url() }}" alt="{{ post.image.alt_text }}"
<a href="{{ post.image.view_url() }}" target="_blank"><img src="{{ post.image.thumbnail_url() }}" alt="{{ post.image.alt_text }}"
width="{{ post.image.thumbnail_width }}" height="{{ post.image.thumbnail_height }}" /></a>
{% endif %}
{% endif %}

View file

@ -34,9 +34,9 @@
<div class="row">
<div class="col-6">
{% if current_user.is_authenticated and community_membership(current_user, post.community) %}
<a class="w-100 btn btn-primary" href="/community/{{ post.community.link() }}/unsubscribe">{{ _('Unsubscribe') }}</a>
<a class="w-100 btn btn-primary" href="/community/{{ post.community.link() }}/unsubscribe">{{ _('Leave') }}</a>
{% else %}
<a class="w-100 btn btn-primary" href="/community/{{ post.community.link() }}/subscribe">{{ _('Subscribe') }}</a>
<a class="w-100 btn btn-primary" href="/community/{{ post.community.link() }}/subscribe">{{ _('Join') }}</a>
{% endif %}
</div>
<div class="col-6">

View file

@ -64,9 +64,9 @@
<div class="row">
<div class="col-6">
{% if current_user.is_authenticated and community_membership(current_user, post.community) %}
<a class="w-100 btn btn-primary" href="/community/{{ post.community.link() }}/unsubscribe">{{ _('Unsubscribe') }}</a>
<a class="w-100 btn btn-primary" href="/community/{{ post.community.link() }}/unsubscribe">{{ _('Leave') }}</a>
{% else %}
<a class="w-100 btn btn-primary" href="/community/{{ post.community.link() }}/subscribe">{{ _('Subscribe') }}</a>
<a class="w-100 btn btn-primary" href="/community/{{ post.community.link() }}/subscribe">{{ _('Join') }}</a>
{% endif %}
</div>
<div class="col-6">

View file

@ -138,9 +138,9 @@
<div class="row">
<div class="col-6">
{% if current_user.is_authenticated and community_membership(current_user, post.community) %}
<a class="w-100 btn btn-primary" href="/community/{{ post.community.link() }}/unsubscribe">{{ _('Unsubscribe') }}</a>
<a class="w-100 btn btn-primary" href="/community/{{ post.community.link() }}/unsubscribe">{{ _('Leave') }}</a>
{% else %}
<a class="w-100 btn btn-primary" href="/community/{{ post.community.link() }}/subscribe">{{ _('Subscribe') }}</a>
<a class="w-100 btn btn-primary" href="/community/{{ post.community.link() }}/subscribe">{{ _('Join') }}</a>
{% endif %}
</div>
<div class="col-6">

View file

@ -63,7 +63,7 @@
</div>
<div class="card-body">
{% if len(subscribed) > 0 %}
<h4>Subscribed to</h4>
<h4>Member of</h4>
<ul>
{% for community in subscribed %}
<li>

View file

@ -72,6 +72,8 @@
</a>
{% endif %}
</nav>
{% else %}
<p>{{ _('No posts yet.') }}</p>
{% endif %}
{% if post_replies %}
@ -93,6 +95,8 @@
</a>
{% endif %}
</nav>
{% else %}
<p>{{ _('No comments yet.') }}</p>
{% endif %}
</div>
@ -121,10 +125,10 @@
</div>
<div class="card-body">
{% if len(subscribed) > 0 %}
<h4>Subscribed to</h4>
<ul>
<h4>{{ _('Member of') }}</h4>
<ul class="list-group list-group-flush">
{% for community in subscribed %}
<li>
<li class="list-group-item">
<a href="/c/{{ community.link() }}"><img src="{{ community.icon_image() }}" class="community_icon rounded-circle" loading="lazy" />{{ community.display_name() }}</a>
</li>
{% endfor %}
@ -132,9 +136,9 @@
{% endif %}
{% if len(moderates) > 0 %}
<h4>Moderates</h4>
<ul>
<ul class="list-group list-group-flush">
{% for community in moderates %}
<li>
<li class="list-group-item">
<a href="/c/{{ community.link() }}"><img src="{{ community.icon_image() }}" class="community_icon rounded-circle" loading="lazy" />{{ community.display_name() }}</a>
</li>
{% endfor %}

View file

@ -14,7 +14,7 @@ class ProfileForm(FlaskForm):
password_field = PasswordField(_l('Set new password'), validators=[Optional(), Length(min=1, max=50)],
render_kw={"autocomplete": 'Off'})
about = TextAreaField(_l('Bio'), validators=[Optional(), Length(min=3, max=5000)])
matrix_user_id = StringField(_l('Matrix User ID'), validators=[Optional(), Length(max=255)])
matrix_user_id = StringField(_l('Matrix User ID'), validators=[Optional(), Length(max=255)], render_kw={'autocomplete': 'off'})
profile_file = FileField(_('Avatar image'))
banner_file = FileField(_('Top banner image'))
bot = BooleanField(_l('This profile is a bot'))

View file

@ -86,10 +86,11 @@ def edit_profile(actor):
profile_file = request.files['profile_file']
if profile_file and profile_file.filename != '':
# remove old avatar
file = File.query.get(current_user.avatar_id)
file.delete_from_disk()
current_user.avatar_id = None
db.session.delete(file)
if current_user.avatar_id:
file = File.query.get(current_user.avatar_id)
file.delete_from_disk()
current_user.avatar_id = None
db.session.delete(file)
# add new avatar
file = save_icon_file(profile_file, 'users')
@ -98,10 +99,11 @@ def edit_profile(actor):
banner_file = request.files['banner_file']
if banner_file and banner_file.filename != '':
# remove old cover
file = File.query.get(current_user.cover_id)
file.delete_from_disk()
current_user.cover_id = None
db.session.delete(file)
if current_user.cover_id:
file = File.query.get(current_user.cover_id)
file.delete_from_disk()
current_user.cover_id = None
db.session.delete(file)
# add new cover
file = save_banner_file(banner_file, 'users')