mirror of
https://github.com/MCV-Software/TWBlue.git
synced 2025-11-07 06:47:05 +00:00
fix: avoid passing params that are not editable to API Calls; display polls as attachments in post edit dialog, warns user about vote resetting when editing a post with poll
This commit is contained in:
@@ -514,6 +514,29 @@ class BaseBuffer(base.Buffer):
|
||||
if item.account.id != self.session.db["user_id"] or item.reblog != None:
|
||||
output.speak(_("You can only edit your own posts."))
|
||||
return
|
||||
# Check if post has a poll with votes - warn user before proceeding
|
||||
if hasattr(item, 'poll') and item.poll is not None:
|
||||
votes_count = item.poll.votes_count if hasattr(item.poll, 'votes_count') else 0
|
||||
if votes_count > 0:
|
||||
# Show confirmation dialog
|
||||
warning_title = _("Warning: Poll with votes")
|
||||
warning_message = _("This post contains a poll with {votes} votes.\n\n"
|
||||
"According to Mastodon's API, editing this post will reset ALL votes to zero, "
|
||||
"even if you don't modify the poll itself.\n\n"
|
||||
"Do you want to continue editing?").format(votes=votes_count)
|
||||
dialog = wx.MessageDialog(self.buffer, warning_message, warning_title,
|
||||
wx.YES_NO | wx.NO_DEFAULT | wx.ICON_WARNING)
|
||||
result = dialog.ShowModal()
|
||||
dialog.Destroy()
|
||||
if result != wx.ID_YES:
|
||||
output.speak(_("Edit cancelled"))
|
||||
return
|
||||
# Log item info for debugging
|
||||
log.debug("Editing status: id={}, has_media_attachments={}, media_count={}".format(
|
||||
item.id,
|
||||
hasattr(item, 'media_attachments'),
|
||||
len(item.media_attachments) if hasattr(item, 'media_attachments') else 0
|
||||
))
|
||||
# Create edit dialog with existing post data
|
||||
title = _("Edit post")
|
||||
caption = _("Edit your post here")
|
||||
@@ -522,7 +545,8 @@ class BaseBuffer(base.Buffer):
|
||||
if response == wx.ID_OK:
|
||||
post_data = post.get_data()
|
||||
# Call edit_post method in session
|
||||
call_threaded(self.session.edit_post, post_id=post.post_id, posts=post_data, visibility=post.get_visibility(), language=post.get_language())
|
||||
# Note: visibility and language cannot be changed when editing per Mastodon API
|
||||
call_threaded(self.session.edit_post, post_id=post.post_id, posts=post_data)
|
||||
if hasattr(post.message, "destroy"):
|
||||
post.message.destroy()
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
import os
|
||||
import re
|
||||
import wx
|
||||
import logging
|
||||
import widgetUtils
|
||||
import config
|
||||
import output
|
||||
@@ -14,6 +15,8 @@ from wxUI.dialogs.mastodon import postDialogs
|
||||
from extra.autocompletionUsers import completion
|
||||
from . import userList
|
||||
|
||||
log = logging.getLogger("controller.mastodon.messages")
|
||||
|
||||
def character_count(post_text, post_cw, character_limit=500):
|
||||
# We will use text for counting character limit only.
|
||||
full_text = post_text+post_cw
|
||||
@@ -264,7 +267,11 @@ class post(messages.basicMessage):
|
||||
|
||||
class editPost(post):
|
||||
def __init__(self, session, item, title, caption, *args, **kwargs):
|
||||
""" Initialize edit dialog with existing post data. """
|
||||
""" Initialize edit dialog with existing post data.
|
||||
|
||||
Note: Per Mastodon API, visibility and language cannot be changed when editing.
|
||||
These fields will be displayed but disabled in the UI.
|
||||
"""
|
||||
# Extract text from post
|
||||
if item.reblog != None:
|
||||
item = item.reblog
|
||||
@@ -276,30 +283,87 @@ class editPost(post):
|
||||
super(editPost, self).__init__(session, title, caption, text=text, *args, **kwargs)
|
||||
# Store the post ID for editing
|
||||
self.post_id = item.id
|
||||
# Set visibility
|
||||
# Set visibility (read-only, cannot be changed)
|
||||
visibility_settings = dict(public=0, unlisted=1, private=2, direct=3)
|
||||
self.message.visibility.SetSelection(visibility_settings.get(item.visibility, 0))
|
||||
# Set language
|
||||
self.message.visibility.Enable(False) # Disable as it cannot be edited
|
||||
# Set language (read-only, cannot be changed)
|
||||
if item.language:
|
||||
self.set_language(item.language)
|
||||
self.message.language.Enable(False) # Disable as it cannot be edited
|
||||
# Set sensitive content and spoiler
|
||||
if item.sensitive:
|
||||
self.message.sensitive.SetValue(True)
|
||||
if item.spoiler_text:
|
||||
self.message.spoiler.ChangeValue(item.spoiler_text)
|
||||
self.message.on_sensitivity_changed()
|
||||
# Load existing media attachments
|
||||
if hasattr(item, 'media_attachments') and len(item.media_attachments) > 0:
|
||||
# Load existing poll (if any)
|
||||
# Note: You cannot have both media and a poll, so check poll first
|
||||
if hasattr(item, 'poll') and item.poll is not None:
|
||||
log.debug("Loading existing poll for post {}".format(self.post_id))
|
||||
poll = item.poll
|
||||
# Extract poll options (just the text, not the votes)
|
||||
poll_options = [option.title for option in poll.options]
|
||||
# Calculate expires_in based on current time and expires_at
|
||||
# For editing, we need to provide a new expiration time
|
||||
# Since we can't get the original expires_in, use a default or let user configure
|
||||
# For now, use 1 day (86400 seconds) as default
|
||||
expires_in = 86400
|
||||
if hasattr(poll, 'expires_at') and poll.expires_at and not poll.expired:
|
||||
# Calculate remaining time if poll hasn't expired
|
||||
from dateutil import parser as date_parser
|
||||
import datetime
|
||||
try:
|
||||
expires_at = poll.expires_at
|
||||
if isinstance(expires_at, str):
|
||||
expires_at = date_parser.parse(expires_at)
|
||||
now = datetime.datetime.now(datetime.timezone.utc)
|
||||
remaining = (expires_at - now).total_seconds()
|
||||
if remaining > 0:
|
||||
expires_in = int(remaining)
|
||||
except Exception as e:
|
||||
log.warning("Could not calculate poll expiration: {}".format(e))
|
||||
|
||||
poll_info = {
|
||||
"type": "poll",
|
||||
"file": "",
|
||||
"description": _("Poll with {} options").format(len(poll_options)),
|
||||
"options": poll_options,
|
||||
"expires_in": expires_in,
|
||||
"multiple": poll.multiple if hasattr(poll, 'multiple') else False,
|
||||
"hide_totals": poll.voters_count == 0 if hasattr(poll, 'voters_count') else False
|
||||
}
|
||||
self.attachments.append(poll_info)
|
||||
self.message.add_item(item=[poll_info["file"], poll_info["type"], poll_info["description"]])
|
||||
log.debug("Loaded poll with {} options. WARNING: Editing will reset all votes!".format(len(poll_options)))
|
||||
# Load existing media attachments (only if no poll)
|
||||
elif hasattr(item, 'media_attachments'):
|
||||
log.debug("Loading existing media attachments for post {}".format(self.post_id))
|
||||
log.debug("Item has media_attachments attribute, count: {}".format(len(item.media_attachments)))
|
||||
if len(item.media_attachments) > 0:
|
||||
for media in item.media_attachments:
|
||||
log.debug("Processing media: id={}, type={}, url={}".format(media.id, media.type, media.url))
|
||||
media_info = {
|
||||
"id": media.id, # Keep the existing media ID
|
||||
"type": media.type,
|
||||
"file": media.url, # URL of existing media
|
||||
"description": media.description or ""
|
||||
}
|
||||
# Include focus point if available
|
||||
if hasattr(media, 'meta') and media.meta and 'focus' in media.meta:
|
||||
focus = media.meta['focus']
|
||||
media_info["focus"] = (focus.get('x'), focus.get('y'))
|
||||
log.debug("Added focus point: {}".format(media_info["focus"]))
|
||||
self.attachments.append(media_info)
|
||||
# Display in the attachment list
|
||||
self.message.add_item(item=[media.url.split('/')[-1], media.type, media.description or ""])
|
||||
display_name = media.url.split('/')[-1]
|
||||
log.debug("Adding item to UI: name={}, type={}, desc={}".format(display_name, media.type, media.description or ""))
|
||||
self.message.add_item(item=[display_name, media.type, media.description or ""])
|
||||
log.debug("Total attachments loaded: {}".format(len(self.attachments)))
|
||||
else:
|
||||
log.debug("media_attachments list is empty")
|
||||
else:
|
||||
log.debug("Item has no poll or media attachments")
|
||||
# Update text processor to reflect the loaded content
|
||||
self.text_processor()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user