diff --git a/.env.dist b/.env.dist index 8576069..3a9868d 100644 --- a/.env.dist +++ b/.env.dist @@ -62,6 +62,7 @@ FAIRPOST_REQUEST_PORT=8000 # FAIRPOST_TWITTER_OA1_API_KEY_SECRET=xxx # FAIRPOST_TWITTER_OA1_ACCESS_TOKEN=xxx # FAIRPOST_TWITTER_OA1_ACCESS_SECRET=xxx +# FAIRPOST_TWITTER_OA1_ADDITIONAL_OWNER=xxx # twitter auth # FAIRPOST_TWITTER_ACCESS_TOKEN=xxx # FAIRPOST_TWITTER_REFRESH_TOKEN=xxx diff --git a/docs/Facebook.md b/docs/Facebook.md index ed3518f..5e0d93d 100644 --- a/docs/Facebook.md +++ b/docs/Facebook.md @@ -3,6 +3,7 @@ The `facebook` platform manages a facebook **page** (not your feed) using the plain graph api - no extensions installed. + ## Setting up the Facebook platform @@ -23,27 +24,72 @@ using the plain graph api - no extensions installed. ### Enable the platform - Add 'facebook' to your `FAIRPOST_FEED_PLATFORMS` in `.env` + ### Get a (long lived) Page Access Token for the page you want the app to manage This token should last forever. It involves getting a user access token, exchanging it for a long-lived user token and then requesting the 'accounts' for your 'app scoped user id'; -but this app provides a tool to help you do that: +but this app provides a tool to help you do that. + +Requesting access tokens only works + - in dev mode and for users that can manage the app + - or in live mode if the app has advanced access permissions + +To get advanced access permissions, the app has to go +through a review. Below, I will assume you use dev +mode when requesting the tokens. Once you have the +tokens, you can turn on Live mode and start posting. + - - call `./fairpost.js setup-platform --platform=facebook` - - follow instructions from the command line +- set your app back in dev mode + - go to https://developers.facebook.com/ + - select your app, edit it + - set App Mode to 'dev' +- call `./fairpost.js setup-platform --platform=facebook` +- follow instructions from the command line ### Test the platform - call `./fairpost.js test-platform --platform=facebook` -### Make the app live - - before you use the app, set the App Mode to 'Live' - - use https://github.com/commonpike/fairpost/blob/master/public/privacy-policy.md for the privacy policy url +### Set the App to Live Mode +before you use the app, set the App Mode to 'Live' + - go to https://developers.facebook.com/ + - select your app, edit it + - set App Mode to 'live' + - use https://github.com/commonpike/fairpost/blob/master/public/privacy-policy.md for the privacy policy url ### Other settings `FAIRPOST_FACEBOOK_PUBLISH_POSTS` - if false, posts will be posted but not be published +## Manage additional pages with the same app + +One fairpost `.env` can only manage one page. If you create a second `.env-foo`, you can use the same app id to manage a different page. The app is registered on your account, so if you can manage the other page, so can the app. + +### Enter credentials for your other installation + +- set the `FAIRPOST_FACEBOOK_APP_ID` in your .env-foo +- set the `FAIRPOST_FACEBOOK_APP_SECRET` in your .env-foo + +### Enable the app on the other page + +- Go to https://www.facebook.com/settings/?tab=business_tools +- edit the app and check the boxes of the other pages you want to manage. + +### Get a access token for the other page + +- set your app back in dev mode + - go to https://developers.facebook.com/ + - select your app, edit it + - set App Mode to 'dev' +- call `./fairpost.js setup-platform --platform=facebook --config=.env-foo` +- follow instructions from the command line +- put your app back in live mode + +### Test the platform for the other page + - call `./fairpost.js test-platform --platform=facebook --config=.env-foo` + # Limitations ## Images diff --git a/docs/Instagram.md b/docs/Instagram.md index bebf72c..2d0334f 100644 --- a/docs/Instagram.md +++ b/docs/Instagram.md @@ -11,6 +11,8 @@ It uses the related facebook account to upload temporary files, because the instagram api requires files in posts to have an url. + + ## Setting up the Instagram platform @@ -31,8 +33,7 @@ api requires files in posts to have an url. ### Find your instagram user id - go to https://www.instagram.com/web/search/topsearch/?query={username} - find your fbid_v2 - - note the user id - - save this as `FAIRPOST_INSTAGRAM_USER_ID` in your .env + - save this as `FAIRPOST_INSTAGRAM_USER_ID` in your .env ### Enable the platform - Add 'instagram' to your `FAIRPOST_FEED_PLATFORMS` in `.env` @@ -42,14 +43,67 @@ api requires files in posts to have an url. This token should last forever. It involves getting a user access token, exchaning it for a long-lived user token and then requesting the 'accounts' for your 'app scoped user id'; -but this app provides a tool to help you do that: +but this app provides a tool to help you do that. + +Requesting access tokens only works + - in dev mode and for users that can manage the app + - or in live mode if the app has advanced access permissions + +To get advanced access permissions, the app has to go +through a review. Below, I will assume you use dev +mode when requesting the tokens. Once you have the +tokens, you can turn on Live mode and start posting. - - call `./fairpost.js setup-platform --platform=instagram` - - follow instructions from the command line + +- set your app back in dev mode + - go to https://developers.facebook.com/ + - select your app, edit it + - set App Mode to 'dev' +- call `./fairpost.js setup-platform --platform=instagram` +- follow instructions from the command line ### Test the platform - call `./fairpost.js test-platform --platform=instagram` +### Set the App to Live Mode +before you use the app, set the App Mode to 'Live' + - go to https://developers.facebook.com/ + - select your app, edit it + - set App Mode to 'live' + - use https://github.com/commonpike/fairpost/blob/master/public/privacy-policy.md for the privacy policy url + +## Manage additional pages with the same app + +One fairpost `.env` can only manage one page. If you create a second `.env-foo`, you can use the same app id to manage a different page. The app is registered on your account, so if you can manage the other page, so can the app. + +### Enter credentials for your other installation + +- set the `FAIRPOST_INSTAGRAM_APP_ID` in your .env-foo +- set the `FAIRPOST_INSTAGRAM_APP_SECRET` in your .env-foo + +### Find your other instagram user id + - go to https://www.instagram.com/web/search/topsearch/?query={username} + - find your fbid_v2 + - save this as `FAIRPOST_INSTAGRAM_USER_ID` in your .env-foo + +### Enable the app on the other page +- Go to https://www.facebook.com/settings/?tab=business_tools +- edit the app and check the boxes of the other pages you want to manage. + +### Get a access token for the other page + +- set your app back in dev mode + - go to https://developers.facebook.com/ + - select your app, edit it + - set App Mode to 'dev' +- call `./fairpost.js setup-platform --platform=instagram --config=.env-foo` +- follow instructions from the command line +- put your app back in live mode + +### Test the platform for the other page + - call `./fairpost.js test-platform --platform=instagram --config=.env-foo` + + # Limitations ## Images diff --git a/docs/LinkedIn.md b/docs/LinkedIn.md index 2543fc1..108ae62 100644 --- a/docs/LinkedIn.md +++ b/docs/LinkedIn.md @@ -7,7 +7,7 @@ The LinkedIn platform posts to your companies feed. ### Create a new App in your linkedin account - create an company your account can manage -- find your company id (like , 93841222) +- find your company id (in the url, like , 93841222) - save this as `FAIRPOST_LINKEDIN_COMPANY_ID` in your .env - create an app to manage the company page \ https://www.linkedin.com/developers/apps/new @@ -38,6 +38,25 @@ The refresh token (if given) lasts for 1 year. ### Test the platform - call `./fairpost.js test-platform --platform=linkedin` +## Manage additional pages with the same app + +One fairpost `.env` can only manage one page. If you create a second `.env-foo`, you can use the same app id to manage a different page. The app is registered on your account, so if you can manage the other page, so can the app. + +### Enter credentials for your other installation + +- set the `FAIRPOST_LINKEDIN_CLIENT_ID` in your .env-foo +- set the `FAIRPOST_LINKEDIN_CLIENT_SECRET` in your .env-foo +- find your company id (in the url, like , 93841222) + - save this as `FAIRPOST_LINKEDIN_COMPANY_ID` in your .env-foo + +### Get an OAuth2 Access Token for your other page + + - call `./fairpost.js setup-platform --platform=linkedin --config=.env-foo` + - follow instructions from the command line + +### Test the other installation + - call `./fairpost.js test-platform --platform=linkedin --config=.env-foo` + # Limitations ## Images diff --git a/docs/Twitter.md b/docs/Twitter.md index c821728..09c448e 100644 --- a/docs/Twitter.md +++ b/docs/Twitter.md @@ -44,6 +44,35 @@ This token should last forever (?) - call `./fairpost.js setup-platform --platform=twitter` - follow instructions from the command line +### Test the platform + - call `./fairpost.js test-platform --platform=twitter` + +## Manage additional feeds with the same app + +One fairpost `.env` can only manage one feed. If you create a second `.env-foo`, you can use the same app to manage a different feed. OAuth2 allows you to enable the app for your second account, but the OAuth1 part is tied to your first +account and requires you to specify an 'additional_owner' for the uploaded media. + +### Enter credentials for your other installation + +- set the `FAIRPOST_TWITTER_CLIENT_ID` in your .env-foo +- set the `FAIRPOST_TWITTER_CLIENT_SECRET` in your .env-foo +- set the `FAIRPOST_TWITTER_OA1_API_KEY` in your .env-foo +- set the `FAIRPOST_TWITTER_OA1_API_KEY_SECRET` in your .env-foo +- set the `FAIRPOST_TWITTER_OA1_ACCESS_TOKEN` in your .env-foo +- set the `FAIRPOST_TWITTER_OA1_ACCESS_SECRET` in your .env-foo + +### Get an OAuth2 Access Token for your other page + +- call `./fairpost.js setup-platform --platform=twitter --config=.env-foo` +- follow instructions from the command line + +### Test the other installation +- call `./fairpost.js test-platform --platform=twitter --config=.env-foo` + +### Set the 'additional owner' +- from the previous `test-platform` result, copy the `oauth2:id` +- set this as the `FAIRPOST_TWITTER_OA1_ADDITIONAL_OWNER` in your .env-foo + # Random documentation https://github.com/twitterdev/twitter-api-typescript-sdk/blob/main/src/gen/Client.ts#L889 diff --git a/src/platforms/LinkedIn/LinkedIn.ts b/src/platforms/LinkedIn/LinkedIn.ts index e0666b2..58c87db 100644 --- a/src/platforms/LinkedIn/LinkedIn.ts +++ b/src/platforms/LinkedIn/LinkedIn.ts @@ -197,7 +197,7 @@ export default class LinkedIn extends Platform { // https://learn.microsoft.com/en-us/linkedin/marketing/integrations/community-management/shares/videos-api?view=li-lms-2023-10&tabs=http#sample-response-4 const body = { author: this.POST_AUTHOR, - commentary: post.getCompiledBody("!title"), + commentary: post.getCompiledBody(), visibility: this.POST_VISIBILITY, distribution: this.POST_DISTRIBUTION, content: { @@ -282,7 +282,7 @@ export default class LinkedIn extends Platform { // https://learn.microsoft.com/en-us/linkedin/marketing/integrations/community-management/shares/videos-api?view=li-lms-2023-10&tabs=http#sample-response-4 const body = { author: this.POST_AUTHOR, - commentary: post.getCompiledBody("!title"), + commentary: post.getCompiledBody(), visibility: this.POST_VISIBILITY, distribution: this.POST_DISTRIBUTION, content: { diff --git a/src/platforms/Twitter/Twitter.ts b/src/platforms/Twitter/Twitter.ts index b88e590..5dbee79 100644 --- a/src/platforms/Twitter/Twitter.ts +++ b/src/platforms/Twitter/Twitter.ts @@ -38,11 +38,18 @@ export default class Twitter extends Platform { accessToken: Storage.get("settings", "TWITTER_OA1_ACCESS_TOKEN"), accessSecret: Storage.get("settings", "TWITTER_OA1_ACCESS_SECRET"), }); + const creds1 = await client1.v1.verifyCredentials(); Logger.trace("Twitter.test: get oauth2 api"); const client2 = new TwitterApi(Storage.get("auth", "TWITTER_ACCESS_TOKEN")); + const creds2 = await client2.v2.me(); return { - oauth1: await client1.v1.verifyCredentials(), - oauth2: await client2.v2.me(), + oauth1: { + id: creds1["id"], + name: creds1["name"], + screen_name: creds1["screen_name"], + url: creds1["url"], + }, + oauth2: creds2["data"], }; } @@ -177,11 +184,24 @@ export default class Twitter extends Platform { }); const mediaIds = []; + const additionalOwner = Storage.get( + "settings", + "TWITTER_OA1_ADDITIONAL_OWNER", + ); for (const image of post.getFiles("image")) { const path = post.getFilePath(image.name); Logger.trace("Uploading " + path + "..."); try { - mediaIds.push(await client1.v1.uploadMedia(path)); + mediaIds.push( + await client1.v1.uploadMedia(path, { + // mimeType : '' //MIME type as a string. To help you across allowed MIME types, enum EUploadMimeType is here for you. This option is required if file is not specified as string. + // target: 'tweet' //Target type tweet or dm. Defaults to tweet. You must specify it if you send a media to use in DMs. + // longVideo : false //Specify true here if you're sending a video and it can exceed 120 seconds. Otherwise, this option has no effet. + // shared: false //Specify true here if you want to use this media in Welcome Direct Messages. + additionalOwners: additionalOwner ? [additionalOwner] : [], //List of user IDs (except you) allowed to use the new media ID. + // maxConcurrentUploads: 3 //Number of concurrent chunk uploads allowed to be sent. Defaults to 3. + }), + ); } catch (e) { throw Logger.error("Twitter.publishPost uploadMedia failed", e); }