Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
75 commits
Select commit Hold shift + click to select a range
d2e3fc3
feat: add FusionAuth SSO integration and provider
kipsang01 Dec 8, 2025
8680910
feat: enhance FusionAuth integration with redirect validation and err…
kipsang01 Dec 9, 2025
ff0c968
feat: refactor SSO endpoints to support dynamic providers and enhance…
kipsang01 Dec 9, 2025
8d7e86b
Feat: Add apm logging
kipsang01 Dec 9, 2025
86e6f18
feat: add GitHub Actions workflow for building and pushing Docker images
kipsang01 Dec 9, 2025
9c8a7e3
Merge pull request #1 from truehostcloud/feat/fusion-auth
kipsang01 Dec 9, 2025
1235679
feat: add Elastic APM RUM dependency and remove captureExceptions fro…
kipsang01 Dec 9, 2025
fa94cfc
Merge pull request #2 from truehostcloud/feat/fusion-auth
kipsang01 Dec 9, 2025
8137b79
feat: update Docker Hub login action to use DOCKERHUB_PASSWORD secret
kipsang01 Dec 9, 2025
7ea0bf4
Merge pull request #3 from truehostcloud/feat/fusion-auth
kipsang01 Dec 9, 2025
7ae9ddb
feat: no follow in terms and privacy
nevo-david Dec 9, 2025
1f72797
Merge remote-tracking branch 'origin/main'
nevo-david Dec 9, 2025
8e30271
Temporarily disable ESLint
egelhaus Dec 9, 2025
6c4cf41
fix(ci): Force fresh base image in Docker builds
adambkovacs Dec 15, 2025
41090bd
Merge pull request #1118 from adambkovacs/fix/docker-build-fresh-base…
egelhaus Dec 15, 2025
f4ce7f7
feat: register change
nevo-david Dec 18, 2025
7294cad
feat: branded signin-signup
nevo-david Dec 18, 2025
e066804
Merge remote-tracking branch 'origin/main'
nevo-david Dec 18, 2025
b7ce23c
fix: mobile cons
nevo-david Dec 18, 2025
022f9bf
feat: width change
nevo-david Dec 19, 2025
991d354
feat: billing change
nevo-david Dec 22, 2025
0fe1097
feat: billing change
nevo-david Dec 22, 2025
e6f2d87
feat: extension
nevo-david Dec 22, 2025
59d0df5
feat: package upgrade
nevo-david Dec 22, 2025
1114bbd
feat: old layout remove
nevo-david Dec 22, 2025
9c2abfb
feat: nextjs upgrade
nevo-david Dec 22, 2025
3e04076
feat: check payment
nevo-david Dec 22, 2025
8d0b4a1
feat: upgrade old packages
nevo-david Dec 22, 2025
eaec9bf
feat: neyner fix
nevo-david Dec 22, 2025
d43690e
feat: force nextjs version
nevo-david Dec 22, 2025
0690d0b
feat: logo fix
nevo-david Dec 22, 2025
21f0b64
feat: trailing
nevo-david Dec 22, 2025
f4dec2e
feat: powered by
nevo-david Dec 22, 2025
63c3e1c
fix: tolt
nevo-david Dec 22, 2025
ec623a6
fix: discord support
nevo-david Dec 22, 2025
37c4574
feat: refactor for creation modal
nevo-david Dec 25, 2025
f5dff1e
feat: svg change
nevo-david Dec 25, 2025
74b84b5
feat: fix information display
nevo-david Dec 25, 2025
d4f18d1
HOT FIX
nevo-david Dec 26, 2025
2497bd1
feat: add WebP image upload support
Fer-r Dec 26, 2025
0043029
Merge pull request #1138 from Fer-r/feature/webp-image-upload-support
egelhaus Dec 26, 2025
1da332e
feat: sentry errors
nevo-david Dec 26, 2025
13137e8
Merge remote-tracking branch 'origin/main'
nevo-david Dec 26, 2025
70d0724
faet: remove comments
nevo-david Dec 26, 2025
1c61e76
fix: better block view
nevo-david Dec 26, 2025
f98ae08
feat: fix monthly yearly
nevo-david Dec 26, 2025
6f889d4
feat: responsive payment
nevo-david Dec 26, 2025
90da9d4
fix: pagination
nevo-david Dec 27, 2025
0d134c0
feat: editor bug fixes, some previews
nevo-david Dec 27, 2025
2cf0d63
feat: editor bug fixes, some previews
nevo-david Dec 27, 2025
8c1191a
fix: full screen settings
nevo-david Dec 27, 2025
9c751fb
feat: provider checks protection
nevo-david Dec 28, 2025
a188baa
feat: calendar skeleton
nevo-david Dec 28, 2025
5f945bd
feat: color changes
nevo-david Dec 28, 2025
e0b496c
feat: settings change
nevo-david Dec 28, 2025
3387b3c
feat: higher concurrency rate for facebook
nevo-david Dec 28, 2025
7a82798
feat: fix throttler
nevo-david Dec 28, 2025
b906242
feat: fix linkedin pdf
nevo-david Dec 28, 2025
e5a4c55
feat: fix throttle
nevo-david Dec 28, 2025
00caa7d
feat: moving to dub partners
nevo-david Dec 28, 2025
ca941ae
fix: customer
nevo-david Dec 28, 2025
6729de4
fix: hot fix for modal creation
nevo-david Dec 29, 2025
0e5d6f8
fix: hot fix for modal creation
nevo-david Dec 29, 2025
faef577
feat: generator
nevo-david Dec 29, 2025
5f4de7c
feat: fullscreen
nevo-david Dec 29, 2025
44f190d
Update README.md
nevo-david Dec 31, 2025
c8c812e
feat: fix additional settings modal
nevo-david Jan 1, 2026
4f0f4c2
Merge remote-tracking branch 'origin/main'
nevo-david Jan 1, 2026
b3d298d
fix: change vietnam flag
nevo-david Jan 1, 2026
cd085e2
feat: more translations
nevo-david Jan 1, 2026
9e0eff7
feat: payload wizard
nevo-david Jan 3, 2026
263e503
Merge pull request #5 from gitroomhq/main
kipsang01 Jan 5, 2026
c927a50
Merge branch 'staging' of https://github.com/truehostcloud/postiz-app…
kipsang01 Jan 5, 2026
ac0ba30
feat: update dependencies for Elastic APM
kipsang01 Jan 5, 2026
8519dda
feat: add repository condition to workflow jobs
kipsang01 Jan 6, 2026
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
13 changes: 13 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,19 @@ POSTIZ_OAUTH_CLIENT_ID=""
POSTIZ_OAUTH_CLIENT_SECRET=""
# POSTIZ_OAUTH_SCOPE="openid profile email" # default values

