Skip to content

refactor: stop shadowing core REST API templates; inject geometry instead - #385

Merged
dkastl merged 2 commits into
nextfrom
feat/api-deshadow
Jun 14, 2026
Merged

refactor: stop shadowing core REST API templates; inject geometry instead#385
dkastl merged 2 commits into
nextfrom
feat/api-deshadow

Conversation

@dkastl

@dkastl dkastl commented Jun 14, 2026

Copy link
Copy Markdown
Member

Summary

The plugin shipped full copies of six core *.api.rsb templates (issues, projects, users × index/show) purely to add a geojson field (plus rotation on projects and distance on the issues index). Copying core's entire field list is update-fragile, and it has already drifted:

  • users/show.api.rsb had lost core's && !User.current.authorized_by_oauth? guard on the api_key field (a security-relevant drift), and
  • several newer core user fields (twofa_scheme, passwd_changed_on, status) were missing from the response entirely.

This replaces the shadowing with an after_action (ApiGeometryInjection) that appends the plugin's own fields to core's already-rendered JSON/XML response. Core renders its own template untouched, so the API can no longer fall behind core, and the concern never lists a core field.

What changed

  • Deleted the six shadow templates (net -292 lines).
  • Added lib/redmine_gtt/patches/api_geometry_injection.rb: a small concern that merges per-record fields into the rendered resource object(s), parsing/re-serializing JSON or inserting nodes for XML, with a rescue so it can never turn a valid core response into an error.
  • Wired it via after_action in the issues/projects/users controller patches.

Behavior preserved (backward-compatible)

  • geojson is a parsed object for ?format=json and a JSON string otherwise (xml), and is present as null/empty when a record has no geometry. Gated on geom.present?, exactly as the old templates were.
  • Projects keep rotation (always) and geojson (only with include=geometry).
  • The issues index keeps distance when present.
  • The dedicated .geojson FeatureCollection endpoints are unchanged.

As a bonus, users and issues/projects responses now include whatever core fields had drifted out of the stale copies, and the api_key OAuth guard is restored.

Verification

  • The existing issues_api_test, users_api_test, and projects_api_test integration tests pass (12 runs, 157 assertions, 0 failures) against this change. They pin the exact behavior: object for JSON, string for XML, null/empty when no geometry, for both index and show.
  • Verified live in a Redmine 6.1 dev instance via the REST API: issue show/index, project show/index (with and without include=geometry), user show/index, across .json and .xml, plus the empty-geometry case; the .geojson endpoints still work; server logs clean.

Note: the unrelated gtt_map_layers_controller_test failures in my local CI-mirror are a stale test-DB missing the type column from #381/#382 (this branch does not touch that area); they pass in CI which migrates fresh.

…tead

The plugin shipped full copies of six core *.api.rsb templates (issues,
projects, users x index/show) just to add a geojson field (and
rotation/distance). Those copies silently drifted from core on every
Redmine upgrade: the users/show copy had lost core's
'&& !User.current.authorized_by_oauth?' guard on the api_key field, and
several newer core user fields (twofa_scheme, passwd_changed_on, status)
were missing entirely.

Replace the shadowing with an after_action that appends the plugin's own
fields to core's rendered JSON/XML response (ApiGeometryInjection). Core
renders its template untouched, so the response can no longer fall behind
core; the concern never lists a core field.

Behavior is preserved: geojson is a parsed object for ?format=json and a
JSON string otherwise, present as null/empty when a record has no
geometry; projects keep rotation (always) and geojson (only with
include=geometry); the issues index keeps distance. The dedicated
.geojson FeatureCollection endpoints are unchanged.

Verified against the existing issues/users/projects API integration tests
(157 assertions) and live in a Redmine 6.1 dev instance across json/xml,
show/index, and the empty-geometry case.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

This PR removes plugin-shipped copies of core REST API *.api.rsb templates (which had drifted from Redmine core) and replaces them with an after_action-based approach that post-processes the rendered JSON/XML to inject the plugin’s geometry-related fields.

Changes:

  • Added ApiGeometryInjection concern to merge geojson (plus rotation / distance) into already-rendered core API responses.
  • Wired the injection via after_action in the issues/projects/users controller patches.
  • Deleted six previously-shadowed core REST API templates for issues/projects/users index/show.

Reviewed changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
lib/redmine_gtt/patches/api_geometry_injection.rb Adds response post-processing helpers to inject geometry fields into JSON/XML bodies.
lib/redmine_gtt/patches/issues_controller_patch.rb Hooks injection after show/index to append geojson and optional distance.
lib/redmine_gtt/patches/projects_controller_patch.rb Hooks injection after show/index to append rotation and conditional geojson.
lib/redmine_gtt/patches/users_controller_patch.rb Hooks injection after show/index to append geojson without shadowing core user templates.
app/views/issues/index.api.rsb Removes plugin shadow template for issues index API.
app/views/issues/show.api.rsb Removes plugin shadow template for issues show API.
app/views/projects/index.api.rsb Removes plugin shadow template for projects index API.
app/views/projects/show.api.rsb Removes plugin shadow template for projects show API.
app/views/users/index.api.rsb Removes plugin shadow template for users index API.
app/views/users/show.api.rsb Removes plugin shadow template for users show API.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread lib/redmine_gtt/patches/api_geometry_injection.rb
init.rb aliases :geojson to application/json, so request.format.json? is
also true for .geojson requests. Without an explicit guard the after_action
would reparse and re-serialize the FeatureCollection body the controllers
send_data for that format. Skip injection when the format is :geojson.
@dkastl
dkastl merged commit 6337078 into next Jun 14, 2026
17 of 18 checks passed
@dkastl
dkastl deleted the feat/api-deshadow branch June 14, 2026 13:19
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.

2 participants