3136 Commits

Author SHA1 Message Date
Andrey Antukh
9e681260cc
🐛 Fix incorrect invitation token handling on register process (#9380)
* 🐛 Fix incorrect invitation token handling on register process

- Reject prepare-register-profile when an active profile already
  exists for the requested email.
- Stop embedding an existing profile's :profile-id into the
  prepared-register JWE. Profile resolution in register-profile is
  now done exclusively by email lookup, never by a JWE claim.
- Add created? guard to the invitation-success branch in
  register-profile, so existing profiles (active or not) cannot
  reach session creation via anonymous registration.

Signed-off-by: Andrey Antukh <niwi@niwi.nz>

* ♻️ Restructure invitation handling inside register-profile

Move the invitation-success branch into the created? sub-cond so it
sits alongside the other post-creation branches, making the control
flow consistent.

- Active new profile + matching invitation: mint session and return
  :invitation-token (frontend redirects to :auth-verify-token).
- Not-yet-active new profile + matching invitation: embed the
  invitation token inside the verify-email JWE and send the
  verification email. When the user clicks the link, they get
  logged in and the frontend completes the team-invitation flow.
- Extend send-email-verification! with an optional invitation-token
  parameter propagated into the verify-email JWE claims.
- Update the frontend verify-email handler to navigate to
  :auth-verify-token when the response carries :invitation-token.

Signed-off-by: Andrey Antukh <niwi@niwi.nz>

* 🐛 Handle email-already-exists error on registration form

Add a specific handler for the [:validation :email-already-exists] error
code in the registration form's on-error callback. The backend raises
this error when an active profile already exists for the requested email,
but the frontend was falling through to the generic error message.

Now it shows the existing "Email already used" i18n message instead of
the generic "Something wrong has happened" toast.

* 🐛 Reset submitted state on registration form error

The on-error handler in the registration form was not resetting the
submitted? state, causing the submit button to remain disabled after
any error. The completion callback in rx/subs! only fires on success,
not on error.

Add (reset! submitted? false) at the beginning of the on-error handler
so the form becomes submittable again after any error, allowing the user
to fix their input and retry.

---------

Signed-off-by: Andrey Antukh <niwi@niwi.nz>
2026-05-06 14:20:55 +02:00
Yamila Moreno
d627d1cfac
Improve team name validation (#9176) 2026-04-29 08:59:09 +02:00
Andrey Antukh
57f1b80013 Merge remote-tracking branch 'origin/main' into main-staging 2026-04-27 17:26:30 +02:00
Andrey Antukh
cbd5f7795b Add minor compatibility adjustments for audit archive task (#8491) 2026-04-27 16:15:35 +02:00
Andrey Antukh
feec89679a Merge remote-tracking branch 'origin/main' into main-staging 2026-04-27 09:58:13 +02:00
Yamila Moreno
7031052c4e 🐛 Prevent invitations to blacklisted domains 2026-04-24 16:48:59 +02:00
Andrey Antukh
0b6416e53b Merge remote-tracking branch 'origin/main' into main-staging 2026-04-24 14:09:03 +02:00
Andrey Antukh
d380efdb0c
⬆️ Update devenv dependencies (#9142)
* ⬆️ Update devenv dependencies

*  Fix formatting issues

* 📎 Fix linter issues
2026-04-24 14:07:51 +02:00
Andrey Antukh
fd38f5b431 Merge remote-tracking branch 'origin/main' into main-staging 2026-04-24 08:18:55 +02:00
Yamila Moreno
5f7de04efe
🚑 Fix email blacklisting (#9122) 2026-04-23 09:42:40 +02:00
Andrey Antukh
97d234a566 Add 2h min-age threshold to storage/gc_touched task
Skip storage objects touched less than 2 hours ago, matching the pattern
used by upload-session-gc. Update all affected tests to advance the clock
past the threshold using ct/*clock* bindings.
2026-04-22 08:48:04 +02:00
Andrey Antukh
e5f9c1e863 🎉 Add chunked upload API for large media and binary files
Introduce a purpose-agnostic three-step session-based upload API that
allows uploading large binary blobs (media files and .penpot imports)
without hitting multipart size limits.

Backend:
- Migration 0147: new `upload_session` table (profile_id, total_chunks,
  created_at) with indexes on profile_id and created_at.
- Three new RPC commands in media.clj:
    * `create-upload-session`  – allocates a session row; enforces
      `upload-sessions-per-profile` and `upload-chunks-per-session`
      quota limits (configurable in config.clj, defaults 5 / 20).
    * `upload-chunk`           – stores each slice as a storage object;
      validates chunk index bounds and profile ownership.
    * `assemble-file-media-object` – reassembles chunks via the shared
      `assemble-chunks!` helper and creates the final media object.
- `assemble-chunks!` is a public helper in media.clj shared by both
  `assemble-file-media-object` and `import-binfile`.
- `import-binfile` (binfile.clj): accepts an optional `upload-id` param;
  when provided, materialises the temp file from chunks instead of
  expecting an inline multipart body, removing the 200 MiB body limit
  on .penpot imports.  Schema updated with an `:and` validator requiring
  either `:file` or `:upload-id`.
- quotes.clj: new `upload-sessions-per-profile` quota check.
- Background GC task (`tasks/upload_session_gc.clj`): deletes stalled
  (never-completed) sessions older than 1 hour; scheduled daily at
  midnight via the cron system in main.clj.
- backend/AGENTS.md: document the background-task wiring pattern.

Frontend:
- New `app.main.data.uploads` namespace: generic `upload-blob-chunked`
  helper drives steps 1–2 (create session + upload all chunks with a
  concurrency cap of 2) and emits `{:session-id uuid}` for callers.
- `config.cljs`: expose `upload-chunk-size` (default 25 MiB, overridable
  via `penpotUploadChunkSize` global).
- `workspace/media.cljs`: blobs ≥ chunk-size go through the chunked path
  (`upload-blob-chunked` → `assemble-file-media-object`); smaller blobs
  use the existing direct `upload-file-media-object` path.
  `handle-media-error` simplified; `on-error` callback removed.
- `worker/import.cljs`: new `import-blob-via-upload` helper replaces the
  inline multipart approach for both binfile-v1 and binfile-v3 imports.
- `repo.cljs`: `:upload-chunk` derived as a `::multipart-upload`;
  `form-data?` removed from `import-binfile` (JSON params only).

Tests:
- Backend (rpc_media_test.clj): happy path, idempotency, permission
  isolation, invalid media type, missing chunks, session-not-found,
  chunk-index out-of-range, and quota-limit scenarios.
- Frontend (uploads_test.cljs): session creation and chunk-count
  correctness for `upload-blob-chunked`.
- Frontend (workspace_media_test.cljs): direct-upload path for small
  blobs, chunked path for large blobs, and chunk-count correctness for
  `process-blobs`.
- `helpers/http.cljs`: shared fetch-mock helpers (`install-fetch-mock!`,
  `make-json-response`, `make-transit-response`, `url->cmd`).

Signed-off-by: Andrey Antukh <niwi@niwi.nz>
2026-04-21 18:51:10 +00:00
Andrey Antukh
a395768987 🐛 Fix incorrect handlig of version restore operation (#9041)
- Add session ID tracking to RPC layer (backend and frontend)
- Send session ID header with RPC requests for request correlation
- Rename file-restore to file-restored for consistency
- Extract initialize-file function from initialize-workspace flow
- Improve file restoration initialization with wait-for-persistence
- Extract initialize-version event handler for version restoration
- Fix viewport key generation with file version numbers for proper re-renders
- Update layout item schema and constraints to use internal sizing state
- Add v-sizing state retrieval in layout-size-constraints component
- Refactor file-change notifications stream handling with rx/map
- Fix team-id lookup in restore-version-from-plugins

Improves request traceability across frontend/backend sessions and streamlines
the workspace initialization flow for file restoration scenarios.

Signed-off-by: Andrey Antukh <niwi@niwi.nz>
2026-04-21 20:50:41 +02:00
Andrey Antukh
3a39676969 Backport MCP from staging (part 1) 2026-04-20 19:37:02 +02:00
Andrey Antukh
de27ea904d
Add minor adjustments to the auth events (#9027) 2026-04-16 09:59:45 +02:00
Andrey Antukh
c8675c5b7e
♻️ Normalize newsletter-updates checbox on different register flows (#8839)
*  Add newsletter opt-in checkbox to registration validation form

Add accept-newsletter-updates support through the full registration
token flow. The newsletter checkbox is now available on the
registration validation form, allowing users to opt-in during the
email verification step.

Backend changes:
- Refactor prepare-register to consolidate UTM params and newsletter
  preference into props at token creation time
- Add accept-newsletter-updates to prepare-register-profile and
  register-profile schemas
- Handle newsletter-updates in register-profile by updating token
  claims props on second step

Frontend changes:
- Add newsletter-options component to register-validate-form
- Add accept-newsletter-updates to validation schema
- Fix subscription finalize/error handling in register form

Signed-off-by: Andrey Antukh <niwi@niwi.nz>

* ♻️ Refactor auth register components to modern style

Migrate all components in app.main.ui.auth.register and
app.main.ui.auth.login/demo-warning to use the modern * suffix
convention, removing deprecated ::mf/props :obj metadata and
updating all invocations from [:& name] to [:> name*] syntax.

Components updated:
- terms-and-privacy -> terms-and-privacy*
- register-form -> register-form*
- register-methods -> register-methods*
- register-page -> register-page*
- register-success-page -> register-success-page*
- terms-register -> terms-register*
- register-validate-form -> register-validate-form*
- register-validate-page -> register-validate-page*
- demo-warning -> demo-warning*

Also remove unused old context-notification import in login.cljs.

Signed-off-by: Andrey Antukh <niwi@niwi.nz>

* 🔥 Remove unused onboarding-newsletter component

The newsletter opt-in is now handled directly in the registration
form via the newsletter-options* component, making the standalone
onboarding-newsletter modal obsolete.

Signed-off-by: Andrey Antukh <niwi@niwi.nz>

* 🐛 Fix register test for UTM params to use prepare-register step

UTM params are now extracted and stored in token props during the
prepare-register step, not at register-profile time. Move utm_campaign
and mtm_campaign from the register-profile call to the
prepare-register-profile call in the test.

Signed-off-by: Andrey Antukh <niwi@niwi.nz>

---------

Signed-off-by: Andrey Antukh <niwi@niwi.nz>
2026-04-08 17:00:52 +02:00
Andrey Antukh
81b1b253f1
Add unique email domains to telemetry report (#8819)
Extend the telemetry payload with a sorted list of unique email domains
extracted from all registered profile email addresses. The new
:email-domains field is populated via a single SQL query using
split_part and DISTINCT, and is included in the stats sent when
telemetry is enabled.

Also update the tasks-telemetry-test to assert the new field is present
and contains the expected domain values.
2026-04-01 11:49:50 +02:00
Andrey Antukh
0dfa62a5b6
🐛 Improve error reporting on request parsing failures (#8805)
Include request URI and status in frontend handle-response error data,
and add request path/context to backend IOException handler logs and
response body. Previously these errors had no identifying information
about which endpoint or request caused the failure.
2026-03-26 15:42:49 +01:00
Andrey Antukh
cc03f3f884 📚 Add minor improvements to ai agents documentation 2026-03-24 18:00:39 +01:00
Andrey Antukh
2d616cf9c0
📚 Add better organization for AGENTS.md file (#8675) 2026-03-18 14:59:38 +01:00
Andrey Antukh
7ec9261475
Add improvements to AGENTS.md (#8586) 2026-03-11 15:24:40 +01:00
Andrey Antukh
ab90500ec8 🐛 Fix download-image to properly handle network errors and non-2xx responses (#8554)
The download-image function in app.media silently succeeded when the
remote image URL was unreachable or returned an error status code,
causing create-file-media-object-from-url to report success with no
actual image stored.

Add exception handling for connection refused, timeouts, and I/O errors
around the HTTP request, and validate the HTTP status code in
parse-and-validate before processing the response body.

Fixes #8499

Signed-off-by: Andrey Antukh <niwi@niwi.nz>
2026-03-10 15:01:23 +01:00
Andrey Antukh
0f47c30349 Merge branch 'main' into staging 2026-03-10 14:39:16 +01:00
Andrey Antukh
68fbacf8b3 Merge tag '2.14.0-RC2' 2026-03-10 14:38:58 +01:00
Andrey Antukh
32cf95265a 📚 Add GitHub Copilot instructions (#8548) 2026-03-10 13:12:15 +01:00
Andrey Antukh
77955d7f91 Add several redundant checks for library-id on file rpc methods 2026-03-09 10:01:29 +01:00
Andrey Antukh
151238e518 💄 Add cosmetic change to link-file-to-library rpc method impl 2026-03-09 10:01:29 +01:00
Andrey Antukh
86e851f408
🐛 Fix incorrect version visibility on workspace (#8463)
* 🐛 Add missing order by clause to snapshot query

This fixes the incorrect snapshot visibility when file
has a lot of versions.

*  Reduce allocation on milestone-group* component

* 🐛 Fix milestone group timestamp formatting

* 📎 Update changelog

* 🐛 Fix scroll on history panel

---------

Co-authored-by: Eva Marco <evamarcod@gmail.com>
2026-03-04 09:27:51 +01:00
Andrey Antukh
a4351d133b
Add minor improvements to error reporting (#8402) 2026-03-04 09:12:19 +01:00
Andrey Antukh
1b8afccba2 Remove usage of multipart body size config on backend 2026-02-23 14:44:44 +01:00
Andrey Antukh
3909bc0fc1 Merge remote-tracking branch 'origin/main' into staging 2026-02-16 14:17:46 +01:00
Andrey Antukh
b6427ecaac 🐛 Revert yetti upgrade
Because of regression introduced on undertow-core 2.3.19
2026-02-16 14:16:29 +01:00
Andrey Antukh
4a7b89a1da
Merge pull request #8327 from penpot/niwinz-develop-rlimit-notifications
 Add proper mattermost notifications for rlimit rejects
2026-02-13 17:11:54 +01:00
Andrey Antukh
12bc3ac9ed Update default cors headers 2026-02-13 13:17:08 +01:00
Sagar
cfcebf59d5
🐛 Make S3Client and S3Presigner use identical credential resolution (#8316) 2026-02-13 12:21:05 +01:00
Andrey Antukh
920fbe34ad 🐛 Fix invalid deps passed to http management routes service 2026-02-10 13:46:29 +01:00
Andrey Antukh
f08700945a Merge remote-tracking branch 'origin/staging' into develop 2026-02-10 11:58:09 +01:00
Andrey Antukh
06e5825c8a 🐛 Add proper input checking to font related RCP method 2026-02-10 10:36:57 +01:00
Pablo Alba
5d3ccbc8b4
Add managed profiles endpoint to nitrate api (#8292) 2026-02-09 15:52:18 +01:00
Andrey Antukh
ac1c3ff184 Merge branch 'staging-render' into develop 2026-02-09 14:14:02 +01:00
Andrey Antukh
43cd92c76d Merge remote-tracking branch 'origin/staging' into staging-render 2026-02-09 14:12:55 +01:00
Alejandro Alonso
3d20fc508d
🐛 Fix image magick info call (#8300) 2026-02-09 12:26:42 +01:00
Andrey Antukh
2ccb33ba89 📎 Add missing for-update for the migration 145 2026-02-05 18:12:11 +01:00
Andrey Antukh
ee88ee63a2 Add data migration for fix plugins data on profiles 2026-02-05 18:08:28 +01:00
Andrey Antukh
1656fefdc9 Merge remote-tracking branch 'origin/staging-render' into develop 2026-02-04 16:23:46 +01:00
Andrey Antukh
7f318bb110 Merge remote-tracking branch 'origin/staging' into staging-render 2026-02-04 16:22:13 +01:00
Andrey Antukh
06afd94a74 ⬆️ Update backend dependencies (mainly bugfixes) 2026-02-04 16:21:19 +01:00
Andrey Antukh
ca4d00df69 🐛 Fix latest error report related migration 2026-02-04 15:36:07 +01:00
Andrey Antukh
9667477d6b 🐛 Add missing dep for rpc routes on backend 2026-02-04 15:26:02 +01:00
Andrey Antukh
d80ba1856a
Add several improvements to frontend error reporting
*  Add major improvement on error handling

*  Add the ability to store frontend reports

* 📎 Add PR feedback changes
2026-02-04 12:45:38 +01:00