# === Elastic APM (optional)
# Backend / Workers APM configuration
# Set `ELASTIC_APM_SERVICE_NAME` to identify the service
ELASTIC_APM_SERVICE_NAME="postiz-backend"
# APM Server URL (APM Server default port is 8200)
ELASTIC_APM_SERVER_URL="http://localhost:8200"

# Frontend (RUM) configuration — exposed to the browser
NEXT_PUBLIC_ELASTIC_APM_SERVER_URL="http://localhost:8200"
NEXT_PUBLIC_ELASTIC_APM_SERVICE_NAME="postiz-frontend"
# Public frontend URL used for distributed tracing origins
NEXT_PUBLIC_FRONTEND_URL="http://localhost:4200"

# Short Link Service Settings
# DUB_TOKEN="" # Your self-hosted Dub API token
# DUB_API_ENDPOINT="https://api.dub.co" # Your self-hosted Dub API endpoint
Expand Down
86 changes: 86 additions & 0 deletions .github/workflows/build-and-push-dockerhub.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
name: Build and Push Docker Hub Images

on:
workflow_dispatch:
push:
branches:
- main
- staging
- dev

jobs:
build-push:
name: Build and Push
runs-on: ubuntu-latest

steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Set short SHA and tag base
id: set-vars
run: |
SHORT_SHA=$(git rev-parse --short=8 HEAD)
BRANCH=${GITHUB_REF#refs/heads/}
if [ "$BRANCH" = "main" ]; then
TAG_BASE=prod
elif [ "$BRANCH" = "staging" ] || [ "$BRANCH" = "dev" ]; then
TAG_BASE=dev
else
echo "Branch '$BRANCH' is not configured for Docker push. Exiting.";
exit 0
fi
echo "short_sha=$SHORT_SHA" >> "$GITHUB_OUTPUT"
echo "tag_base=$TAG_BASE" >> "$GITHUB_OUTPUT"

- name: Prepare image tags
id: prepare-tags
run: |
TAG_BASE=${{ steps.set-vars.outputs.tag_base }}
SHORT_SHA=${{ steps.set-vars.outputs.short_sha }}
USER=${{ secrets.DOCKERHUB_USERNAME }}
TAGS="docker.io/${USER}/postiz-app:${TAG_BASE}\ndocker.io/${USER}/postiz-app:${TAG_BASE}-${SHORT_SHA}"
if [ "${TAG_BASE}" = "prod" ]; then
TAGS="${TAGS}\ndocker.io/${USER}/postiz-app:latest"
fi
echo "Preparing tags:\n$TAGS"
echo "tags<<EOF" >> $GITHUB_OUTPUT
echo -e "$TAGS" >> $GITHUB_OUTPUT
echo "EOF" >> $GITHUB_OUTPUT

- name: Set up QEMU
uses: docker/setup-qemu-action@v2

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Log in to Docker Hub
uses: docker/login-action@v3
with:
registry: docker.io
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_PASSWORD }}

