feat: Add "Post to Fediverse"
This commit is contained in:
		@@ -8,7 +8,7 @@ from django.urls import reverse
 | 
				
			|||||||
from django.utils.http import urlencode
 | 
					from django.utils.http import urlencode
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from .models import User, Language, Text, ReportComment, ReportAdoptionNotice, Log, Timestamp, SearchSubscription, \
 | 
					from .models import User, Language, Text, ReportComment, ReportAdoptionNotice, Log, Timestamp, SearchSubscription, \
 | 
				
			||||||
    SpeciesSpecificURL, ImportantLocation
 | 
					    SpeciesSpecificURL, ImportantLocation, SocialMediaPost
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from .models import Animal, Species, RescueOrganization, AdoptionNotice, Location, Rule, Image, ModerationAction, \
 | 
					from .models import Animal, Species, RescueOrganization, AdoptionNotice, Location, Rule, Image, ModerationAction, \
 | 
				
			||||||
    Comment, Report, Announcement, AdoptionNoticeStatus, User, Subscriptions, Notification
 | 
					    Comment, Report, Announcement, AdoptionNoticeStatus, User, Subscriptions, Notification
 | 
				
			||||||
@@ -162,6 +162,9 @@ class LocationAdmin(admin.ModelAdmin):
 | 
				
			|||||||
        ImportantLocationInline,
 | 
					        ImportantLocationInline,
 | 
				
			||||||
    ]
 | 
					    ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@admin.register(SocialMediaPost)
 | 
				
			||||||
 | 
					class SocialMediaPostAdmin(admin.ModelAdmin):
 | 
				
			||||||
 | 
					    list_filter = ("platform",)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
admin.site.register(Animal)
 | 
					admin.site.register(Animal)
 | 
				
			||||||
