10000 LinkedIn post as carousel by nevo-david · Pull Request #786 · gitroomhq/postiz-app · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

LinkedIn post as carousel #786

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Jun 8, 2025
Merged

LinkedIn post as carousel #786

merged 4 commits into from
Jun 8, 2025

Conversation

nevo-david
Copy link
Contributor
@nevo-david nevo-david commented Jun 8, 2025
  • feat: carousel
  • feat: linkedin post as carousel

Summary by CodeRabbit

  • New Features

    • Added support for posting PDF documents and image carousels to LinkedIn, allowing multiple images to be combined into a single PDF for carousel posts.
    • Introduced a new LinkedIn post setting, "Post as images carousel," with a user interface checkbox.
    • Enhanced LinkedIn post validation to enforce requirements for carousel posts.
  • Improvements

    • Updated LinkedIn provider to handle PDFs, images, and videos more efficiently.
    • Added new translations for the "Post as images carousel" setting in multiple languages.
  • Chores

    • Removed unused JavaScript compiler configuration files.
    • Added the "image-to-pdf" library as a dependency.

Copy link
vercel bot commented Jun 8, 2025

The latest updates on your projects. Learn more about Vercel for Git ↗︎

1 Skipped Deployment
Name Status Preview Comments Updated (UTC)
postiz ⬜️ Ignored (Inspect) Visit Preview Jun 8, 2025 9:05am

Copy link
coderabbitai bot commented Jun 8, 2025

Caution

Review failed

The pull request is closed.

Walkthrough

This update introduces support for posting image carousels as PDFs to LinkedIn, refactoring the LinkedIn provider to handle PDF, image, and video uploads. It adds a user setting for carousel posting, updates DTOs and validation, modifies translations, and adds the "image-to-pdf" dependency. SWC configuration files are also removed.

Changes