- name: Build and push multi-arch image
uses: docker/build-push-action@v4
with:
context: .
file: Dockerfile.dev
platforms: linux/amd64,linux/arm64
push: true
cache-from: type=gha
cache-to: type=gha,mode=max
tags: ${{ steps.prepare-tags.outputs.tags }}
build-args: |
NEXT_PUBLIC_VERSION=${{ steps.set-vars.outputs.short_sha }}
labels: |
org.opencontainers.image.revision=${{ steps.set-vars.outputs.short_sha }}
org.opencontainers.image.source=${{ github.repository }}

- name: Verify pushed image (list)
run: |
echo "Pushed tags:"
echo "docker.io/${{ secrets.DOCKERHUB_USERNAME }}/postiz-app:${{ steps.set-vars.outputs.tag_base }}"
echo "docker.io/${{ secrets.DOCKERHUB_USERNAME }}/postiz-app:${{ steps.set-vars.outputs.tag_base }}-${{ steps.set-vars.outputs.short_sha }}"
5 changes: 5 additions & 0 deletions .github/workflows/build-containers.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ on:

jobs:
build-containers-common:
if: github.repository == 'gitroomhq/postiz-app'
runs-on: ubuntu-latest
outputs:
containerver: ${{ steps.getcontainerver.outputs.containerver }}
Expand All @@ -19,6 +20,7 @@ jobs:
echo "containerver=${{ github.ref_name }}" >> "$GITHUB_OUTPUT"

build-containers:
if: github.repository == 'gitroomhq/postiz-app'
needs: build-containers-common
strategy:
matrix:
Expand Down Expand Up @@ -53,10 +55,13 @@ jobs:
-f Dockerfile.dev \
-t ghcr.io/gitroomhq/postiz-app:${{ env.CONTAINERVER }}-${{ matrix.arch }} \
--build-arg NEXT_PUBLIC_VERSION=${{ env.NEXT_PUBLIC_VERSION }} \
--pull \
--no-cache \
--provenance=false --sbom=false \
--output "type=registry,name=ghcr.io/gitroomhq/postiz-app:${{ env.CONTAINERVER }}-${{ matrix.arch }}" .

