Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions apps/frontend/src/components/launches/continue.integration.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,16 @@ export const ContinueIntegration: FC<{
existingId={[]}
initialData={twoStepState.pages}
isSaving={isSaving}
onBack={
logged || twoStepState.returnURL
? () =>
navigateOrShow(
'/launches',
twoStepState.returnURL,
'Channel setup cancelled'
)
: undefined
}
/>
</IntegrationContext.Provider>
</div>
Expand Down
2 changes: 1 addition & 1 deletion apps/frontend/src/components/layout/top.tip.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@

import { Tooltip } from 'react-tooltip';
export const ToolTip = () => {
return <Tooltip className="z-[200]" id="tooltip" />;
return <Tooltip className="z-[200] whitespace-pre-line" id="tooltip" />;
};
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ export interface ContinueProviderProps {
existingId: string[];
initialData?: any[];
isSaving?: boolean;
// Shows a "Back to Postiz" button in the empty state — used by the
// full-page OAuth landing flow, which has no dialog to close
onBack?: () => void;
}

export interface EmptyStateMessage {
Expand Down Expand Up @@ -59,7 +62,7 @@ export function withContinueProvider<TItem, TSelection>(
} = config;

return function ContinueProviderComponent(props: ContinueProviderProps) {
const { onSave, existingId, initialData, isSaving } = props;
const { onSave, existingId, initialData, isSaving, onBack } = props;
const call = useCustomProviderFunction();
const t = useT();
const [selection, setSelection] = useState<TSelection | null>(null);
Expand Down Expand Up @@ -119,6 +122,13 @@ export function withContinueProvider<TItem, TSelection>(
)}
</span>
))}
{!!onBack && (
<div className="mt-[24px]">
<Button type="button" onClick={onBack}>
{t('back_to_postiz', 'Back to Postiz')}
</Button>
</div>
)}
</div>
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,7 @@ export class IntegrationRepository {
...params,
disabled: false,
deletedAt: null,
refreshNeeded: false,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why this was added?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updateIntegration is only called from saveProviderPage - the step where the user picks a page during reconnect and we save the fresh page token. It already clears disabled and deletedAt to revive the channel, but it left refreshNeeded set, so a channel flagged for reconnection stayed flagged even after the user reconnected with a valid token - the banner never went away and post workflows kept blocking it. The regular OAuth save path (createOrUpdateIntegration) already resets refreshNeeded to false, so this just makes the page-selection path consistent with it.

},
});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ import { Rules } from '@gitroom/nestjs-libraries/chat/rules.description.decorato
export class FacebookProvider extends SocialAbstract implements SocialProvider {
identifier = 'facebook';
name = 'Facebook Page';
toolTip =
'Your Facebook page selection is shared across all your Meta channels, check all relevant pages';
isBetweenSteps = true;
scopes = [
'pages_show_list',
Expand Down Expand Up @@ -79,6 +81,14 @@ export class FacebookProvider extends SocialAbstract implements SocialProvider {
};
}

if (/"code":\s*190\b/.test(body)) {
return {
type: 'refresh-token' as const,
value:
'The Facebook access token is invalid, please reconnect the channel',
};
}

if (body.indexOf('1366046') > -1) {
return {
type: 'bad-body' as const,
Expand Down Expand Up @@ -243,6 +253,9 @@ export class FacebookProvider extends SocialAbstract implements SocialProvider {
`${process.env.FRONTEND_URL}/integrations/social/facebook`
)}` +
`&state=${state}` +
// Re-prompt permissions/assets the user previously declined, so a
// bad page grant can be repaired by reconnecting
`&auth_type=rerequest` +
`&scope=${this.scopes.join(',')}`,
codeVerifier: makeId(10),
state,
Expand Down Expand Up @@ -383,7 +396,9 @@ export class FacebookProvider extends SocialAbstract implements SocialProvider {
// Business Manager API not available for all users
}

return allPages;
// Pages without an access_token were never granted to the app in the
// OAuth dialog — publishing through them is impossible
return allPages.filter((p: any) => p.access_token);
}

async fetchPageInformation(accessToken: string, data: { page: string }) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ export class InstagramProvider
identifier = 'instagram';
name = 'Instagram\n(Facebook Business)';
isBetweenSteps = true;
toolTip = 'Instagram must be business and connected to a Facebook page';
toolTip =
'Your Facebook page selection is shared across all your Meta channels, check all relevant pages\nInstagram must be business and connected to a Facebook page, check this page too';
scopes = [
'instagram_basic',
'pages_show_list',
Expand Down Expand Up @@ -319,11 +320,11 @@ export class InstagramProvider
};
}

if (body.indexOf('190,') > -1) {
if (/"code":\s*190\b/.test(body)) {
return {
type: 'bad-body' as const,
type: 'refresh-token' as const,
value:
'The account is missing some permissions to perform this action, please re-add the account and allow all permissions',
'The Instagram access token is invalid, please reconnect the channel',
};
}

Expand Down Expand Up @@ -421,6 +422,9 @@ export class InstagramProvider
`${process.env.FRONTEND_URL}/integrations/social/instagram`
)}` +
`&state=${state}` +
// Re-prompt permissions/assets the user previously declined, so a
// bad page grant can be repaired by reconnecting
`&auth_type=rerequest` +
`&scope=${encodeURIComponent(this.scopes.join(','))}`,
codeVerifier: makeId(10),
state,
Expand Down Expand Up @@ -544,21 +548,36 @@ export class InstagramProvider
// Business Manager API not available for all users
}

const onlyConnectedAccounts = await Promise.all(
allFacebookPages
.filter((f: any) => f.instagram_business_account)
.map(async (p: any) => {
return {
pageId: p.id,
...(await (
const onlyConnectedAccounts = (
await Promise.all(
allFacebookPages
.filter((f: any) => f.instagram_business_account)
.map(async (p: any) => {
// Pages without an access_token were never granted to the app
// in the OAuth dialog — selecting them would store a broken
// "undefined___..." token
const { access_token } = await (
await fetch(
`https://graph.facebook.com/v20.0/${p.instagram_business_account.id}?fields=name,profile_picture_url&access_token=${accessToken}`
`https://graph.facebook.com/v20.0/${p.id}?fields=access_token&access_token=${accessToken}`
)
).json()),
id: p.instagram_business_account.id,
};
})
);
).json();

if (!access_token) {
return null;
}

return {
pageId: p.id,
...(await (
await fetch(
`https://graph.facebook.com/v20.0/${p.instagram_business_account.id}?fields=name,profile_picture_url&access_token=${accessToken}`
)
).json()),
id: p.instagram_business_account.id,
};
})
)
).filter(Boolean);

return onlyConnectedAccounts.map((p: any) => ({
pageId: p.pageId,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,7 @@
"we_couldn_t_find_any_business_connected_to_the_selected_pages": "لم نتمكن من العثور على أي نشاط تجاري مرتبط بالصفحات المحددة.",
"we_recommend_you_to_connect_all_the_pages_and_all_the_businesses": "نوصي بربط جميع الصفحات وجميع الأنشطة التجارية.",
"please_close_this_dialog_delete_your_integration_and_add_a_new_channel_again": "يرجى إغلاق هذه النافذة، حذف التكامل الخاص بك، ثم إضافة قناة جديدة مرة أخرى.",
"back_to_postiz": "العودة إلى Postiz",
"select_instagram_account": "اختر حساب إنستغرام:",
"select_page": "اختر الصفحة:",
"generate_image_with_ai": "توليد صورة بالذكاء الاصطناعي",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,7 @@
"we_couldn_t_find_any_business_connected_to_the_selected_pages": "আমরা নির্বাচিত পৃষ্ঠাগুলির সাথে সংযুক্ত কোনো ব্যবসা খুঁজে পাইনি।",
"we_recommend_you_to_connect_all_the_pages_and_all_the_businesses": "আমরা আপনাকে সব পৃষ্ঠা এবং সব ব্যবসা সংযুক্ত করার পরামর্শ দিই।",
"please_close_this_dialog_delete_your_integration_and_add_a_new_channel_again": "অনুগ্রহ করে এই ডায়ালগটি বন্ধ করুন, আপনার ইন্টিগ্রেশন মুছে ফেলুন এবং আবার একটি নতুন চ্যানেল যোগ করুন।",
"back_to_postiz": "Postiz-এ ফিরে যান",
"select_instagram_account": "Instagram অ্যাকাউন্ট নির্বাচন করুন:",
"select_page": "পৃষ্ঠা নির্বাচন করুন:",
"generate_image_with_ai": "AI দিয়ে ছবি তৈরি করুন",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,7 @@
"we_couldn_t_find_any_business_connected_to_the_selected_pages": "Wir konnten kein Unternehmen finden, das mit den ausgewählten Seiten verbunden ist.",
"we_recommend_you_to_connect_all_the_pages_and_all_the_businesses": "Wir empfehlen Ihnen, alle Seiten und alle Unternehmen zu verbinden.",
"please_close_this_dialog_delete_your_integration_and_add_a_new_channel_again": "Bitte schließen Sie diesen Dialog, löschen Sie Ihre Integration und fügen Sie erneut einen neuen Kanal \n hinzu.",
"back_to_postiz": "Zurück zu Postiz",
"select_instagram_account": "Instagram-Konto auswählen:",
"select_page": "Seite auswählen:",
"generate_image_with_ai": "Bild mit KI generieren",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,7 @@
"we_couldn_t_find_any_business_connected_to_the_selected_pages": "We couldn't find any business connected to the selected pages.",
"we_recommend_you_to_connect_all_the_pages_and_all_the_businesses": "We recommend you to connect all the pages and all the businesses.",
"please_close_this_dialog_delete_your_integration_and_add_a_new_channel_again": "Please close this dialog, delete your integration and add a new channel\n again.",
"back_to_postiz": "Back to Postiz",
"select_instagram_account": "Select Instagram Account:",
"select_page": "Select Page:",
"generate_image_with_ai": "Generate image with AI",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,7 @@
"we_couldn_t_find_any_business_connected_to_the_selected_pages": "No pudimos encontrar ningún negocio conectado a las páginas seleccionadas.",
"we_recommend_you_to_connect_all_the_pages_and_all_the_businesses": "Te recomendamos conectar todas las páginas y todos los negocios.",
"please_close_this_dialog_delete_your_integration_and_add_a_new_channel_again": "Por favor, cierra este diálogo, elimina tu integración y agrega un nuevo canal nuevamente.",
"back_to_postiz": "Volver a Postiz",
"select_instagram_account": "Selecciona la cuenta de Instagram:",
"select_page": "Selecciona la página:",
"generate_image_with_ai": "Generar imagen con IA",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,7 @@
"we_couldn_t_find_any_business_connected_to_the_selected_pages": "Nous n'avons trouvé aucune entreprise liée aux pages sélectionnées.",
"we_recommend_you_to_connect_all_the_pages_and_all_the_businesses": "Nous vous recommandons de connecter toutes les pages et toutes les entreprises.",
"please_close_this_dialog_delete_your_integration_and_add_a_new_channel_again": "Veuillez fermer cette fenêtre, supprimer votre intégration et ajouter à nouveau un nouveau canal.",
"back_to_postiz": "Retour à Postiz",
"select_instagram_account": "Sélectionnez le compte Instagram :",
"select_page": "Sélectionnez la page :",
"generate_image_with_ai": "Générer une image avec l'IA",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,7 @@
"we_couldn_t_find_any_business_connected_to_the_selected_pages": "לא הצלחנו למצוא עסק שמחובר לעמודים שנבחרו.",
"we_recommend_you_to_connect_all_the_pages_and_all_the_businesses": "אנו ממליצים לחבר את כל העמודים וכל העסקים.",
"please_close_this_dialog_delete_your_integration_and_add_a_new_channel_again": "אנא סגור את החלון הזה, מחק את האינטגרציה שלך והוסף ערוץ חדש שוב.",
"back_to_postiz": "חזרה ל-Postiz",
"select_instagram_account": "בחר חשבון אינסטגרם:",
"select_page": "בחר עמוד:",
"generate_image_with_ai": "צור תמונה עם בינה מלאכותית",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,7 @@
"we_couldn_t_find_any_business_connected_to_the_selected_pages": "Non siamo riusciti a trovare nessuna azienda collegata alle pagine selezionate.",
"we_recommend_you_to_connect_all_the_pages_and_all_the_businesses": "Ti consigliamo di collegare tutte le pagine e tutte le aziende.",
"please_close_this_dialog_delete_your_integration_and_add_a_new_channel_again": "Per favore chiudi questa finestra di dialogo, elimina la tua integrazione e aggiungi nuovamente un nuovo canale.",
"back_to_postiz": "Torna a Postiz",
"select_instagram_account": "Seleziona account Instagram:",
"select_page": "Seleziona pagina:",
"generate_image_with_ai": "Genera immagine con IA",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,7 @@
"we_couldn_t_find_any_business_connected_to_the_selected_pages": "選択したページに接続されているビジネスが見つかりませんでした。",
"we_recommend_you_to_connect_all_the_pages_and_all_the_businesses": "すべてのページとすべてのビジネスを接続することをおすすめします。",
"please_close_this_dialog_delete_your_integration_and_add_a_new_channel_again": "このダイアログを閉じて、連携を削除し、再度新しいチャンネルを追加してください。",
"back_to_postiz": "Postizに戻る",
"select_instagram_account": "Instagramアカウントを選択:",
"select_page": "ページを選択:",
"generate_image_with_ai": "AIで画像を生成",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,7 @@
"we_couldn_t_find_any_business_connected_to_the_selected_pages": "არჩეულ გვერდებს მიერთებული ბიზნესი ვერ ვიპოვეთ.",
"we_recommend_you_to_connect_all_the_pages_and_all_the_businesses": "გირჩევთ დააკავშიროთ ყველა გვერდი და ყველა ბიზნესი.",
"please_close_this_dialog_delete_your_integration_and_add_a_new_channel_again": "დახურეთ ეს ფანჯარა, წაშალეთ ინტეგრაცია და თავიდან დაამატეთ არხი.",
"back_to_postiz": "Postiz-ზე დაბრუნება",
"select_instagram_account": "აირჩიეთ Instagram ანგარიში:",
"select_page": "გვერდის არჩევა:",
"generate_image_with_ai": "სურათის გენერირება AI-ით",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,7 @@
"we_couldn_t_find_any_business_connected_to_the_selected_pages": "선택한 페이지에 연결된 비즈니스를 찾을 수 없습니다.",
"we_recommend_you_to_connect_all_the_pages_and_all_the_businesses": "모든 페이지와 모든 비즈니스를 연결하는 것을 권장합니다.",
"please_close_this_dialog_delete_your_integration_and_add_a_new_channel_again": "이 대화 상자를 닫고, 통합을 삭제한 후 새 채널을 다시 추가해 주세요.",
"back_to_postiz": "Postiz로 돌아가기",
"select_instagram_account": "Instagram 계정 선택:",
"select_page": "페이지 선택:",
"generate_image_with_ai": "AI로 이미지 생성",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,7 @@
"we_couldn_t_find_any_business_connected_to_the_selected_pages": "Não conseguimos encontrar nenhum negócio conectado às páginas selecionadas.",
"we_recommend_you_to_connect_all_the_pages_and_all_the_businesses": "Recomendamos que você conecte todas as páginas e todos os negócios.",
"please_close_this_dialog_delete_your_integration_and_add_a_new_channel_again": "Por favor, feche este diálogo, exclua sua integração e adicione um novo canal novamente.",
"back_to_postiz": "Voltar ao Postiz",
"select_instagram_account": "Selecione a Conta do Instagram:",
"select_page": "Selecione a Página:",
"generate_image_with_ai": "Gerar imagem com IA",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,7 @@
"we_couldn_t_find_any_business_connected_to_the_selected_pages": "Мы не смогли найти ни одного бизнеса, связанного с выбранными страницами.",
"we_recommend_you_to_connect_all_the_pages_and_all_the_businesses": "Рекомендуем подключить все страницы и все бизнесы.",
"please_close_this_dialog_delete_your_integration_and_add_a_new_channel_again": "Пожалуйста, закройте это окно, удалите интеграцию и снова добавьте новый канал.",
"back_to_postiz": "Вернуться в Postiz",
"select_instagram_account": "Выберите аккаунт Instagram:",
"select_page": "Выберите страницу:",
"generate_image_with_ai": "Сгенерировать изображение с помощью ИИ",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,7 @@
"we_couldn_t_find_any_business_connected_to_the_selected_pages": "Seçilen sayfalara bağlı herhangi bir işletme bulamadık.",
"we_recommend_you_to_connect_all_the_pages_and_all_the_businesses": "Tüm sayfaları ve tüm işletmeleri bağlamanızı öneririz.",
"please_close_this_dialog_delete_your_integration_and_add_a_new_channel_again": "Lütfen bu pencereyi kapatın, entegrasyonunuzu silin ve tekrar yeni bir kanal ekleyin.",
"back_to_postiz": "Postiz'e geri dön",
"select_instagram_account": "Instagram Hesabı Seç:",
"select_page": "Sayfa Seç:",
"generate_image_with_ai": "Yapay Zeka ile görsel oluştur",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,7 @@
"we_couldn_t_find_any_business_connected_to_the_selected_pages": "Chúng tôi không tìm thấy doanh nghiệp nào liên kết với các trang đã chọn.",
"we_recommend_you_to_connect_all_the_pages_and_all_the_businesses": "Chúng tôi khuyên bạn nên kết nối tất cả các trang và tất cả các doanh nghiệp.",
"please_close_this_dialog_delete_your_integration_and_add_a_new_channel_again": "Vui lòng đóng hộp thoại này, xóa tích hợp của bạn và thêm kênh mới lại.",
"back_to_postiz": "Quay lại Postiz",
"select_instagram_account": "Chọn tài khoản Instagram:",
"select_page": "Chọn Trang:",
"generate_image_with_ai": "Tạo hình ảnh bằng AI",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,7 @@
"we_couldn_t_find_any_business_connected_to_the_selected_pages": "我们未能找到与所选页面关联的任何企业。",
"we_recommend_you_to_connect_all_the_pages_and_all_the_businesses": "我们建议您连接所有页面和所有企业。",
"please_close_this_dialog_delete_your_integration_and_add_a_new_channel_again": "请关闭此对话框,删除您的集成并再次添加新频道。",
"back_to_postiz": "返回 Postiz",
"select_instagram_account": "选择 Instagram 账号:",
"select_page": "选择页面:",
"generate_image_with_ai": "用 AI 生成图片",
Expand Down
Loading