Commit Graph

8573 Commits

Author SHA1 Message Date
Oliver Günther b5350cccf7 Add rack-attack throttler for all logins
We have a built-in bruteforce protection for built-in users. When users
are being created from LDAP on-the-fly, these limits cannot apply, as we
do not have a user object yet.

Instead, we can provide a more generous throttler to block attempts
2026-05-29 12:33:28 +02:00
Oliver Günther 4565b53957 Extract and use charset to properly serve inline text attachments (#23432)
* Extract and use charset to properly encode attachments

* Add the content type for external URLs

* Be more cautious when parsing charset from `file`
2026-05-29 10:51:37 +02:00
Oliver Günther a852d46cb6 Be more cautious when parsing charset from file 2026-05-29 10:30:07 +02:00
Oliver Günther 5330745e69 Add the content type for external URLs 2026-05-29 10:26:43 +02:00
Oliver Günther 6f63faeed1 Extract and use charset to properly encode attachments 2026-05-29 10:26:43 +02:00
Ivan Kuchin f6e073f0a1 [#74769] Remove portfolio_models feature flag
https://community.openproject.org/wp/74769
2026-05-28 13:53:08 +02:00
OpenProject Actions CI 49b802ca02 Merge branch 'release/17.5' into dev 2026-05-28 08:51:09 +00:00
Kabiru Mwenja ab32cab495 Merge pull request #23337 from opf/bug/74762-numeric-id-in-the-email-notification-after-adding-watchers
bug/74762 Numeric ID in the email notification after adding watchers
2026-05-28 11:38:02 +03:00
OpenProject Actions CI eb6717f81e Merge branch 'release/17.5' into dev 2026-05-27 14:11:35 +00:00
Kabiru Mwenja 3036e852a9 Tighten render_mode and mail formatting helper docstrings
Strip a forward-looking aside about future external surfaces in RenderMode;
the invariant is that external surfaces need both absolute URLs and static
rendering. Replace "in practice" with "a coupled set" to drop the soft
hedge.

Drop the lead "wrappers around format_text" sentence on MailFormattingHelper
since the module body already shows the wrapping; the WHY (channel pinning,
extension/helper name parity) is the part worth documenting.
2026-05-27 13:22:56 +03:00
Kabiru Mwenja 499d7820a2 Add render_mode flag and MailFormattingHelper
`format_text` accepts `render_mode:` (`:in_app_html`, `:external_html`,
`:external_text`), which resolves the `only_path`, `static_html` and
`plain_text` context flags as a set. External surfaces (mailer HTML
body, future RSS/PDF/webhook) need absolute URLs and static rendering
together; pinning the trio at the public API keeps callers from
forgetting one. Explicit primitive kwargs still override.

`MailFormattingHelper` exposes `format_mail_html` and `format_mail_text`
thin wrappers around `format_text(render_mode:)`. The `_html` / `_text`
suffix matches the `.html.erb` / `.text.erb` template extension so
caller intent stays visible in the view, with no introspection of
`formats`.

The five WorkPackageMailer view sites use the helpers; `_work_package_details`,
`mentioned.html`, `mentioned.text`, `watcher_changed.html`, `watcher_changed.text`
drop the `static_html:`/`only_path:`/`plain_text:` boilerplate.
2026-05-27 13:04:26 +03:00
Oliver Günther 4cc9faef4f Consistently use OpenProject::SqlSanitization instead of forwarding to sanitize_sql_array 2026-05-27 10:08:16 +02:00
Oliver Günther 4724150e3d Avoid quote_string in favor of bindings where possible 2026-05-27 10:08:16 +02:00
Kabiru Mwenja f5957d800f Collapse plain-text formatter into a context option
Same pattern as the static-HTML collapse: the `markdown_as_text` format
symbol was a thin subclass setting a context flag and swapping the filter
list. Replace it with `plain_text: true` on the existing rich formatter,
which now picks between `RICH_FILTERS` and `TEXT_FILTERS` constants based
on the flag. `static_html:` and `plain_text:` now sit as peer options on
one format.

Rename the `as_text` context key to `plain_text` for symmetry with
`static_html`. Update both mailer `.text.erb` views and the two handler
predicates that branch on the flag.
2026-05-26 22:10:29 +03:00
Kabiru Mwenja c607b36b8e Rename with_hash_prefix to format_display_id 2026-05-26 22:10:07 +03:00
OpenProject Actions CI a147cf2168 Merge branch 'release/17.5' into dev 2026-05-26 13:14:53 +00:00
Kabiru Mwenja 94c13c11fa Collapse static-HTML formatter into a context option
The static-HTML pipeline differs from the rich pipeline only by a
context flag - both share the same filter chain. The dedicated
`Markdown::StaticHtmlFormatter` and `:markdown_as_static_html`
format symbol were pure boilerplate around that one-line override.

Callers now pass `format: :rich, static_html: true` and the matchers
read `context[:static_html]` directly.
2026-05-26 14:50:59 +03:00
Kabiru Mwenja 2ca379fe37 Trim verbose comments
Strip explanatory paragraphs and cross-reference jargon
("Mirrors X", "Shared with Y", etc.) from comments introduced
on this branch. Keep only the WHY — the parts of the design
intent that aren't already evident from method names and
short bodies. Pre-existing comments on methods this branch
didn't author stay as-is.
2026-05-26 14:32:37 +03:00
Kabiru Mwenja 989dbf9da8 Name the preload-required predicate
Compress the "do we need to load WP records?" condition into
`preload_required?(context)` so the call site reads as intent rather
than a tangle of two unrelated signals. The reasoning (semantic mode
needs row lookup; static-HTML output needs type/subject for the
anchor) moves to a comment on the predicate, where it belongs.
2026-05-26 14:24:03 +03:00
Kabiru Mwenja e70b9ab21c Tighten mention pipeline: helper extraction, principal preload, coverage
Lift the static-anchor label composition out of LinkHandlers and into
a small Helpers::StaticMacroLabel module so the envelope path
(MentionFilter) and the text-reference path (LinkHandlers) share one
shape — same module called from both, no cross-class reach-through.

Batch the User and Group mention preloads alongside the existing WP
preload so a note with N principals costs one SELECT per type rather
than N. Class lookup now reads from indexed hashes; visibility-gating
stays where it was (at the find for principals, separate from the
label for WPs).

Rename SemanticIdentifier.format → with_hash_prefix; the prior name
was broad enough to invite misuse for arbitrary work-package values.
Override StaticHtmlFormatter#filters explicitly so a future filter
appearing in Formatter#filters is a deliberate decision to apply to
mailer-side rendering, not an automatic one.

Spec coverage: classic-mode quickinfo and inaccessible-WP paths
(symmetric with the existing semantic-mode contexts), a principal
preload N+1 guard, and an anonymous current_user smoke test that
confirms the static-HTML pipeline doesn't raise when invoked without
an authenticated viewer.
2026-05-26 14:24:02 +03:00
Kabiru Mwenja 666069e126 Cleanup unneeded comments, touch up syntax 2026-05-26 14:19:24 +03:00
Kabiru Mwenja e269fddffc Extract shared static-macro label composition
Reviewer feedback on cd122f867cc: the `parts << status / type / label`
block was duplicated between the regex-driven (`WorkPackages` link
handler) and envelope-driven (`MentionFilter`) static paths, with no
guard against silent desynchronisation. Centralise the composition on
the link handler and document why the two callers pass different
labels — the regex path preserves the alias-as-matched, the envelope
path normalises to the WP's current formatted_id.
2026-05-26 14:19:24 +03:00
Kabiru Mwenja ee4c9aee59 Render WP quickinfo macros as static HTML in mailer notes
The `##N` and `###N` work-package macros emit JS-hydrated
`<opce-macro-wp-quickinfo>` custom elements, which mail clients
collapse to empty bullets. Introduce a `:markdown_as_static_html`
format that shares the rich filter chain but signals
`context[:as_static_html]` so the matcher and `MentionFilter` emit a
server-rendered anchor — formatted_id, type name, subject, and (for
`###`) status name — closely mirroring the in-app widget once
flattened.

Mailer HTML templates (`mentioned`, `watcher_changed`,
`_work_package_details`) opt into the new format. Invisible WPs still
render as plain-text labels, matching the cross-project visibility
policy.

`ResourceLinksMatcher.build_cache` and
`MentionFilter#preload_work_package_mentions` eager-load `:type` and
`:status` only when `:as_static_html` is set, leaving the default web
path's two-SELECT shape untouched. Classic-mode preload now also runs
under `:as_static_html` so the link handler can resolve type/subject
for `##`/`###`.

Renames the internal flag `context[:plain_text]` to `context[:as_text]`
to restore symmetry with the user-facing `:markdown_as_text` format.
2026-05-26 14:19:23 +03:00
Kabiru Mwenja a54dd3dc0b Rename :plain_text format to :markdown_as_text
The format runs the full markdown pipeline and then collapses the DOM
to text — it has nothing to do with the existing `:plain` format,
which strips markdown entirely. Moves the formatter under the Markdown
namespace next to the rich-output formatter whose pipeline it mirrors,
and renames the symbol so the relationship is legible from the
formatter_for case clause.
2026-05-26 14:19:11 +03:00
Kabiru Mwenja 5d8929a7c3 Resolve invisible WP mentions to their current formatted_id
The mention filter previously dropped to the envelope's stored text
when the recipient lacked view permission on the referenced work
package, which left stale identifiers in mailer bodies after a
project rename and diverged from the `#N` text-reference path on
the same render.

Adopts the two-SELECT pattern ResourceLinksMatcher uses for `#N`
references: a single unscoped batched lookup for label resolution
plus a visibility-scoped id pluck for anchor gating. Invisible WPs
render as plain text with the current formatted_id; the per-mention
`WorkPackage.visible.find_by` is gone.
2026-05-26 14:19:11 +03:00
Kabiru Mwenja 8d9aa18ad3 Collapse work-package preload state into one cache value object
Pairs unscoped label resolution and viewer-scoped link gating in a
WorkPackagePreloadCache instead of two RequestStore keys with a
five-method save/restore protocol. Exposes one `current_cache` reader;
consumers ask the cache directly via `fetch` and `visible?`.

Extracts a `text_only?` predicate in the WP link handler so the
`context[:plain_text]` and invisible-WP guards collapse into a single
call site. `SemanticIdentifier.format` renames its parameter to
reflect that the input may or may not be semantic.
2026-05-26 14:19:10 +03:00
Kabiru Mwenja 878048f8e8 Resolve WP labels across visibility boundaries in text macros
The macro preload was visibility-scoped — references to work packages the
recipient cannot see would fall through to the literal `#43` shape, even
when the same reference rendered as `DCP-1` for an author with full view
permission. Notification recipients saw misleading numeric ids for cross-
project references in journal notes.

Splits label resolution from link gating:

- `ResourceLinksMatcher.build_lookup` now does an unscoped fetch for the
  primary identifier and a separate visibility-scoped id pluck. The link
  handler reads `visible_to_current_user?` to decide between a navigable
  anchor and a plain-text label.
- `UpdateAncestorsService#set_journal_note` writes `#display_id` so new
  notes carry the semantic shape at the source; render-time resolution
  heals legacy `#N` content for users with view permission.

Tradeoff: a recipient without view permission now sees the WP's semantic
identifier (e.g. `DCP-1`) as plain text rather than `#43`. The reference's
existence was already disclosed by the stored journal text; the project
identifier is the only new piece of information surfaced, and is not
treated as a secret elsewhere in the system (URLs, exports, API).
2026-05-26 14:18:48 +03:00
Kabiru Mwenja 7c9d15e506 Render WP identifiers per current mode in plain-text mailer notes
The `mentioned` and `watcher_changed` text-mailer bodies surfaced raw
journal markdown — numeric `#42` references stayed numeric in semantic
mode, and `<mention>` envelopes leaked as HTML source.

Introduces `:plain_text` as a sibling format inside the existing Plain
module. The filter chain mirrors the markdown pipeline (markdown,
sanitization, mention, pattern-matcher) and finishes with a new
`PlainTextOutputFilter` that collapses the DOM to text. The
`WorkPackages` link handler and `MentionFilter` get plain-text branches
keyed off `context[:plain_text]` so identifier resolution stays in one
place across rich and plain channels.

Closes https://community.openproject.org/wp/74762
2026-05-26 14:18:17 +03:00
David F 88a29a0aff Turn checkbox filters into toggle switch. wp/74380 2026-05-26 08:14:56 +02:00
David F 2fa7ce3ae8 Remove filters specific-attributes from date pickers. wp/74380 2026-05-26 08:14:56 +02:00
David F 8403bb74f2 Generalize datetime helper for advanced filters. wp/74380 2026-05-26 08:14:56 +02:00
David F f22771f5fc Replace old select with toggle with autocompleter. wp/74380 2026-05-26 08:14:56 +02:00
David F fe39ccec97 Improve input group markup for advanced filters. wp/74380 2026-05-26 08:14:56 +02:00
David F 1ce489a2e0 Turn partials into form components. wp/74380 2026-05-26 08:14:56 +02:00
OpenProject Actions CI 1e62f01690 Merge branch 'release/17.4' into release/17.5 2026-05-26 05:10:56 +00:00
Oliver Günther 61cd01b784 Add associated_visible_resource to properly handle undisclosed work packages 2026-05-26 07:09:59 +02:00
OpenProject Actions CI e38557f12f Merge branch 'release/17.5' into dev 2026-05-26 04:53:23 +00:00
Tomas Hykel 948fa43321 chore: Remove feature flag for project-based work package identifiers 2026-05-25 17:45:06 +02:00
OpenProject Actions CI 9a74b5356b Merge branch 'release/17.4' into release/17.5 2026-05-22 08:36:48 +00:00
Oliver Günther 83c69820d6 Merge remote-tracking branch 'origin/release/17.4' into dev 2026-05-22 10:36:14 +02:00
Oliver Günther d6d7abea19 Merge pull request #23304 from opf/fix/message-pack-safe-buffer-serialization
Allow serialization of safebuffer without encoding issues
2026-05-22 10:35:50 +02:00
Oliver Günther 4a07d490d0 Bumped version to 17.6.0
[ci skip]
2026-05-21 06:55:20 +02:00
Kabiru Mwenja b181e1fde1 Follow-up refactors for the text-macro preload cache (#23285)
* Scope SQL log assertions to target SELECTs in alias-fold-in spec

The N+1 guard was counting the entire QueryRecorder log, which made it
brittle against any incidental Setting/permission query that landed on
the same render path. Switch to scoped greps against the two SELECTs
we actually care about: the work_packages batched query and the
sidecar alias pluck. A regression on either now fails with a clear
message pointing at the offending source.

* Flatten matcher preload wrapping into an iterative fold

The recursive shift-and-recurse shape mutated a duplicated array and
forwarded an anonymous block at every frame, which obscured what the
loop was actually doing: wrap each opt-in matcher's preload hook
around the inner block, first matcher outermost. The iterative form
walks the matcher list once in reverse and rebinds a lambda, so the
nesting order is visible without unwinding a recursion.

* Make the WP preload cache's stringified-key invariant explicit

Both ends of the cache assumed every key was a string, but the
contract lived only in the read site's `identifier.to_s` and an
ambient confidence that the identifier column is text. Normalize at
write time too, swap the safe-navigation lookup for `dig`, and leave
a one-line note at the canonical builder so a future reader doesn't
have to grep the call sites to convince themselves a numeric input
will resolve.
2026-05-20 21:36:09 +03:00
Kabiru Mwenja e2631598c2 Merge pull request #23204 from opf/feature/editor-mention-semantic-id
Render work-package mentions with the current display identifier
2026-05-20 17:26:50 +03:00
Jens Ulferts 0ceaa2617c Merge pull request #23181 from opf/code-maintenance/74768-remove-calculated_value_project_attribute-feature-flag
[#74768] Remove calculated_value_project_attribute feature flag
2026-05-20 16:09:46 +02:00
Oliver Günther 274f7c6e3d Merge pull request #23230 from opf/feat/monthly-meeting-option
Meeting series: Add monthly scheduling options
2026-05-20 16:02:36 +02:00
Dombi Attila f5e08b3d78 Merge pull request #23103 from opf/feature/71305-exclude-certain-work-package-types-from-automated-backlog-per-project
Feature/71305 exclude certain work package types from automated backlog per project
2026-05-20 16:51:06 +03:00
Kabiru Mwenja 70931762d9 Merge remote-tracking branch 'origin/dev' into feature/editor-mention-semantic-id
# Conflicts:
#	frontend/src/vendor/ckeditor/ckeditor.js
#	frontend/src/vendor/ckeditor/ckeditor.js.map
2026-05-20 16:33:47 +03:00
Oliver Günther 6295d90346 Add monthly scheduling options 2026-05-20 15:20:16 +02:00
Kabiru Mwenja a1440eb9bb Merge pull request #23221 from opf/feature/text-macro-preload-cache
Implement doc-level preload cache for WP text macros
2026-05-20 13:19:59 +03:00