add follow on mastodon button #2

This commit is contained in:
rimu 2024-05-12 14:16:12 +12:00
parent acb108b292
commit 850e159a58
6 changed files with 115 additions and 8 deletions

View file

@ -8,7 +8,7 @@ from app.utils import MultiCheckboxField
class NewReplyForm(FlaskForm): class NewReplyForm(FlaskForm):
body = TextAreaField(_l('Body'), render_kw={'placeholder': 'What are your thoughts?', 'rows': 5}, validators={DataRequired(), Length(min=1, max=5000)}) body = TextAreaField(_l('Body'), render_kw={'placeholder': 'What are your thoughts?', 'rows': 5}, validators=[DataRequired(), Length(min=1, max=5000)])
notify_author = BooleanField(_l('Notify about replies')) notify_author = BooleanField(_l('Notify about replies'))
language_id = SelectField(_l('Language'), validators=[DataRequired()], coerce=int, render_kw={'class': 'form-select language-float-right'}) language_id = SelectField(_l('Language'), validators=[DataRequired()], coerce=int, render_kw={'class': 'form-select language-float-right'})
submit = SubmitField(_l('Comment')) submit = SubmitField(_l('Comment'))

View file

@ -632,6 +632,20 @@ function setupMarkdownEditorEnabler() {
}); });
} }
function getCookie(name) {
var cookies = document.cookie.split(';');
for (var i = 0; i < cookies.length; i++) {
var cookie = cookies[i].trim();
if (cookie.indexOf(name + '=') === 0) {
return cookie.substring(name.length + 1);
}
}
return null;
}
/* register a service worker */ /* register a service worker */
if ('serviceWorker' in navigator) { if ('serviceWorker' in navigator) {
window.addEventListener('load', function() { window.addEventListener('load', function() {

View file

@ -0,0 +1,64 @@
{% if theme() and file_exists('app/templates/themes/' + theme() + '/base.html') %}
{% extends 'themes/' + theme() + '/base.html' %}
{% else %}
{% extends "base.html" %}
{% endif %} %}
{% from 'bootstrap/form.html' import render_form %}
{% set active_child = 'settings' %}
{% block app_content %}
<div class="row">
<div class="col-12 col-md-8 position-relative main_pane">
<nav class="mb-2" aria-label="breadcrumb" id="breadcrumb_nav" title="Navigation">
<ol class="breadcrumb">
<li class="breadcrumb-item"><a href="/">{{ _('Home') }}</a></li>
<li class="breadcrumb-item"><a href="/u/{{ user.link() }}">{{ user.display_name() }}</a></li>
<li class="breadcrumb-item active">{{ _('Follow on Mastodon') }}</li>
</ol>
</nav>
<h1>{{ _('Follow on Mastodon') }}</h1>
<p>{{ _('We are about to send you to your mastodon instance where you will then need to click the "Follow" button.') }}</p>
{{ render_form(form) }}
{% if send_to %}
<div id="redirectMessage"></div>
<script defer nonce="{{ session['nonce'] }}">
window.addEventListener("load", function () {
var redirectTimeout;
var cookieName = "mastodon_instance_url";
var redirectURL = getCookie(cookieName);
if (redirectURL) {
var redirectMessageDiv = document.getElementById('redirectMessage');
// Add message to the div
redirectMessageDiv.textContent = "Redirecting to: " + redirectURL + " in 5 seconds...";
// Cancel button
var cancelButton = document.createElement('button');
cancelButton.textContent = "Cancel";
cancelButton.addEventListener('click', cancelRedirect);
// Append cancel button to the div
redirectMessageDiv.appendChild(cancelButton);
// Set timeout and store the timeout ID
redirectTimeout = setTimeout(function() {
window.location.href = 'https://' + redirectURL + '/@{{ user.link() }}@{{ current_app.config["SERVER_NAME"] }}';
}, 5000);
}
// Function to cancel redirect
function cancelRedirect() {
// Clear the timeout
clearTimeout(redirectTimeout);
var redirectMessageDiv = document.getElementById('redirectMessage');
redirectMessageDiv.textContent = "Redirect cancelled.";
}
});
</script>
{% endif %}
</div>
</div>
{% endblock %}

View file

@ -64,8 +64,8 @@
{% endif %} {% endif %}
</h1> </h1>
{% endif %} {% endif %}
<div class="profile_action_buttons">
{% if current_user.is_authenticated and current_user != user %} {% if current_user.is_authenticated and current_user != user %}
<div class="profile_action_buttons">
<a class="btn btn-primary" href="{{ url_for('chat.new_message', to=user.id) }}" rel="nofollow" aria-label="{{ _('Send message') }}">{{ _('Send message') }}</a> <a class="btn btn-primary" href="{{ url_for('chat.new_message', to=user.id) }}" rel="nofollow" aria-label="{{ _('Send message') }}">{{ _('Send message') }}</a>
{% if user.matrix_user_id %} {% if user.matrix_user_id %}
<a class="btn btn-primary" href="https://matrix.to/#/{{ user.matrix_user_id }}" rel="nofollow" aria-label="{{ _('Send message with matrix chat') }}">{{ _('Send message using Matrix') }}</a> <a class="btn btn-primary" href="https://matrix.to/#/{{ user.matrix_user_id }}" rel="nofollow" aria-label="{{ _('Send message with matrix chat') }}">{{ _('Send message using Matrix') }}</a>
@ -76,8 +76,12 @@
<a class="btn btn-primary confirm_first" href="{{ url_for('user.block_profile', actor=user.link()) }}" rel="nofollow">{{ _('Block') }}</a> <a class="btn btn-primary confirm_first" href="{{ url_for('user.block_profile', actor=user.link()) }}" rel="nofollow">{{ _('Block') }}</a>
{% endif %} {% endif %}
<a class="btn btn-primary" href="{{ url_for('user.report_profile', actor=user.link()) }}" rel="nofollow">{{ _('Report') }}</a> <a class="btn btn-primary" href="{{ url_for('user.report_profile', actor=user.link()) }}" rel="nofollow">{{ _('Report') }}</a>
</div>
{% endif %} {% endif %}
{% if user.is_local() %}
<a class="btn btn-primary" href="{{ url_for('user.mastodon_redirect', actor=user.link()) }}" rel="nofollow">{{ _('Follow on Mastodon') }}</a>
{% endif %}
</div>
<p class="small">{{ _('Joined') }}: {{ moment(user.created).fromNow(refresh=True) }}<br /> <p class="small">{{ _('Joined') }}: {{ moment(user.created).fromNow(refresh=True) }}<br />
{% if user.bot %} {% if user.bot %}
{{ _('Bot Account') }}<br /> {{ _('Bot Account') }}<br />

View file

@ -88,14 +88,20 @@ class ReportUserForm(FlaskForm):
class FilterEditForm(FlaskForm): class FilterEditForm(FlaskForm):
title = StringField(_l('Name'), validators={DataRequired(), Length(min=3, max=50)}) title = StringField(_l('Name'), validators=[DataRequired(), Length(min=3, max=50)])
filter_home = BooleanField(_l('Home feed'), default=True) filter_home = BooleanField(_l('Home feed'), default=True)
filter_posts = BooleanField(_l('Posts in communities')) filter_posts = BooleanField(_l('Posts in communities'))
filter_replies = BooleanField(_l('Comments on posts')) filter_replies = BooleanField(_l('Comments on posts'))
hide_type_choices = [(0, _l('Make semi-transparent')), (1, _l('Hide completely'))] hide_type_choices = [(0, _l('Make semi-transparent')), (1, _l('Hide completely'))]
hide_type = RadioField(_l('Action to take'), choices=hide_type_choices, default=1, coerce=int) hide_type = RadioField(_l('Action to take'), choices=hide_type_choices, default=1, coerce=int)
keywords = TextAreaField(_l('Keywords that trigger this filter'), keywords = TextAreaField(_l('Keywords that trigger this filter'),
render_kw={'placeholder': 'One keyword or phrase per line', 'rows': 3}, render_kw={'placeholder': 'One keyword or phrase per line', 'rows': 3},
validators={DataRequired(), Length(min=3, max=500)}) validators=[DataRequired(), Length(min=3, max=500)])
expire_after = DateField(_l('Expire after'), validators={Optional()}) expire_after = DateField(_l('Expire after'), validators=[Optional()])
submit = SubmitField(_l('Save')) submit = SubmitField(_l('Save'))
class FollowOnMastodonForm(FlaskForm):
instance_url = StringField(_l('Your mastodon instance:'), validators=[DataRequired(), Length(min=3, max=50)],
render_kw={'placeholder': 'e.g. mastodon.social'})
submit = SubmitField(_l('View profile in Mastodon'))

View file

@ -14,7 +14,8 @@ from app.models import Post, Community, CommunityMember, User, PostReply, PostVo
Instance, Report, UserBlock, CommunityBan, CommunityJoinRequest, CommunityBlock, Filter, Domain, DomainBlock, \ Instance, Report, UserBlock, CommunityBan, CommunityJoinRequest, CommunityBlock, Filter, Domain, DomainBlock, \
InstanceBlock, NotificationSubscription InstanceBlock, NotificationSubscription
from app.user import bp from app.user import bp
from app.user.forms import ProfileForm, SettingsForm, DeleteAccountForm, ReportUserForm, FilterEditForm from app.user.forms import ProfileForm, SettingsForm, DeleteAccountForm, ReportUserForm, FilterEditForm, \
FollowOnMastodonForm
from app.user.utils import purge_user_then_delete, unsubscribe_from_community from app.user.utils import purge_user_then_delete, unsubscribe_from_community
from app.utils import get_setting, render_template, markdown_to_html, user_access, markdown_to_text, shorten_string, \ from app.utils import get_setting, render_template, markdown_to_html, user_access, markdown_to_text, shorten_string, \
is_image_url, ensure_directory_exists, gibberish, file_get_contents, community_membership, user_filters_home, \ is_image_url, ensure_directory_exists, gibberish, file_get_contents, community_membership, user_filters_home, \
@ -804,3 +805,21 @@ def user_email_notifs_unsubscribe(user_id, token):
user.email_unread = False user.email_unread = False
db.session.commit() db.session.commit()
return render_template('user/email_notifs_unsubscribed.html') return render_template('user/email_notifs_unsubscribed.html')
@bp.route('/u/<actor>/mastodon_redirect', methods=['GET', 'POST'])
def mastodon_redirect(actor):
actor = actor.strip()
user = User.query.filter_by(user_name=actor, deleted=False).first()
if user and user.is_local():
form = FollowOnMastodonForm()
if form.validate_on_submit():
resp = make_response(redirect(f'https://{form.instance_url.data}/@{user.user_name}@{current_app.config["SERVER_NAME"]}'))
resp.set_cookie('mastodon_instance_url', form.instance_url.data, expires=datetime(year=2099, month=12, day=30))
return resp
else:
send_to = ''
if request.cookies.get('mastodon_instance_url'):
send_to = request.cookies.get('mastodon_instance_url')
form.instance_url.data = send_to
return render_template('user/mastodon_redirect.html', form=form, user=user, send_to=send_to, current_app=current_app)