File(s) Summary
apps/backend/.swcrc, apps/cron/.swcrc Removed SWC compiler configuration files.
apps/frontend/src/components/launches/providers/linkedin/linkedin.provider.tsx Refactored provider to add a settings UI for "Post as images carousel", updated validation logic, and typing.
libraries/nestjs-libraries/src/dtos/posts/providers-settings/linkedin.dto.ts Added LinkedinDto DTO with optional post_as_images_carousel boolean property.
libraries/nestjs-libraries/src/integrations/social/linkedin.provider.ts Refactored and enhanced LinkedIn provider to support PDF carousels, modularized media handling and posting logic.
libraries/react-shared-libraries/src/translation/locales/*/translation.json (en, ar, bn, de, es, fr, he, it, ja, ko, pt, ru, tr, vi, zh) Added translation key for "Post as images carousel" in multiple locales.
package.json Added "image-to-pdf" dependency.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant Frontend
    participant Backend
    participant LinkedInProvider
    participant LinkedInAPI

    User->>Frontend: Selects "Post as images carousel" and submits post
    Frontend->>Backend: Sends post details with carousel setting
    Backend->>LinkedInProvider: Calls post() with post details and settings
    alt post_as_images_carousel enabled
        LinkedInProvider->>LinkedInProvider: Convert images to PDF carousel
        LinkedInProvider->>LinkedInProvider: Upload PDF document to LinkedIn
    else
        LinkedInProvider->>LinkedInProvider: Upload images/videos as usual
    end
    LinkedInProvider->>LinkedInAPI: Create main post with media
    loop For each additional post
        LinkedInProvider->>LinkedInAPI: Create comment post
    end
    LinkedInProvider->>Backend: Return post response(s)
    Backend->>Frontend: Return post result
Loading

Possibly related PRs

  • Weird behavior with LinkedIn not posting PNG even though it uploads them #481: Both PRs modify the LinkedinProvider class in linkedin.provider.ts focusing on media upload and post creation logic, with the main PR extending functionality to support PDF carousels and refactoring media handling, while the retrieved PR improves image upload processing and error handling for LinkedIn posts.

Poem

🐇
A carousel of images, now bundled as a PDF,
LinkedIn posts get fancier, with logic that's not brief.
Settings for the user, translations up to date,
The code now handles carousels—oh, isn't that great?
With "image-to-pdf" in tow,
Our LinkedIn posts steal the show!

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

libraries/nestjs-libraries/src/integrations/social/linkedin.provider.ts

Oops! Something went wrong! :(

ESLint: 8.57.0

Error [ERR_MODULE_NOT_FOUND]: Cannot find package '@eslint/eslintrc' imported from /eslint.config.mjs
at Object.getPackageJSONURL (node:internal/modules/package_json_reader:255:9)
at packageResolve (node:internal/modules/esm/resolve:767:81)
at moduleResolve (node:internal/modules/esm/resolve:853:18)
at defaultResolve (node:internal/modules/esm/resolve:983:11)
at ModuleLoader.defaultResolve (node:internal/modules/esm/loader:799:12)
at #cachedDefaultResolve (node:internal/modules/esm/loader:723:25)
at ModuleLoader.resolve (node:internal/modules/esm/loader:706:38)
at ModuleLoader.getModuleJobForImport (node:internal/modules/esm/loader:307:38)
at #link (node:internal/modules/esm/module_job:170:49)


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between da60d8f and 8cfd940.

📒 Files selected for processing (1)
  • libraries/nestjs-libraries/src/integrations/social/linkedin.provider.ts (7 hunks)
✨ Finishing Touches
  • 📝 Generate Docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 6

🧹 Nitpick comments (6)
libraries/nestjs-libraries/src/integrations/social/linkedin.provider.ts (6)

385-387: Use a more descriptive filename for the PDF carousel.

The hardcoded filename 'carousel.pdf' is generic and doesn't provide context.

-      url: 'carousel.pdf',
+      url: `linkedin-carousel-${Date.now()}.pdf`,

369-373: Consider handling images with different dimensions more gracefully.

Using only the first image's dimensions for all PDF pages might cause cropping or distortion for images with different aspect ratios.

Consider calculating the maximum dimensions or standardizing all images to a common aspect ratio:

-    const firstImageDimensions = imageData[0];
-    const pageSize = [firstImageDimensions.width, firstImageDimensions.height];
+    // Use the largest dimensions to avoid cropping
+    const maxWidth = Math.max(...imageData.map(img => img.width));
+    const maxHeight = Math.max(...imageData.map(img => img.height));
+    const pageSize = [maxWidth, maxHeight];

468-468: Consider making the image resize width configurable.

The hardcoded width of 1000px might not be optimal for all use cases. LinkedIn supports images up to 7680×4320 pixels.

Consider making this configurable or using LinkedIn's recommended dimensions:

-      .resize({ width: 1000 })
+      .resize({ width: 1200, height: 627, fit: 'inside' }) // LinkedIn's recommended dimensions

481-481: Use a more descriptive title for PDF documents.

The hardcoded title 'slides.pdf' is generic.

-            ...(isPdf ? { title: 'slides.pdf' } : {}),
+            ...(isPdf ? { title: 'Carousel Presentation' } : {}),

550-552: Improve error handling with more descriptive messages.

The current error message is generic and doesn't help with debugging.

-    if (response.status !== 201 && response.status !== 200) {
-      throw new Error('Error posting to LinkedIn');
-    }
+    if (response.status !== 201 && response.status !== 200) {
+      const errorBody = await response.text();
+      throw new Error(`LinkedIn post failed with status ${response.status}: ${errorBody}`);
+    }

657-667: Add error handling for individual comment post failures.

If one comment post fails, it will prevent subsequent posts from being created. Consider continuing with remaining posts.

    for (const post of restPosts) {
+     try {
        const commentPostId = await this.createCommentPost(
          id,
          accessToken,
          post,
          mainPostId,
          type
        );
        responses.push(this.createPostResponse(commentPostId, post.id, false));
+     } catch (error) {
+       // Log error but continue with other posts
+       console.error(`Failed to create comment for post ${post.id}:`, error);
+       responses.push({
+         status: 'failed',
+         postId: '',
+         id: post.id,
+         releaseURL: '',
+         error: error.message
+       });
+     }
    }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9dc9ac3 and 40f71c0.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (7)
  • apps/backend/.swcrc (0 hunks)
  • apps/cron/.swcrc (0 hunks)
  • apps/frontend/src/components/launches/providers/linkedin/linkedin.provider.tsx (1 hunks)
  • libraries/nestjs-libraries/src/dtos/posts/providers-settings/linkedin.dto.ts (1 hunks)
  • libraries/nestjs-libraries/src/integrations/social/linkedin.provider.ts (7 hunks)
  • libraries/react-shared-libraries/src/translation/locales/en/translation.json (1 hunks)
  • package.json (1 hunks)
💤 Files with no reviewable changes (2)
  • apps/backend/.swcrc
  • apps/cron/.swcrc
🧰 Additional context used
🧬 Code Graph Analysis (1)
apps/frontend/src/components/launches/providers/linkedin/linkedin.provider.tsx (5)
libraries/react-shared-libraries/src/translation/get.transation.service.client.ts (1)
  • useT (14-18)
apps/frontend/src/components/launches/helpers/use.values.ts (1)
  • useSettings (87-87)
libraries/react-shared-libraries/src/form/checkbox.tsx (1)
  • Checkbox (6-85)
apps/frontend/src/components/launches/providers/high.order.provider.tsx (1)
  • withProvider (82-668)
libraries/nestjs-libraries/src/dtos/posts/providers-settings/linkedin.dto.ts (1)
  • LinkedinDto (3-7)
⏰ Context from checks skipped due to timeout of 90000ms (3)
  • GitHub Check: build-and-publish
  • GitHub Check: build (20.17.0)
  • GitHub Check: build (20.17.0)
🔇 Additional comments (12)
package.json (1)

152-152:

✅ Verification successful

Verify the image-to-pdf package version and security status.

The addition of the image-to-pdf dependency supports the new LinkedIn carousel feature. Please verify that version ^3.0.2 is valid, actively maintained, and free from security vulnerabilities.


🌐 Web query:

Is image-to-pdf version 3.0.2 a valid npm package version and are there any known security vulnerabilities?

💡 Result:

Based on the search results, image-to-pdf version 3.0.2 is indeed a valid npm package version. It is the latest version of the package as mentioned in multiple search results[1][3]. The package was last published approximately 5 months ago according to the information from January 2025[1], which would be around January 2025.

The image-to-pdf package is a simple image to PDF converter that accepts PNG and JPEG formats as input. These can be passed as base64, Buffer, or file paths[1]. The package allows you to convert images to PDF documents with various page size options, including preset sizes like A4 or custom sizes specified as [x, y] coordinates[1].

Regarding security vulnerabilities, there are no specific mentions of security issues for version 3.0.2 of the image-to-pdf package in the provided search results. The search results do mention vulnerabilities in other PDF-related npm packages such as pdf-image (versions ≤ 2.0.0), which had issues like command injection due to unescaped string parameters[6][9], but these are unrelated to the image-to-pdf package.

It's worth noting that the package appears to be actively maintained, as evidenced by its recent version release. The package is also well-documented with examples provided for CommonJS, ECMAScript, and TypeScript implementations[1][3].

Citations:


Dependency image-to-pdf@^3.0.2 is valid and secure

  • Confirmed version 3.0.2 is the latest release (published ~January 2025)
  • Package is actively maintained and well-documented
  • No known security vulnerabilities for this version

The addition of image-to-pdf@^3.0.2 can proceed safely.

libraries/react-shared-libraries/src/translation/locales/en/translation.json (1)

485-486: LGTM! Translation addition is well-structured.

The new translation key follows existing naming conventions and provides clear labeling for the LinkedIn carousel feature. The trailing comma maintains valid JSON syntax.

libraries/nestjs-libraries/src/dtos/posts/providers-settings/linkedin.dto.ts (1)

1-7: LGTM! Clean and correct DTO implementation.

The DTO follows NestJS best practices with proper validation decorators. The optional boolean property is well-suited for the carousel feature flag.

apps/frontend/src/components/launches/providers/linkedin/linkedin.provider.tsx (4)

2-5: LGTM! Imports are well-organized and necessary.

All imports are appropriately used in the component implementation and follow the project's import structure.


7-22: LGTM! Settings component is well-implemented.

The LinkedInSettings component follows React best practices:

  • Proper use of hooks for translation and form state
  • Correct form registration with default value
  • Appropriate use of the Checkbox component with proper styling variant

30-36: Excellent validation logic for LinkedIn carousel requirements.

The validation correctly enforces LinkedIn carousel constraints:

  • Requires at least 2 images (minimum for a carousel)
  • Prohibits videos in carousel posts (LinkedIn limitation)
  • Provides clear error messaging

This validation prevents user frustration by catching invalid configurations before posting.


23-50: LGTM! Proper integration with withProvider HOC.

The component correctly:

  • Types the provider with LinkedinDto
  • Passes the settings component and DTO to the HOC
  • Maintains existing validation logic alongside new carousel validation
  • Uses appropriate character limit (3000) for LinkedIn
libraries/nestjs-libraries/src/integrations/social/linkedin.provider.ts (5)

14-16: LGTM! Imports are appropriate for the new functionality.

The new imports support the PDF carousel feature correctly.


404-411: LGTM! Standard stream to buffer conversion.

The implementation correctly handles stream events and errors.


591-606: LGTM! Clean response object creation.

The method properly constructs LinkedIn URLs for both main and comment posts.


502-502: ⚠️ Potential issue

Fix typo in parameter name.

The parameter isPdf is misspelled.

-    isPdf: boolean
+    isPdf: boolean

Likely an incorrect or invalid review comment.


207-207: 🛠️ Refactor suggestion

Make PDF detection case-insensitive.

The current PDF detection is case-sensitive. Files with extensions like .PDF, .Pdf, etc., won't be recognized as PDFs.

-    const isPdf = fileName.toLowerCase().indexOf('pdf') > -1;
+    const isPdf = fileName.toLowerCase().endsWith('.pdf');

Likely an incorrect or invalid review comment.

Comment on lines +567 to +589
const response = await this.fetch(
`https://api.linkedin.com/v2/socialActions/${decodeURIComponent(
parentPostId
)}/comments`,
{
status: 'posted',
postId: topPostId,
id: firstPost.id,
releaseURL: `https://www.linkedin.com/feed/update/${topPostId}`,
},
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${accessToken}`,
},
body: JSON.stringify({
actor,
object: parentPostId,
message: {
text: this.fixText(post.message),
},
}),
}
);

const { object } = await response.json();
return object;
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add error handling for comment post creation.

The method doesn't handle API errors, which could cause the entire post operation to fail.

Add error handling:

if (!response.ok) {
  const errorBody = await response.text();
  throw new Error(`Failed to create comment: ${response.status} - ${errorBody}`);
}
🤖 Prompt for AI Agents
In libraries/nestjs-libraries/src/integrations/social/linkedin.provider.ts
around lines 567 to 589, the code lacks error handling for the API response when
creating a comment. Add a check after the fetch call to verify if response.ok is
false; if so, read the response text and throw an error with the status code and
error body to properly handle API failures and prevent silent errors.

// Return modified post details with PDF instead of images
const modifiedFirstPost = {
...firstPost,
media: [pdfMedia] as any[],
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Avoid using any type casting for better type safety.

The cast to any[] bypasses TypeScript's type checking and could hide potential issues.

Define a proper type for media with buffer:

interface MediaWithBuffer {
  url: string;
  buffer?: Buffer;
}

Then use it instead of any[].

🤖 Prompt for AI Agents
In libraries/nestjs-libraries/src/integrations/social/linkedin.provider.ts at
line 392, avoid casting media to any[] which disables type checking. Define a
MediaWithBuffer interface with url as string and optional buffer as Buffer, then
replace the any[] cast with MediaWithBuffer[] to ensure proper type safety for
the media array.

@nevo-david nevo-david merged commit 9192cc4 into main Jun 8, 2025
6 of 7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant
0