admin.site.register(Species)
 | 
					admin.site.register(Species)
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										25
									
								
								src/fellchensammlung/migrations/0058_socialmediapost.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								src/fellchensammlung/migrations/0058_socialmediapost.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,25 @@
 | 
				
			|||||||
 | 
					# Generated by Django 5.2.1 on 2025-07-19 17:48
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import django.db.models.deletion
 | 
				
			||||||
 | 
					import django.utils.timezone
 | 
				
			||||||
 | 
					from django.db import migrations, models
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Migration(migrations.Migration):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    dependencies = [
 | 
				
			||||||
 | 
					        ('fellchensammlung', '0057_delete_speciesspecialization'),
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    operations = [
 | 
				
			||||||
 | 
					        migrations.CreateModel(
 | 
				
			||||||
 | 
					            name='SocialMediaPost',
 | 
				
			||||||
 | 
					            fields=[
 | 
				
			||||||
 | 
					                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
 | 
				
			||||||
 | 
					                ('created_at', models.DateField(default=django.utils.timezone.now, verbose_name='Erstellt am')),
 | 
				
			||||||
 | 
					                ('platform', models.CharField(choices=[('fediverse', 'Fediverse')], max_length=255, verbose_name='Social Media Platform')),
 | 
				
			||||||
 | 
					                ('url', models.URLField(verbose_name='URL')),
 | 
				
			||||||
 | 
					                ('adoption_notice', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='fellchensammlung.adoptionnotice', verbose_name='Vermittlung')),
 | 
				
			||||||
 | 
					            ],
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
@@ -475,7 +475,6 @@ class AdoptionNotice(models.Model):
 | 
				
			|||||||
            return False
 | 
					            return False
 | 
				
			||||||
        return self.adoptionnoticestatus.is_disabled
 | 
					        return self.adoptionnoticestatus.is_disabled
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
    @property
 | 
					    @property
 | 
				
			||||||
    def is_closed(self):
 | 
					    def is_closed(self):
 | 
				
			||||||
        if not hasattr(self, 'adoptionnoticestatus'):
 | 
					        if not hasattr(self, 'adoptionnoticestatus'):
 | 
				
			||||||
@@ -516,6 +515,14 @@ class AdoptionNotice(models.Model):
 | 
				
			|||||||
                                        text=text,
 | 
					                                        text=text,
 | 
				
			||||||
                                        title=notification_title)
 | 
					                                        title=notification_title)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def last_posted(self, platform=None):
 | 
				
			||||||
 | 
					        if platform is None:
 | 
				
			||||||
 | 
					            last_post = SocialMediaPost.objects.filter(adoption_notice=self).order_by('-created_at').first()
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            last_post = SocialMediaPost.objects.filter(adoption_notice=self, platform=platform).order_by(
 | 
				
			||||||
 | 
					                '-created_at').first()
 | 
				
			||||||
 | 
					        return last_post.created_at
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class AdoptionNoticeStatus(models.Model):
 | 
					class AdoptionNoticeStatus(models.Model):
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
@@ -1038,3 +1045,24 @@ class SpeciesSpecificURL(models.Model):
 | 
				
			|||||||
    rescue_organization = models.ForeignKey(RescueOrganization, on_delete=models.CASCADE,
 | 
					    rescue_organization = models.ForeignKey(RescueOrganization, on_delete=models.CASCADE,
 | 
				
			||||||
                                            verbose_name=_("Tierschutzorganisation"))
 | 
					                                            verbose_name=_("Tierschutzorganisation"))
 | 
				
			||||||
    url = models.URLField(verbose_name=_("Tierartspezifische URL"))
 | 
					    url = models.URLField(verbose_name=_("Tierartspezifische URL"))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class PlatformChoices(models.TextChoices):
 | 
				
			||||||
 | 
					    FEDIVERSE = "fediverse", _("Fediverse")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class SocialMediaPost(models.Model):
 | 
				
			||||||
 | 
					    created_at = models.DateField(verbose_name=_('Erstellt am'), default=timezone.now)
 | 
				
			||||||
 | 
					    platform = models.CharField(max_length=255, verbose_name=_("Social Media Platform"),
 | 
				
			||||||
 | 
					                                choices=PlatformChoices.choices)
 | 
				
			||||||
 | 
					    adoption_notice = models.ForeignKey(AdoptionNotice, on_delete=models.CASCADE, verbose_name=_('Vermittlung'))
 | 
				
			||||||
 | 
					    url = models.URLField(verbose_name=_("URL"))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @staticmethod
 | 
				
			||||||
 | 
					    def get_an_to_post():
 | 
				
			||||||
 | 
					        adoption_notices_without_post = AdoptionNotice.objects.filter(socialmediapost__isnull=True,
 | 
				
			||||||
 | 
					                                                                      adoptionnoticestatus__major_status=AdoptionNoticeStatus.ACTIVE)
 | 
				
			||||||
 | 
					        return adoption_notices_without_post.first()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __str__(self):
 | 
				
			||||||
 | 
					        return f"{self.platform} - {self.adoption_notice}"
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -0,0 +1,14 @@
 | 
				
			|||||||
 | 
					{% extends "fellchensammlung/base.html" %}
 | 
				
			||||||
 | 
					{% load i18n %}
 | 
				
			||||||
 | 
					{% load custom_tags %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					{% block title %}<title>{% translate "403 Forbidden" %}</title>{% endblock %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					{% block content %}
 | 
				
			||||||
 | 
					    <h1 class="title is-1">404 Not Found</h1>
 | 
				
			||||||
 | 
					    <p>
 | 
				
			||||||
 | 
					    {% blocktranslate %}
 | 
				
			||||||
 | 
					    	Diese Seite existiert nicht.
 | 
				
			||||||
 | 
					    {% endblocktranslate %}
 | 
				
			||||||
 | 
					    </p>
 | 
				
			||||||
 | 
					{% endblock %}
 | 
				
			||||||
@@ -7,13 +7,52 @@
 | 
				
			|||||||
    <div class="block">
 | 
					    <div class="block">
 | 
				
			||||||
        <h1 class="title is-1">{% translate 'Moderationstools' %}</h1>
 | 
					        <h1 class="title is-1">{% translate 'Moderationstools' %}</h1>
 | 
				
			||||||
        <div class="block">
 | 
					        <div class="block">
 | 
				
			||||||
            <a class="button is-primary is-fullwidth" href="{% url 'modqueue' %}">{% translate 'Moderationswarteschlange' %}</a>
 | 
					            <a class="button is-primary is-fullwidth"
 | 
				
			||||||
 | 
					               href="{% url 'modqueue' %}">{% translate 'Moderationswarteschlange' %}</a>
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
        <div class="block">
 | 
					        <div class="block">
 | 
				
			||||||
            <a class="button is-primary is-fullwidth" href="{% url 'updatequeue' %}">{% translate 'Up-To-Date Check' %}</a>
 | 
					            <a class="button is-primary is-fullwidth"
 | 
				
			||||||
 | 
					               href="{% url 'updatequeue' %}">{% translate 'Up-To-Date Check' %}</a>
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
        <div class="block">
 | 
					        <div class="block">
 | 
				
			||||||
            <a class="button is-primary is-fullwidth" href="{% url 'organization-check' %}">{% translate 'Organisations Check' %}</a>
 | 
					            <a class="button is-primary is-fullwidth"
 | 
				
			||||||
 | 
					               href="{% url 'organization-check' %}">{% translate 'Organisations Check' %}</a>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        <div class="block">
 | 
				
			||||||
 | 
					            {% if action_was_posting %}
 | 
				
			||||||
 | 
					                {% if posted_successfully %}
 | 
				
			||||||
 | 
					                    <div class="message is-success">
 | 
				
			||||||
 | 
					                        <div class="message-header">
 | 
				
			||||||
 | 
					                            {% translate 'Vermittlung gepostet' %}
 | 
				
			||||||
 | 
					                        </div>
 | 
				
			||||||
 | 
					                        <div class="message-body">
 | 
				
			||||||
 | 
					                            {% blocktranslate with post_url=post.url %}
 | 
				
			||||||
 | 
					                                Link zum Post: <a href={{ post_url }}>{{ post_url }}</a>
 | 
				
			||||||
 | 
					                            {% endblocktranslate %}
 | 
				
			||||||
 | 
					                        </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    </div>
 | 
				
			||||||
 | 
					                {% else %}
 | 
				
			||||||
 | 
					                    <div class="message is-danger">
 | 
				
			||||||
 | 
					                        <div class="message-header">
 | 
				
			||||||
 | 
					                            {% translate 'Vermittlung konnte nicht gepostet werden' %}
 | 
				
			||||||
 | 
					                        </div>
 | 
				
			||||||
 | 
					                        <div class="message-body">
 | 
				
			||||||
 | 
					                            {{ error_message }}
 | 
				
			||||||
 | 
					                        </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    </div>
 | 
				
			||||||
 | 
					                {% endif %}
 | 
				
			||||||
 | 
					            {% endif %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            <form class="cell" method="post">
 | 
				
			||||||
 | 
					                {% csrf_token %}
 | 
				
			||||||
 | 
					                <input type="hidden" name="action" value="post_to_fedi">
 | 
				
			||||||
 | 
					                <button class="button is-fullwidth is-warning is-primary" type="submit" id="submit">
 | 
				
			||||||
 | 
					                    <i class="fa-solid fa-bullhorn fa-fw"></i> {% translate "Vermittlung ins Fediverse posten" %}
 | 
				
			||||||
 | 
					                </button>
 | 
				
			||||||
 | 
					            </form>
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										95
									
								
								src/fellchensammlung/tools/fedi.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										95
									
								
								src/fellchensammlung/tools/fedi.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,95 @@
 | 
				
			|||||||
 | 
					import logging
 | 
				
			||||||
 | 
					import requests
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from fellchensammlung.models import SocialMediaPost, PlatformChoices
 | 
				
			||||||
 | 
					from notfellchen import settings
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class FediClient:
 | 
				
			||||||
 | 
					    def __init__(self, access_token, api_base_url):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        :param access_token: Your server API access token.
 | 
				
			||||||
 | 
					        :param api_base_url: The base URL of the Fediverse instance (e.g., 'https://gay-pirate-assassins.de').
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        self.access_token = access_token
 | 
				
			||||||
 | 
					        self.api_base_url = api_base_url.rstrip('/')
 | 
				
			||||||
 | 
					        self.headers = {
 | 
				
			||||||
 | 
					            'Authorization': f'Bearer {self.access_token}',
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def upload_media(self, image_path, alt_text):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Uploads media (image) to the server and returns the media ID.
 | 
				
			||||||
 | 
					        :param image_path: Path to the image file to upload.
 | 
				
			||||||
 | 
					        :param alt_text: Description (alt text) for the image.
 | 
				
			||||||
 | 
					        :return: The media ID of the uploaded image.
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        media_endpoint = f'{self.api_base_url}/api/v2/media'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        with open(image_path, 'rb') as image_file:
 | 
				
			||||||
 | 
					            files = {
 | 
				
			||||||
 | 
					                'file': image_file,
 | 
				
			||||||
 | 
					                'description': (None, alt_text)
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            response = requests.post(media_endpoint, headers=self.headers, files=files)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            # Raise exception if upload fails
 | 
				
			||||||
 | 
					            response.raise_for_status()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Parse and return the media ID from the response
 | 
				
			||||||
 | 
					        media_id = response.json().get('id')
 | 
				
			||||||
 | 
					        return media_id
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def post_status(self, status, media_ids=None):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Posts a status to Mastodon with optional media.
 | 
				
			||||||
 | 
					        :param status: The text of the status to post.
 | 
				
			||||||
 | 
					        :param media_ids: A list of media IDs to attach to the status (optional).
 | 
				
			||||||
 | 
					        :return: The response from the Mastodon API.
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        status_endpoint = f'{self.api_base_url}/api/v1/statuses'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        payload = {
 | 
				
			||||||
 | 
					            'status': status,
 | 
				
			||||||
 | 
					            'media_ids[]': media_ids if media_ids else []
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        response = requests.post(status_endpoint, headers=self.headers, data=payload)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Raise exception if posting fails
 | 
				
			||||||
 | 
					        response.raise_for_status()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return response.json()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def post_status_with_images(self, status, images):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Uploads one or more image, then posts a status with that images and alt text.
 | 
				
			||||||
 | 
					        :param status: The text of the status.
 | 
				
			||||||
 | 
					        :param image_paths: The paths to the image file.
 | 
				
			||||||
 | 
					        :param alt_text: The alt text for the image.
 | 
				
			||||||
 | 
					        :return: The response from the Mastodon API.
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        media_ids = []
 | 
				
			||||||
 | 
					        for image in images:
 | 
				
			||||||
 | 
					            # Upload the image and get the media ID
 | 
				
			||||||
 | 
					            media_ids = self.upload_media(f"{settings.MEDIA_ROOT}/{image.image}", image.alt_text)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Post the status with the uploaded image's media ID
 | 
				
			||||||
 | 
					        return self.post_status(status, media_ids=media_ids)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def post_an_to_fedi(adoption_notice):
 | 
				
			||||||
 | 
					    client = FediClient(settings.fediverse_access_token, settings.fediverse_api_base_url)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    status_text = adoption_notice.name
 | 
				
			||||||
 | 
					    images = adoption_notice.get_photos()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if images is not None:
 | 
				
			||||||
 | 
					        response = client.post_status_with_images(status_text, images)
 | 
				
			||||||
 | 
					    else:
 | 
				
			||||||
 | 
					        response = client.post_status(status_text)
 | 
				
			||||||
 | 
					    logging.info(response)
 | 
				
			||||||
 | 
					    post = SocialMediaPost.objects.create(adoption_notice=adoption_notice,
 | 
				
			||||||
 | 
					                                          platform=PlatformChoices.FEDIVERSE,
 | 
				
			||||||
 | 
					                                          url=response['url'], )
 | 
				
			||||||
 | 
					    return post
 | 
				
			||||||
@@ -14,6 +14,7 @@ from django.contrib.auth.decorators import user_passes_test
 | 
				
			|||||||
from django.core.serializers import serialize
 | 
					from django.core.serializers import serialize
 | 
				
			||||||
from django.utils.translation import gettext_lazy as _
 | 
					from django.utils.translation import gettext_lazy as _
 | 
				
			||||||
import json
 | 
					import json
 | 
				
			||||||
 | 
					import requests
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from .mail import notify_mods_new_report
 | 
					from .mail import notify_mods_new_report
 | 
				
			||||||
from notfellchen import settings
 | 
					from notfellchen import settings
 | 
				
			||||||
@@ -22,11 +23,12 @@ from fellchensammlung import logger
 | 
				
			|||||||
from .models import AdoptionNotice, Text, Animal, Rule, Image, Report, ModerationAction, \
 | 
					from .models import AdoptionNotice, Text, Animal, Rule, Image, Report, ModerationAction, \
 | 
				
			||||||
    User, Location, AdoptionNoticeStatus, Subscriptions, Notification, RescueOrganization, \
 | 
					    User, Location, AdoptionNoticeStatus, Subscriptions, Notification, RescueOrganization, \
 | 
				
			||||||
    Species, Log, Timestamp, TrustLevel, SexChoicesWithAll, SearchSubscription, \
 | 
					    Species, Log, Timestamp, TrustLevel, SexChoicesWithAll, SearchSubscription, \
 | 
				
			||||||
    ImportantLocation, SpeciesSpecificURL, NotificationTypeChoices
 | 
					    ImportantLocation, SpeciesSpecificURL, NotificationTypeChoices, SocialMediaPost
 | 
				
			||||||
from .forms import AdoptionNoticeForm, ImageForm, ReportAdoptionNoticeForm, \
 | 
					from .forms import AdoptionNoticeForm, ImageForm, ReportAdoptionNoticeForm, \
 | 
				
			||||||
    CommentForm, ReportCommentForm, AnimalForm, AdoptionNoticeFormAutoAnimal, SpeciesURLForm, RescueOrgInternalComment
 | 
					    CommentForm, ReportCommentForm, AnimalForm, AdoptionNoticeFormAutoAnimal, SpeciesURLForm, RescueOrgInternalComment
 | 
				
			||||||
from .models import Language, Announcement
 | 
					from .models import Language, Announcement
 | 
				
			||||||
from .tools import i18n
 | 
					from .tools import i18n
 | 
				
			||||||
 | 
					from .tools.fedi import post_an_to_fedi
 | 
				
			||||||
from .tools.geo import GeoAPI, zoom_level_for_radius
 | 
					from .tools.geo import GeoAPI, zoom_level_for_radius
 | 
				
			||||||
from .tools.metrics import gather_metrics_data
 | 
					from .tools.metrics import gather_metrics_data
 | 
				
			||||||
from .tools.admin import clean_locations, get_unchecked_adoption_notices, deactivate_unchecked_adoption_notices, \
 | 
					from .tools.admin import clean_locations, get_unchecked_adoption_notices, deactivate_unchecked_adoption_notices, \
 | 
				
			||||||
@@ -864,7 +866,31 @@ def rescue_organization_check_dq(request):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
@user_passes_test(user_is_trust_level_or_above)
 | 
					@user_passes_test(user_is_trust_level_or_above)
 | 
				
			||||||
def moderation_tools_overview(request):
 | 
					def moderation_tools_overview(request):
 | 
				
			||||||
    return render(request, 'fellchensammlung/mod-tool-overview.html')
 | 
					    context = None
 | 
				
			||||||
 | 
					    if request.method == "POST":
 | 
				
			||||||
 | 
					        action = request.POST.get("action")
 | 
				
			||||||
 | 
					        if action == "post_to_fedi":
 | 
				
			||||||
 | 
					            adoption_notice = SocialMediaPost.get_an_to_post()
 | 
				
			||||||
 | 
					            if adoption_notice is not None:
 | 
				
			||||||
 | 
					                try:
 | 
				
			||||||
 | 
					                    post = post_an_to_fedi(adoption_notice)
 | 
				
			||||||
 | 
					                    context = {"action_was_posting": True, "post": post, "posted_successfully": True}
 | 
				
			||||||
 | 
					                except requests.exceptions.ConnectionError as e:
 | 
				
			||||||
 | 
					                    logging.error(f"Could not post fediverse post: {e}")
 | 
				
			||||||
 | 
					                    context = {"action_was_posting": True,
 | 
				
			||||||
 | 
					                               "posted_successfully": False,
 | 
				
			||||||
 | 
					                               "error_message": _("Verbindungsfehler. Vermittlung wurde nicht gepostet")}
 | 
				
			||||||
 | 
					                except requests.exceptions.HTTPError as e:
 | 
				
			||||||
 | 
					                    logging.error(f"Could not post fediverse post: {e}")
 | 
				
			||||||
 | 
					                    context = {"action_was_posting": True,
 | 
				
			||||||
 | 
					                               "posted_successfully": False,
 | 
				
			||||||
 | 
					                               "error_message": _("Fehler beim Posten. Vermittlung wurde nicht gepostet. Das kann "
 | 
				
			||||||
 | 
					                                                  "z.B. an falschen Zugangsdaten liegen. Kontaktieren einen Admin.")}
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                context = {"action_was_posting": True,
 | 
				
			||||||
 | 
					                           "posted_successfully": False,
 | 
				
			||||||
 | 
					                           "error_message": _("Keine Vermittlung zum Posten gefunden.")}
 | 
				
			||||||
 | 
					    return render(request, 'fellchensammlung/mod-tool-overview.html', context=context)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def deactivate_an(request, adoption_notice_id):
 | 
					def deactivate_an(request, adoption_notice_id):
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -118,6 +118,12 @@ else:
 | 
				
			|||||||
    EMAIL_USE_TLS = config.getboolean('mail', 'tls', fallback=False)
 | 
					    EMAIL_USE_TLS = config.getboolean('mail', 'tls', fallback=False)
 | 
				
			||||||
    EMAIL_USE_SSL = config.getboolean('mail', 'ssl', fallback=False)
 | 
					    EMAIL_USE_SSL = config.getboolean('mail', 'ssl', fallback=False)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					""" Fediverse """
 | 
				
			||||||
 | 
					fediverse_enabled = config.get('fediverse', 'enabled', fallback=False)
 | 
				
			||||||
 | 
					if fediverse_enabled:
 | 
				
			||||||
 | 
					    fediverse_api_base_url = config.get('fediverse', 'api_base_url')
 | 
				
			||||||
 | 
					    fediverse_access_token = config.get('fediverse', 'access_token')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
"""USER MANAGEMENT"""
 | 
					"""USER MANAGEMENT"""
 | 
				
			||||||
AUTH_USER_MODEL = "fellchensammlung.User"
 | 
					AUTH_USER_MODEL = "fellchensammlung.User"
 | 
				
			||||||
ACCOUNT_ACTIVATION_DAYS = 7  # One-week activation window
 | 
					ACCOUNT_ACTIVATION_DAYS = 7  # One-week activation window
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user