Give each user independent read, write and delete flags per area (invoices, bingo, users), so someone can e.g. review and remove bingo incidents without being able to add any. The request method and path decide the flag needed: GET is read except the new/duplicate forms, POST to .../delete is delete, any other POST is write. Unmapped admin paths are superuser-only, and a test enumerates every registered admin route so a new one cannot ship without a rule. Pages follow the same flags: nav and dashboard tiles show readable areas only, write forms and delete buttons are hidden, and the datacenter form is shown read-only. Assisted-by: Claude:opus-5
81 lines
5.6 KiB
Text
81 lines
5.6 KiB
Text
<% fresh = @dc.new? %>
|
||
<div class="header">
|
||
<h1><%= fresh ? 'New datacenter' : "##{@dc.position} #{@dc.name_ru}" %></h1>
|
||
<p class="tagline"><a href="/admin/bingo">← bingo</a><% if !fresh && @dc.position > Bingo::SIZE**2 %> · off card (reserve)<% end %></p>
|
||
</div>
|
||
|
||
<% if @flash %><div class="form-error-base"><div><%= @flash %></div></div><% end %>
|
||
|
||
<% unless fresh %>
|
||
<section class="section">
|
||
<h2>Photo</h2>
|
||
<% if @dc.photo_file %>
|
||
<p><img src="/admin/bingo/p/<%= @dc.photo_file %>" alt="" style="max-width: 100%; max-height: 280px" /></p>
|
||
<% if can?('bingo', 'delete') %>
|
||
<form method="post" action="/admin/bingo/dc/<%= @dc.id %>/photo/delete">
|
||
<input type="hidden" name="authenticity_token" value="<%= csrf_token %>" />
|
||
<button type="submit" class="link-button">remove from card</button>
|
||
</form>
|
||
<% end %>
|
||
<% end %>
|
||
<% if can?('bingo', 'write') %>
|
||
<form class="invoice-form" method="post" action="/admin/bingo/dc/<%= @dc.id %>/photo" enctype="multipart/form-data">
|
||
<input type="hidden" name="authenticity_token" value="<%= csrf_token %>" />
|
||
<div class="field"><label for="photo">Upload <span class="optional">(JPEG/PNG/WebP, ≤ 8 MB)</span></label><input type="file" id="photo" name="photo" accept="image/jpeg,image/png,image/webp" /></div>
|
||
<div class="field"><label for="photo_url">…or import from URL <span class="optional">(blank = saved source URL)</span></label><input type="url" id="photo_url" name="url" placeholder="<%= @dc.photo_source_url %>" /></div>
|
||
<button type="submit" class="download-button">Store photo</button>
|
||
</form>
|
||
<% end %>
|
||
</section>
|
||
<% end %>
|
||
|
||
<section class="section">
|
||
<h2>Details</h2>
|
||
<form class="invoice-form" method="post" action="<%= fresh ? '/admin/bingo/dc' : "/admin/bingo/dc/#{@dc.id}" %>" autocomplete="off">
|
||
<input type="hidden" name="authenticity_token" value="<%= csrf_token %>" />
|
||
<fieldset class="plain" <%= 'disabled' unless can?('bingo', 'write') %>>
|
||
<% if fresh %>
|
||
<div class="field"><label for="slug">Slug <span class="optional">(permanent; used in photo names, e.g. ix-mos7)</span></label><input type="text" id="slug" name="slug" value="<%= @dc.slug %>" required pattern="[a-z0-9]+(-[a-z0-9]+)*" /></div>
|
||
<% end %>
|
||
<div class="invoice-grid">
|
||
<% %w[ru en uk].each do |l| %>
|
||
<div class="field"><label for="name_<%= l %>">Name (<%= l %>)</label><input type="text" id="name_<%= l %>" name="name_<%= l %>" value="<%= @dc[:"name_#{l}"] %>" <%= 'required' if l == 'ru' %> /></div>
|
||
<% end %>
|
||
<% %w[ru en uk].each do |l| %>
|
||
<div class="field"><label for="city_<%= l %>">City (<%= l %>)</label><input type="text" id="city_<%= l %>" name="city_<%= l %>" value="<%= @dc[:"city_#{l}"] %>" <%= 'required' if l == 'ru' %> /></div>
|
||
<% end %>
|
||
<div class="field"><label for="operator">Operator</label><input type="text" id="operator" name="operator" value="<%= @dc.operator %>" required /></div>
|
||
<div class="field"><label for="mw">MW <span class="optional">(number or range)</span></label><input type="text" id="mw" name="mw" value="<%= @dc.mw %>" /></div>
|
||
<div class="field">
|
||
<label for="mw_type">Capacity type</label>
|
||
<select id="mw_type" name="mw_type">
|
||
<option value="" <%= 'selected' unless @dc.mw_type %>>not stated</option>
|
||
<% Bingo::MW_TYPES.each do |m| %><option value="<%= m %>" <%= 'selected' if @dc.mw_type == m %>><%= m %></option><% end %>
|
||
</select>
|
||
</div>
|
||
<div class="field">
|
||
<label for="status">Status</label>
|
||
<select id="status" name="status">
|
||
<% Bingo::STATUSES.each do |s| %><option <%= 'selected' if @dc.status == s %>><%= s %></option><% end %>
|
||
</select>
|
||
</div>
|
||
<div class="field"><label for="year">Year</label><input type="text" id="year" name="year" value="<%= @dc.year %>" inputmode="numeric" /></div>
|
||
<div class="field"><label for="position">Position <span class="optional">(inserts here; 1–<%= Bingo::SIZE**2 %> are on the card<%= ', blank = last' if fresh %>)</span></label><input type="text" id="position" name="position" value="<%= @dc.position %>" inputmode="numeric" /></div>
|
||
</div>
|
||
<div class="field"><label for="photo_credit">Photo credit</label><input type="text" id="photo_credit" name="photo_credit" value="<%= @dc.photo_credit %>" /></div>
|
||
<div class="field"><label for="photo_source_url">Photo source URL</label><input type="url" id="photo_source_url" name="photo_source_url" value="<%= @dc.photo_source_url %>" /></div>
|
||
<div class="field"><label for="info_url">Info / fact source URL</label><input type="url" id="info_url" name="info_url" value="<%= @dc.info_url %>" /></div>
|
||
<% if can?('bingo', 'write') %><button type="submit" class="download-button"><%= fresh ? 'Add datacenter' : 'Save' %></button><% end %>
|
||
</fieldset>
|
||
</form>
|
||
</section>
|
||
|
||
<% if !fresh && can?('bingo', 'delete') %>
|
||
<section class="section">
|
||
<h2>Danger zone</h2>
|
||
<form method="post" action="/admin/bingo/dc/<%= @dc.id %>/delete" onsubmit="return confirm('Delete this datacenter and all its incidents? This cannot be undone.')">
|
||
<input type="hidden" name="authenticity_token" value="<%= csrf_token %>" />
|
||
<button type="submit" class="link-button">delete this datacenter<%= " (and #{@dc.incidents.size} incident(s))" if @dc.incidents.any? %></button>
|
||
</form>
|
||
</section>
|
||
<% end %>
|