admin can send email newsletters

This commit is contained in:
rimu 2024-02-24 20:01:38 +13:00
parent 6da762b8d6
commit 8657699388
8 changed files with 90 additions and 4 deletions

View file

@ -113,3 +113,11 @@ class EditUserForm(FlaskForm):
indexable = BooleanField(_l('Allow search engines to index this profile')) indexable = BooleanField(_l('Allow search engines to index this profile'))
manually_approves_followers = BooleanField(_l('Manually approve followers')) manually_approves_followers = BooleanField(_l('Manually approve followers'))
submit = SubmitField(_l('Save')) submit = SubmitField(_l('Save'))
class SendNewsletterForm(FlaskForm):
subject = StringField(_l('Subject'), validators=[DataRequired()])
body_text = TextAreaField(_l('Body (text)'), render_kw={"rows": 10}, validators=[DataRequired()])
body_html = TextAreaField(_l('Body (html)'), render_kw={"rows": 20}, validators=[DataRequired()])
test = BooleanField(_l('Test mode'), render_kw={'checked': True})
submit = SubmitField(_l('Send newsletter'))

View file

@ -11,8 +11,8 @@ from app.activitypub.routes import process_inbox_request, process_delete_request
from app.activitypub.signature import post_request from app.activitypub.signature import post_request
from app.activitypub.util import default_context from app.activitypub.util import default_context
from app.admin.forms import FederationForm, SiteMiscForm, SiteProfileForm, EditCommunityForm, EditUserForm, \ from app.admin.forms import FederationForm, SiteMiscForm, SiteProfileForm, EditCommunityForm, EditUserForm, \
EditTopicForm EditTopicForm, SendNewsletterForm
from app.admin.util import unsubscribe_from_everything_then_delete, unsubscribe_from_community from app.admin.util import unsubscribe_from_everything_then_delete, unsubscribe_from_community, send_newsletter
from app.community.util import save_icon_file, save_banner_file from app.community.util import save_icon_file, save_banner_file
from app.models import AllowedInstances, BannedInstances, ActivityPubLog, utcnow, Site, Community, CommunityMember, \ from app.models import AllowedInstances, BannedInstances, ActivityPubLog, utcnow, Site, Community, CommunityMember, \
User, Instance, File, Report, Topic, UserRegistration User, Instance, File, Report, Topic, UserRegistration
@ -596,4 +596,21 @@ def admin_reports():
moderating_communities=moderating_communities(current_user.get_id()), moderating_communities=moderating_communities(current_user.get_id()),
joined_communities=joined_communities(current_user.get_id()), joined_communities=joined_communities(current_user.get_id()),
site=g.site site=g.site
) )
@bp.route('/newsletter', methods=['GET', 'POST'])
@login_required
@permission_required('administer all users')
def newsletter():
form = SendNewsletterForm()
if form.validate_on_submit():
send_newsletter(form)
flash('Newsletter sent')
return redirect(url_for('admin.newsletter'))
return render_template("admin/newsletter.html", form=form, title=_('Send newsletter'),
moderating_communities=moderating_communities(current_user.get_id()),
joined_communities=joined_communities(current_user.get_id()),
site=g.site
)

View file

@ -1,4 +1,7 @@
from flask import request, abort, g, current_app, json from flask import request, abort, g, current_app, json, flash, render_template
from flask_login import current_user
from sqlalchemy import text, desc
from app import db, cache, celery from app import db, cache, celery
from app.activitypub.signature import post_request from app.activitypub.signature import post_request
from app.activitypub.util import default_context from app.activitypub.util import default_context
@ -70,3 +73,31 @@ def unsubscribe_from_community(community, user):
post_request(community.ap_inbox_url, undo, user.private_key, user.profile_id() + '#main-key') post_request(community.ap_inbox_url, undo, user.private_key, user.profile_id() + '#main-key')
activity.result = 'success' activity.result = 'success'
db.session.commit() db.session.commit()
def send_newsletter(form):
recipients = User.query.filter(User.newsletter == True, User.banned == False, User.ap_id == None).order_by(desc(User.id)).limit(40000)
from app.email import send_email
if recipients.count() == 0:
flash('No recipients', 'error')
for recipient in recipients:
body_text = render_template('email/newsletter.txt',
recipient=recipient if not form.test.data else current_user,
content=form.body_text.data)
body_html = render_template('email/newsletter.html',
recipient=recipient if not form.test.data else current_user,
content=form.body_html.data,
domain=current_app.config['SERVER_NAME'])
if form.test.data:
to = current_user.email
else:
to = recipient.email
send_email(subject=form.subject.data, sender=f'{g.site.name} <noreply@{current_app.config["SERVER_NAME"]}>', recipients=[to],
text_body=body_text, html_body=body_html)
if form.test.data:
break

View file

@ -10,5 +10,6 @@
{% endif %} {% endif %}
<a href="{{ url_for('admin.admin_reports') }}">{{ _('Moderation') }}</a> | <a href="{{ url_for('admin.admin_reports') }}">{{ _('Moderation') }}</a> |
<a href="{{ url_for('admin.admin_federation') }}">{{ _('Federation') }}</a> | <a href="{{ url_for('admin.admin_federation') }}">{{ _('Federation') }}</a> |
<a href="{{ url_for('admin.newsletter') }}">{{ _('Newsletter') }}</a> |
<a href="{{ url_for('admin.admin_activities') }}">{{ _('Activities') }}</a> <a href="{{ url_for('admin.admin_activities') }}">{{ _('Activities') }}</a>
</nav> </nav>

View file

@ -0,0 +1,17 @@
{% extends "base.html" %}
{% from 'bootstrap/form.html' import render_form %}
{% block app_content %}
<div class="row">
<div class="col">
{% include 'admin/_nav.html' %}
</div>
</div>
<div class="row">
<div class="col">
{{ render_form(form) }}
</div>
</div>
{% endblock %}

View file

@ -0,0 +1,5 @@
<p><a href="https://{{ domain }}/"><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 {{ recipient.display_name() }},</p>
{{ content|safe }}
<p>&nbsp;</p>
<p><small><a href="{{ url_for('user.user_newsletter_unsubscribe', user_id=recipient.id, token=recipient.verification_token, _external=True) }}">Unsubscribe from PieFed newsletter</a></small></p>

View file

@ -0,0 +1,6 @@
Hello {{ recipient.display_name() }},</p>
{{ content }}
Unsubscribe from PieFed newsletter at {{ url_for('user.user_newsletter_unsubscribe', user_id=recipient.id, token=recipient.verification_token, _external=True) }}.

View file

@ -17,3 +17,4 @@ Warm regards,
Rimu Atkinson Rimu Atkinson
Founder Founder
Unsubscribe from PieFed newsletter at {{ url_for('user.user_newsletter_unsubscribe', user_id=user.id, token=user.verification_token, _external=True) }}.