build-container-manifest:
if: github.repository == 'gitroomhq/postiz-app'
needs: [build-containers, build-containers-common]
runs-on: ubuntu-latest
steps:
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/build-extension.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ on:

jobs:
submit:
if: github.repository == 'gitroomhq/postiz-app'
runs-on: ubuntu-latest

steps:
Expand Down
3 changes: 3 additions & 0 deletions .github/workflows/codeql.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ jobs:
analyze:
name: Analyze (${{ matrix.language }})

# Upstream-only: forks often don't want/need security event uploads
if: github.repository == 'gitroomhq/postiz-app'

runs-on: 'ubuntu-latest'
permissions:
security-events: write
Expand Down
2 changes: 2 additions & 0 deletions .github/workflows/eslint.yml → .github/workflows/eslint
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ on:
jobs:
eslint:
name: Run eslint scanning
# Upstream-only: forks often don't want/need SARIF security uploads
if: github.repository == 'gitroomhq/postiz-app'
runs-on: ubuntu-latest
permissions:
contents: read
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/issue-label-triggers.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ on:

jobs:
closed-public-website:
if: github.event.label.name == 'trigger-public-website'
if: github.repository == 'gitroomhq/postiz-app' && github.event.label.name == 'trigger-public-website'
runs-on: ubuntu-latest
permissions:
issues: write
Expand Down
13 changes: 7 additions & 6 deletions .github/workflows/pr-docker-build.yml
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
name: Build and Publish PR Docker Image
name: Build and Publish PR Docker Image (manual)

on:
pull_request_target:
types: [opened, synchronize]
workflow_dispatch:

permissions: write-all
# Automatic PR image pushes are disabled in this fork (PR images not required).
# Trigger this workflow manually if you ever need to build/push a PR image.

jobs:
build-and-publish:
if: github.repository == 'gitroomhq/postiz-app'
runs-on: ubuntu-latest

environment:
Expand All @@ -18,7 +19,7 @@ jobs:
uses: actions/checkout@v4
with:
fetch-depth: 0
ref: ${{ github.event.pull_request.head.sha }}
ref: ${{ github.sha }}

- name: Log in to GitHub Container Registry
uses: docker/login-action@v3
Expand All @@ -29,7 +30,7 @@ jobs:

- name: Set image tag
id: vars
run: echo "IMAGE_TAG=ghcr.io/gitroomhq/postiz-app-pr:${{ github.event.pull_request.number }}" >> $GITHUB_ENV
run: echo "IMAGE_TAG=ghcr.io/gitroomhq/postiz-app-pr:${{ github.run_id }}" >> $GITHUB_ENV

- name: Build Docker image from Dockerfile.dev
run: docker build -f Dockerfile.dev -t $IMAGE_TAG .
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/publish-extension.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ on:

jobs:
submit:
if: github.repository == 'gitroomhq/postiz-app'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ Link: https://opencollective.com/postiz

## Star History

