It's like OpenProject::Cache, but it encrypts cached
values at rest. Callers that store confidential things in the cache
have been updated to use it, reducing the risk to expose secrets
to an attacker that obtained access to the contents of OpenProject's cache.
Also expose the #delete method offered by Rails caches.
Adapt the interface of existing methods to stricter follow
the upstream interface. neither #read nor #write accept passing
a block to them.
The performance decreased because of a combination of calls that were supposed to increase performance.
We have a mechanism in place which automatically eager loads models needed in the element representers when a collection of them is rendered. This is to avoid N+1 queries of course. But, if eager loading is combined with e.g., a LIMIT, which we do because we paginate, rails automatically falls back to issuing two instead of just one SQL statement. Which makes sense as otherwise LEFT JOINS might mess with the result set.
But Rails does so in a somewhat simple fashion. It uses the first query to get the DISTINCT ids. The second is used to load the values (without a limit). But instead of removing all WHERE statements in the second SQL statement and then apply just the one for the ids, it keeps the original WHERE statement and applies the one for the ids on top. The problem with that is that the database trips on that (I didn't check the why) and uses a less than optimal query plan.
That was the problem here as well. The first query remained reasonable quick (300ms) but the second one took 25s.
The fix is to split the two statements by hand in the representer whenever eager loading is defined. The first query has all the filters but no eager loading and fetches the ids. The second takes the ids, and with eager loading included loads the data. Et voila, second query takes 10ms.
That at least works for relations, work_packages and projects. But there are other representers that also seem to have custom behaviour. I'm looking into whether they can be easily adapted.
So far, we've been using the relaxed sanitization rule set. We only need some styles for the table display in CKEditor,
other styles should not be allowed.
We delegate the resource name to the object itself, that way we can
override it in our record and no knowledge about the backlogs module is
necessary in the core.
We already use our own extensive sanitization pipeline, and it turns out
tagfilter is extremely slow on large oneline input (such as big tables).
Rendering a large table inside a work package (2k rows, 20k cells) caused tagfilter to run for over 2 minutes.
Added a separate spec to test all tags the tagfilter filters for to avoid its runaway execution time.
Restore the minimal admin settings blankslate so the admin menu route
remains valid after the sprint-based cleanup. Remove the remaining
settings-driven story/task classification code, dead models and
services, and the obsolete filter and spec setup that depended on it.
Overriding wp.id to return the semantic identifier (e.g. "PROJ-42")
broke cache keys, API filters, row rendering, and CSS selectors that
all depend on the numeric PK.
Instead, keep wp.id as the numeric PK and add two new properties:
- displayId: returns the user-facing identifier ("PROJ-42" or "123")
- displayIdWithHash: returns "#PROJ-42" or "#123" for UI display
Also adds a COALESCE fallback in the SQL representer so work packages
created before semantic mode was enabled still get a valid displayId.
Extract FinderMethods module that transparently resolves both numeric and
semantic identifiers (e.g. "PROJ-42") using FriendlyId's Object#friendly_id?
for dispatch. The module is included in both the WorkPackage class and
extended onto every relation, so scoped queries like
WorkPackage.visible(user).find("PROJ-42") work seamlessly.
- Override find to resolve semantic IDs via identifier column + alias table
- Override exists? with the same resolution chain
- Refactor find_by_id_or_identifier to use friendly_id? instead of semantic_id?
- Update API route to accept string IDs (type: Integer → type: String)
- Update controller and ViewComponent finders to use find_by_id_or_identifier
- Pass display_id from Rails views to Angular custom elements
Replace the conditional `semanticId` API field with `displayId` which is
always present in work package responses. In semantic mode it returns the
project-based identifier (e.g. "PROJ-42"), in classic mode it returns the
numeric ID as a string. This gives API consumers (frontend, mobile) a
single field to read without conditional logic.
- Add `WorkPackage#display_id` method that encapsulates the mode check
- Update both representers (JSON and SQL) to render `displayId` unconditionally
- Update OpenAPI schema documentation