summaryrefslogtreecommitdiff
path: root/app/controllers/page_translations_controller.rb
diff options
context:
space:
mode:
authorerdgeist <erdgeist@erdgeist.org>2026-07-13 23:33:11 +0200
committererdgeist <erdgeist@erdgeist.org>2026-07-13 23:33:11 +0200
commit8eab68f2c5a3c126e2fec2ecdfa7ace87ce0937b (patch)
treef446ebc26a7707c7b64a937aa51a155df146c80a /app/controllers/page_translations_controller.rb
parent42714c697273a7117c6b355fab26c8c35e336ad1 (diff)
parentcdf5d9941ca866d437612d2f863eac6eb0b3db12 (diff)
Merge branch 'erdgeist-revive-events'
Diffstat (limited to 'app/controllers/page_translations_controller.rb')
-rw-r--r--app/controllers/page_translations_controller.rb109
1 files changed, 109 insertions, 0 deletions
diff --git a/app/controllers/page_translations_controller.rb b/app/controllers/page_translations_controller.rb
new file mode 100644
index 0000000..9446cd2
--- /dev/null
+++ b/app/controllers/page_translations_controller.rb
@@ -0,0 +1,109 @@
1class PageTranslationsController < ApplicationController
2 layout 'admin'
3
4 before_action :login_required
5 before_action :find_node
6 before_action :find_locale, :only => [:show, :edit, :update, :autosave, :destroy]
7
8 def index
9 page = @node.draft || @node.head
10 @translations = page ? page.translation_summary : []
11 end
12
13 def show
14 @page = @node.draft || @node.head
15 @translation = @page.translations.find_by(:locale => @locale)
16 @default_translation = @page.translations.find_by(:locale => I18n.default_locale)
17 end
18
19 def edit
20 @node.lock_for_editing!(current_user)
21 @page = @node.draft || @node.head
22 @translation = @page.translations.find_by(:locale => @locale)
23 rescue LockedByAnotherUser => e
24 flash[:error] = e.message
25 redirect_to node_path(@node)
26 end
27
28 def update
29 Globalize.with_locale(@locale) { @node.autosave!(translation_params, current_user) }
30 @node.save_draft!(current_user)
31 flash[:notice] = "#{@locale.upcase} translation saved. Publish the draft to make it live."
32
33 if params[:commit] == "Save + Unlock + Exit"
34 @node.unlock!
35 redirect_to node_path(@node)
36 else
37 redirect_to edit_node_translation_path(@node, @locale)
38 end
39 rescue LockedByAnotherUser => e
40 flash[:error] = e.message
41 redirect_to node_path(@node)
42 end
43
44 def autosave
45 Globalize.with_locale(@locale) { @node.autosave!(translation_params, current_user) }
46 head :ok
47 rescue LockedByAnotherUser => e
48 render plain: e.message, status: :locked
49 rescue ActiveRecord::RecordInvalid => e
50 render plain: e.message, status: :unprocessable_entity
51 rescue StandardError => e
52 render plain: "Autosave failed", status: :internal_server_error
53 end
54
55 def destroy
56 base = @node.draft || @node.head
57 unless base && base.translated_locales.include?(@locale)
58 flash[:error] = "No #{@locale.to_s.upcase} translation exists to remove."
59 return redirect_to node_path(@node)
60 end
61
62 if (base.translated_locales - [@locale]).empty?
63 flash[:error] = "Can't remove the only remaining translation."
64 return redirect_to node_path(@node)
65 end
66
67 draft = ensure_editable_draft
68 draft.translations.where(:locale => @locale).delete_all
69 draft.reload
70
71 flash[:notice] = "#{@locale.upcase} translation removed from the draft. Publish to make this permanent."
72 redirect_to node_path(@node)
73 rescue LockedByAnotherUser => e
74 flash[:error] = e.message
75 redirect_to node_path(@node)
76 end
77
78 private
79
80 def find_node
81 @node = Node.find(params[:node_id])
82 end
83
84 # Every remaining action's :translation_locale is already
85 # router-constrained to non-default locales, so this should never
86 # actually fire in practice -- it's a deliberate second check, kept
87 # as a drift detector in case the route constraint and this list
88 # (both driven by Page.non_default_locales) ever disagree.
89 def find_locale
90 candidate = params[:translation_locale].to_s.to_sym
91 unless Page.non_default_locales.include?(candidate)
92 raise ActionController::RoutingError, "Unknown or default locale"
93 end
94 @locale = candidate
95 end
96
97 # Never mutates head directly. Locks first (same guard as the
98 # primary editor), then reuses an existing draft or creates one --
99 # deliberately not going through the autosave buffer: this is a
100 # plain, explicit Save, not a live-typing surface.
101 def ensure_editable_draft
102 @node.lock_for_editing!(current_user)
103 @node.draft || @node.create_new_draft(current_user)
104 end
105
106 def translation_params
107 params.fetch(:page, {}).permit(:title, :abstract, :body)
108 end
109end