[![Star History Chart](https://api.star-history.com/svg?repos=gitroomhq/postiz-app&type=Date)](https://www.star-history.com/#gitroomhq/postiz-app&Date)
[![Star History Chart](https://api.star-history.com/svg?repos=gitroomhq/postiz-app&type=date&legend=top-left)](https://www.star-history.com/#gitroomhq/postiz-app&type=date&legend=top-left)

## License

Expand Down
2 changes: 1 addition & 1 deletion apps/backend/src/api/routes/agencies.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { CreateAgencyDto } from '@gitroom/nestjs-libraries/dtos/agencies/create.
export class AgenciesController {
constructor(private _agenciesService: AgenciesService) {}
@Get('/')
async getAgencyByUsers(@GetUserFromRequest() user: User) {
async getAgencyByUser(@GetUserFromRequest() user: User) {
return (await this._agenciesService.getAgencyByUser(user)) || {};
}

Expand Down
127 changes: 127 additions & 0 deletions apps/backend/src/api/routes/auth.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -268,4 +268,131 @@ export class AuthController {
login: true,
});
}

@Get('/sso/:provider')
async ssoCallbackGet(
@Param('provider') provider: string,
@Query('code') code: string,
@Query('redirect') redirect: string,
@Res({ passthrough: false }) response: Response,
@RealIP() ip: string,
@UserAgent() userAgent: string
) {
return this.handleSso({
provider,
token: code,
response,
ip,
userAgent,
redirect: redirect || process.env.FRONTEND_URL || '/',
});
}

@Post('/sso/:provider')
async ssoCallbackPost(
@Param('provider') provider: string,
@Body('code') code: string,
@Body('assertion') assertion: string,
@Query('redirect') redirect: string,
@Res({ passthrough: false }) response: Response,
@RealIP() ip: string,
@UserAgent() userAgent: string
) {
return this.handleSso({
provider,
token: code || assertion,
response,
ip,
userAgent,
redirect: redirect || process.env.FRONTEND_URL || '/',
});
}

private async handleSso({
provider,
token,
response,
ip,
userAgent,
redirect,
}: {
provider: string;
token: string;
response: Response;
ip: string;
userAgent: string;
redirect?: string;
}) {
try {
const providerValue = Provider[provider?.toUpperCase() as keyof typeof Provider];
if (!providerValue) {
return response.status(400).send('Unsupported provider');
}

if (!token) {
return response.status(400).send('Missing code');
}

const { jwt, addedOrg } = await this._authService.sso(
providerValue as unknown as string,
token,
ip,
userAgent
);

response.cookie('auth', jwt, {
domain: getCookieUrlFromDomain(process.env.FRONTEND_URL!),
...(!process.env.NOT_SECURED
? {
secure: true,
httpOnly: true,
sameSite: 'none',
}
: {}),
expires: new Date(Date.now() + 1000 * 60 * 60 * 24 * 365),
});

if (process.env.NOT_SECURED) {
response.header('auth', jwt);
}

if (typeof addedOrg !== 'boolean' && addedOrg?.organizationId) {
response.cookie('showorg', addedOrg.organizationId, {
domain: getCookieUrlFromDomain(process.env.FRONTEND_URL!),
...(!process.env.NOT_SECURED
? {
secure: true,
httpOnly: true,
sameSite: 'none',
}
: {}),
expires: new Date(Date.now() + 1000 * 60 * 60 * 24 * 365),
});

if (process.env.NOT_SECURED) {
response.header('showorg', addedOrg.organizationId);
}
}

if (redirect) {
const allowedDomain = new URL(process.env.FRONTEND_URL!).hostname;
const redirectUrl = new URL(redirect, process.env.FRONTEND_URL!);
if (redirectUrl.hostname !== allowedDomain) {
return response.status(400).send('Invalid redirect domain');
}
return response.redirect(302, redirectUrl.toString());
}

response.header('reload', 'true');
return response.status(200).json({ login: true });
} catch (e: any) {
if (redirect) {
const url = new URL(redirect, process.env.FRONTEND_URL || undefined);
url.searchParams.set('sso', 'failed');
return response.redirect(302, url.toString());
}

return response.status(400).send(e.message || 'SSO failed');
}
}
}
17 changes: 17 additions & 0 deletions apps/backend/src/api/routes/billing.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,23 @@ export class BillingController {
};
}

@Post('/embedded')
embedded(
@GetOrgFromRequest() org: Organization,
@GetUserFromRequest() user: User,
@Body() body: BillingSubscribeDto,
@Req() req: Request
) {
const uniqueId = req?.cookies?.track;
return this._stripeService.embedded(
uniqueId,
org.id,
user.id,
body,
org.allowTrial
);
}

@Post('/subscribe')
subscribe(
@GetOrgFromRequest() org: Organization,
Expand Down
Loading
Loading