fix: replace unpublish with withdraw (FB API doesn't support unpublishing)
Some checks are pending
NordaBiz Tests / Unit & Integration Tests (push) Waiting to run
NordaBiz Tests / E2E Tests (Playwright) (push) Blocked by required conditions
NordaBiz Tests / Smoke Tests (Production) (push) Blocked by required conditions
NordaBiz Tests / Send Failure Notification (push) Blocked by required conditions
Some checks are pending
NordaBiz Tests / Unit & Integration Tests (push) Waiting to run
NordaBiz Tests / E2E Tests (Playwright) (push) Blocked by required conditions
NordaBiz Tests / Smoke Tests (Production) (push) Blocked by required conditions
NordaBiz Tests / Send Failure Notification (push) Blocked by required conditions
Facebook Graph API returns error 100 when setting is_published=false on already-published posts. Replaced "Zmień na debug" with "Usuń z Facebooka" which deletes the post from FB and resets status to draft for re-publishing. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
adceaaec60
commit
af745cfb60
@ -322,7 +322,7 @@ def social_publisher_delete(post_id):
|
||||
@login_required
|
||||
@role_required(SystemRole.MANAGER)
|
||||
def social_publisher_toggle_visibility(post_id):
|
||||
"""Przelacz widocznosc posta miedzy debug a live na Facebook."""
|
||||
"""Opublikuj draft post publicznie na Facebook (debug -> live)."""
|
||||
from services.social_publisher_service import social_publisher
|
||||
|
||||
success, message = social_publisher.toggle_visibility(post_id)
|
||||
@ -330,6 +330,18 @@ def social_publisher_toggle_visibility(post_id):
|
||||
return redirect(url_for('admin.social_publisher_edit', post_id=post_id))
|
||||
|
||||
|
||||
@bp.route('/social-publisher/<int:post_id>/withdraw', methods=['POST'])
|
||||
@login_required
|
||||
@role_required(SystemRole.MANAGER)
|
||||
def social_publisher_withdraw(post_id):
|
||||
"""Usun post z Facebooka i przywroc do szkicu."""
|
||||
from services.social_publisher_service import social_publisher
|
||||
|
||||
success, message = social_publisher.withdraw_from_fb(post_id)
|
||||
flash(message, 'success' if success else 'danger')
|
||||
return redirect(url_for('admin.social_publisher_edit', post_id=post_id))
|
||||
|
||||
|
||||
@bp.route('/social-publisher/<int:post_id>/refresh-engagement', methods=['POST'])
|
||||
@login_required
|
||||
@role_required(SystemRole.MANAGER)
|
||||
|
||||
@ -503,10 +503,10 @@ class SocialPublisherService:
|
||||
db.close()
|
||||
|
||||
def toggle_visibility(self, post_id: int) -> Tuple[bool, str]:
|
||||
"""Toggle post visibility between live (public) and debug (draft) on Facebook.
|
||||
"""Publish a debug/draft post live on Facebook (debug -> live only).
|
||||
|
||||
If post.is_live=True -> unpublish (make draft)
|
||||
If post.is_live=False -> publish live (make public)
|
||||
Note: Facebook API does not support unpublishing already-published posts.
|
||||
Use withdraw_from_fb() to delete and reset to draft instead.
|
||||
"""
|
||||
db = SessionLocal()
|
||||
try:
|
||||
@ -515,7 +515,10 @@ class SocialPublisherService:
|
||||
return False, "Post nie znaleziony"
|
||||
|
||||
if post.status != 'published' or not post.meta_post_id:
|
||||
return False, "Post musi być opublikowany na Facebook, aby zmienić widoczność."
|
||||
return False, "Post musi być opublikowany na Facebook."
|
||||
|
||||
if post.is_live:
|
||||
return False, "Post jest już publiczny. Facebook nie pozwala na cofnięcie publikacji — użyj opcji 'Usuń z Facebooka'."
|
||||
|
||||
pub_company_id = post.publishing_company_id
|
||||
if not pub_company_id:
|
||||
@ -528,26 +531,14 @@ class SocialPublisherService:
|
||||
from facebook_graph_service import FacebookGraphService
|
||||
fb = FacebookGraphService(access_token)
|
||||
|
||||
if post.is_live:
|
||||
# Currently public -> make draft
|
||||
result = fb.unpublish_post(post.meta_post_id)
|
||||
if result:
|
||||
post.is_live = False
|
||||
post.updated_at = datetime.now()
|
||||
db.commit()
|
||||
logger.info(f"Post #{post_id} toggled to DRAFT (unpublished)")
|
||||
return True, "Post zmieniony na tryb debug (widoczny tylko dla adminów strony)."
|
||||
return False, "Nie udało się ukryć posta na Facebook."
|
||||
else:
|
||||
# Currently draft -> make public
|
||||
result = fb.publish_draft(post.meta_post_id)
|
||||
if result:
|
||||
post.is_live = True
|
||||
post.updated_at = datetime.now()
|
||||
db.commit()
|
||||
logger.info(f"Post #{post_id} toggled to LIVE (published)")
|
||||
return True, "Post zmieniony na tryb publiczny (widoczny dla wszystkich)."
|
||||
return False, "Nie udało się upublicznić posta na Facebook."
|
||||
result = fb.publish_draft(post.meta_post_id)
|
||||
if result:
|
||||
post.is_live = True
|
||||
post.updated_at = datetime.now()
|
||||
db.commit()
|
||||
logger.info(f"Post #{post_id} toggled to LIVE (published)")
|
||||
return True, "Post opublikowany publicznie — widoczny dla wszystkich."
|
||||
return False, "Nie udało się upublicznić posta na Facebook."
|
||||
|
||||
except Exception as e:
|
||||
db.rollback()
|
||||
@ -556,6 +547,51 @@ class SocialPublisherService:
|
||||
finally:
|
||||
db.close()
|
||||
|
||||
def withdraw_from_fb(self, post_id: int) -> Tuple[bool, str]:
|
||||
"""Delete post from Facebook and reset status to draft.
|
||||
|
||||
Facebook API doesn't support unpublishing, so we delete and let
|
||||
the user re-publish later if needed.
|
||||
"""
|
||||
db = SessionLocal()
|
||||
try:
|
||||
post = db.query(SocialPost).filter(SocialPost.id == post_id).first()
|
||||
if not post:
|
||||
return False, "Post nie znaleziony"
|
||||
|
||||
if post.status != 'published' or not post.meta_post_id:
|
||||
return False, "Post nie jest opublikowany na Facebook."
|
||||
|
||||
pub_company_id = post.publishing_company_id
|
||||
if not pub_company_id:
|
||||
return False, "Brak firmy publikującej."
|
||||
|
||||
access_token, config = self._get_publish_token(db, pub_company_id)
|
||||
if not access_token:
|
||||
return False, "Brak tokena Facebook dla wybranej firmy."
|
||||
|
||||
from facebook_graph_service import FacebookGraphService
|
||||
fb = FacebookGraphService(access_token)
|
||||
|
||||
if fb.delete_post(post.meta_post_id):
|
||||
old_fb_id = post.meta_post_id
|
||||
post.status = 'draft'
|
||||
post.meta_post_id = None
|
||||
post.is_live = False
|
||||
post.published_at = None
|
||||
post.updated_at = datetime.now()
|
||||
db.commit()
|
||||
logger.info(f"Post #{post_id} withdrawn from FB (deleted {old_fb_id}), reset to draft")
|
||||
return True, "Post usunięty z Facebooka i przywrócony do szkicu. Możesz go ponownie opublikować."
|
||||
return False, "Nie udało się usunąć posta z Facebooka."
|
||||
|
||||
except Exception as e:
|
||||
db.rollback()
|
||||
logger.error(f"Failed to withdraw post #{post_id} from FB: {e}")
|
||||
return False, f"Błąd usuwania z Facebooka: {str(e)}"
|
||||
finally:
|
||||
db.close()
|
||||
|
||||
# ---- AI Content Generation ----
|
||||
|
||||
@staticmethod
|
||||
|
||||
@ -486,15 +486,15 @@
|
||||
</form>
|
||||
|
||||
{% if post and post.status == 'published' and post.meta_post_id %}
|
||||
<!-- Toggle visibility (outside postForm to avoid nested forms) -->
|
||||
<!-- Visibility controls (outside postForm to avoid nested forms) -->
|
||||
<div class="btn-group" style="margin-top: var(--spacing-md);">
|
||||
<strong style="align-self: center;">Widoczność na FB:</strong>
|
||||
{% if post.is_live %}
|
||||
<form method="POST" id="toggleVisibilityForm" action="{{ url_for('admin.social_publisher_toggle_visibility', post_id=post.id) }}">
|
||||
<form method="POST" id="withdrawForm" action="{{ url_for('admin.social_publisher_withdraw', post_id=post.id) }}">
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
|
||||
<button type="button" class="btn btn-secondary"
|
||||
onclick="showConfirm({icon: '🔒', title: 'Ukryj post', message: 'Post zostanie przełączony w tryb debug — będzie widoczny tylko dla administratorów strony na Facebooku.', okText: 'Ukryj post', okClass: 'btn btn-secondary', form: 'toggleVisibilityForm'});">
|
||||
Zmień na debug
|
||||
<button type="button" class="btn btn-error"
|
||||
onclick="showConfirm({icon: '🗑️', title: 'Usuń z Facebooka', message: 'Post zostanie usunięty z Facebooka i przywrócony do szkicu. Będziesz mógł go ponownie opublikować.', okText: 'Usuń z FB', okClass: 'btn btn-error', form: 'withdrawForm'});">
|
||||
Usuń z Facebooka
|
||||
</button>
|
||||
</form>
|
||||
{% else %}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user