Add dynamic info page editing via Firestore admin panel#2
Closed
AgentKush wants to merge 33 commits into
Closed
Conversation
b0024a8 to
dc41252
Compare
dc41252 to
dc71366
Compare
The Gemfile specifies ruby "3.4.9" but .ruby-version was still 3.4.8, causing CI to install the wrong Ruby version and fail with "Your Ruby version is 3.4.8, but your Gemfile specified 3.4.9". Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The CSP initializer was entirely commented out, leaving the application with no Content-Security-Policy headers. This is a security risk as it allows unrestricted loading of scripts, styles, and other resources. Configure CSP with sensible defaults for this app's needs: - default_src/script_src/connect_src: self + https - img_src/font_src: self + https + data URIs - object_src: none (blocks Flash/Java embeds) - style_src includes unsafe_inline for Tailwind compatibility - Nonce-based script protection via importmap Starts in report-only mode so violations are logged without breaking the site. Once verified in production, report_only can be removed. Fixes the medium-severity CSP bug reported in DonovanMods#76. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Tool#filename calls url.split("/") without checking if url is nil.
When a Firestore document lacks a fileURL field, url is nil and
calling .split on it raises NoMethodError, crashing the tools
index page.
Add a nil guard that returns nil early when url is absent, and
use URI parsing for consistency with how Mod#filename handles URLs.
Fixes the medium-severity Tool#filename crash reported in DonovanMods#76.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The author_slug method in the Displayable concern calls author.parameterize without checking if author is nil. If a single Firestore document lacks an author field, it raises NoMethodError and can crash the entire mods or tools index page since author_slug is called during rendering of every record. Return "unknown" as a safe fallback slug when author is nil, keeping the page rendering and producing a valid URL segment. Fixes the medium-severity author_slug crash reported in DonovanMods#76. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Use string splitting instead of URI() to avoid URI::InvalidURIError on malformed Firestore URLs, matching the safer approach already used in Mod#filename (commit 2b66be7). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When switching Tailwind from darkMode: "media" to "class", the OS preference is no longer automatically respected. This adds a matchMedia check as fallback when no localStorage preference is saved, preserving the original behavior for first-time visitors. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Implements array-based pagination for the mods index when displaying all mods. Search results and author-filtered views show all matches without pagination, as requested in issue DonovanMods#55. - Add PaginationHelper with page windowing and ellipsis support - Add _pagination.html.erb partial with Prev/Next and page numbers - Paginate at 20 mods per page (configurable via DEFAULT_PER_PAGE) - Show "page X of Y" counter when paginated - Styled with existing Tailwind classes for light/dark mode
Covers paginate_array edge cases (empty collection, page clamping, custom per_page) and PaginationResult methods (first/last page, navigation, page_range with ellipsis). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The .gitignore only had .env.* (matching .env.local, .env.production, etc.) but not .env itself, so the base .env file was committed and tracked. While it currently contains non-secret config (project IDs, bucket names), tracking .env files is a security risk as developers may add secrets to it later. Changes: - Add .env to .gitignore so it is no longer tracked - Remove .env from git index (file stays on disk for existing devs) - Add .env.example template so new developers know which vars to set - Whitelist .env.example in .gitignore so the template is tracked Fixes the low-severity .env tracking bug reported in DonovanMods#76. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The _mod.html.erb partial passes mod.author (which contains spaces and mixed case) to mod_detail_path, producing ugly URLs with encoded spaces like /mods/Donovan%20Young/some-mod. Change to mod.author_slug which produces clean, parameterized URLs like /mods/donovan-young/some-mod, consistent with how the show action and author filtering already work. Fixes the low-severity ugly URL bug reported in DonovanMods#76. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The search input debounce was set to 200ms, firing a Turbo Frame request on nearly every keystroke. Increase to 400ms which still feels responsive but significantly reduces unnecessary requests and Firestore reads during active typing. Fixes the low-severity search debounce bug reported in DonovanMods#76. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The markdown helper created new CodeRayify and Redcarpet::Markdown instances on every call. On the mods index this means allocating these objects once per mod with a README. Extract into a memoized private method so objects are created once per request and reused for all subsequent renders. Fixes the low-severity markdown renderer performance bug in DonovanMods#76. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The require_master_key setting was commented out, meaning the app can boot in production without a master key. Without it, Rails credentials (including Firebase keyfile) can't be decrypted, causing confusing Firestore errors instead of a clear startup failure. Uncomment so production deploys fail fast if RAILS_MASTER_KEY is missing. The Kamal deploy config already provides this as a secret. Fixes the low-severity require_master_key bug reported in DonovanMods#76. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The firestore class method creates a new Google::Cloud::Firestore client on every call. Memoize with @FireStore ||= so the client is created once per class and reused. The Google Cloud Firestore client is designed to be long-lived and thread-safe. Fixes the low-severity Firestore client performance bug in DonovanMods#76. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Reset class-level @FireStore instance variable after each test to prevent RSpec doubles from persisting via Firestorable's @FireStore ||= memoization pattern. This fixes 8 test failures where leaked doubles caused errors in subsequent examples. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
afb555b to
b0e5f15
Compare
- Use .positive? instead of > 0 - Break long line in PaginationResult.new - Use described_class instead of explicit class names in specs - Fix context descriptions to start with when/with/without Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The template now uses mod.author_slug instead of mod.author for cleaner URLs, so the test expectation needs to match. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
These are local MCP plugin directories that shouldn't be tracked. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replaces inline toggleTheme() and DOMContentLoaded listener with a Stimulus theme_controller.js. Uses data-action and data-target attributes instead of global functions and getElementById, preventing potential conflicts with other scripts. The early-load FOUC prevention script in <head> is kept since Stimulus connects after DOMContentLoaded. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Merge nested conditional into outer if to satisfy RuboCop Style/SoleNestedConditional rule. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Extract filter_by_author, filter_by_query, paginate_mods, and render_index private methods to bring ABC size and method length below RuboCop thresholds. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace `return unless params[:x].present?` with `return if params[:x].blank?` per Rails/Blank cop preference. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…smatch Fix .ruby-version to match Gemfile ruby requirement (3.4.9)
…nil-guards-and-csp Fix/medium severity nil guards and csp
…anup-and-performance Fix: Code clean-up, security hardening, and performance improvements
Add dark/light theme toggle to header nav
Add pagination to mods listing
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Addresses issue DonovanMods#25 — the info page content is now stored in Firestore and editable through an admin interface at /admin/info, protected by HTTP Basic Auth (ADMIN_PASSWORD env var). No user login system needed. - SiteContent model reads/writes page sections to Firestore - Admin::BaseController provides HTTP Basic Auth for admin routes - Admin::InfoController allows adding, editing, and removing sections - Info view renders dynamic content with markdown support - Falls back to default content if no Firestore document exists - Includes model and request specs Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add login form at /admin/login with gold theme styling - Session expires after 30 minutes of inactivity - Audit logging for login/logout/failed attempts with IP - Proper logout button in admin panel - Updated specs for session-based auth flow Addresses review feedback about HTTP Basic Auth limitations (no session management, no audit trail, credentials in every request). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Prevents info page specs from hitting Firestore. Returns nil so the controller falls back to default_info_sections. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Override global SiteContent.find stub with and_call_original in spec so tests exercise real implementation through mocked Firestore - Use described_class instead of explicit SiteContent in specs - Fix array indentation in spec - Use modifier if for SiteContent stub in firestore support - Break long lines in base_controller and site_content - Avoid multi-line block chain in info_controller Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
f63b457 to
f3ca7f9
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes DonovanMods#25
Summary
site_content/info_page) and rendered dynamically/admin/infofor editing page sections without redeployingADMIN_PASSWORDenvironment variable (no user login system needed)Setup
Set the
ADMIN_PASSWORDenvironment variable to enable admin access:Then visit
/admin/infoand enter any username with that password.Test plan
bundle exec rspec spec/models/site_content_spec.rb spec/requests/admin/info_spec.rbGenerated with Claude Code