diff --git a/app/controllers/comments_controller.rb b/app/controllers/comments_controller.rb new file mode 100644 index 0000000..f2a76a4 --- /dev/null +++ b/app/controllers/comments_controller.rb @@ -0,0 +1,31 @@ +class CommentsController < ApplicationController + before_action :require_login + before_action :set_commentable + + def create + @comment = @commentable.comments.build(comment_params) + @comment.user = current_user + + if @comment.save + respond_to do |format| + format.turbo_stream + format.html { redirect_to @commentable } + end + else + # Handle validation errors + redirect_to @commentable, alert: "Comment could not be created: #{@comment.errors.full_messages.to_sentence}" + end + end + + private + + def set_commentable + if params[:entry_id] + @commentable = Entry.find(params[:entry_id]) + end + end + + def comment_params + params.require(:comment).permit(:body, :language_code) + end +end diff --git a/app/javascript/controllers/comments_controller.js b/app/javascript/controllers/comments_controller.js new file mode 100644 index 0000000..73b8d44 --- /dev/null +++ b/app/javascript/controllers/comments_controller.js @@ -0,0 +1,25 @@ +import { Controller } from "@hotwired/stimulus" + +export default class extends Controller { + static targets = ["modal", "button"] + + connect() { + this.modalTarget.classList.add("hidden") + this.buttonTarget.classList.remove("hidden") + } + + open(event) { + event.preventDefault() + this.modalTarget.classList.remove("hidden") + } + + close(event) { + if (event.target === this.modalTarget) { + this.modalTarget.classList.add("hidden") + } + } + + closeWithButton() { + this.modalTarget.classList.add("hidden") + } +} diff --git a/app/models/comment.rb b/app/models/comment.rb index 8ed9ab5..03f4544 100644 --- a/app/models/comment.rb +++ b/app/models/comment.rb @@ -1,6 +1,23 @@ class Comment < ApplicationRecord belongs_to :user belongs_to :commentable, polymorphic: true + belongs_to :language, + class_name: "SupportedLanguage", + foreign_key: :language_code, + primary_key: :code, + optional: true validates :body, presence: true + + after_create_commit :notify_users + + private + + def notify_users + return if language_code.blank? + + # Placeholder for notification logic once we decide delivery channels. + users_to_notify = User.where(primary_language: language_code).where.not(id: user_id) + # puts "Notifying users: #{users_to_notify.pluck(:email).join(", ")}" + end end diff --git a/app/views/comments/create.turbo_stream.erb b/app/views/comments/create.turbo_stream.erb new file mode 100644 index 0000000..a3bacc3 --- /dev/null +++ b/app/views/comments/create.turbo_stream.erb @@ -0,0 +1,13 @@ +<%= turbo_stream.append "comments-#{@comment.language_code.presence || 'all'}" do %> + <%= render "entries/comment", comment: @comment %> +<% end %> + +<% if @comment.language_code.present? %> + <%= turbo_stream.replace "comment-details-#{@comment.language_code}" do %> + <%= render "entries/language_comment_details", entry: @commentable, language_code: @comment.language_code %> + <% end %> +<% end %> + +<%= turbo_stream.replace "comment_tabs" do %> + <%= render "entries/comment_tabs", entry: @commentable %> +<% end %> diff --git a/app/views/entries/_comment.html.erb b/app/views/entries/_comment.html.erb new file mode 100644 index 0000000..7feceda --- /dev/null +++ b/app/views/entries/_comment.html.erb @@ -0,0 +1,24 @@ +
+ <%= comment.user&.name || "Anonymous" %> + <% unless comment.language_code.blank? %> + on the <%= language_name(comment.language_code) %> translation + <% end -%> +
++ <%= comment.created_at ? "#{time_ago_in_words(comment.created_at)} ago" : "just now" %> +
+<%= comment.body %>
+No comments yet. Be the first to add one!
+ <% end %> + <% language_groups.each do |language, comments| %> + <% language_code = language == :all ? "all" : language&.code %> + + <% end %> +You are invited to contribute to this work.
+With a login account, you can contribute to this work.
Your Account Details:
diff --git a/config/routes.rb b/config/routes.rb index 5915f1b..1f08c77 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -34,6 +34,7 @@ Rails.application.routes.draw do end resources :entries do + resources :comments, only: [:create] collection do get :download end diff --git a/db/migrate/20260123130957_add_language_code_to_comments.rb b/db/migrate/20260123130957_add_language_code_to_comments.rb new file mode 100644 index 0000000..1c65bd4 --- /dev/null +++ b/db/migrate/20260123130957_add_language_code_to_comments.rb @@ -0,0 +1,5 @@ +class AddLanguageCodeToComments < ActiveRecord::Migration[8.1] + def change + add_column :comments, :language_code, :string + end +end diff --git a/db/structure.sql b/db/structure.sql index 12e774c..11d81d6 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -10,7 +10,7 @@ FOREIGN KEY ("updated_by_id") CREATE INDEX "index_entries_on_created_by_id" ON "entries" ("created_by_id") /*application='SanastoWiki'*/; CREATE INDEX "index_entries_on_updated_by_id" ON "entries" ("updated_by_id") /*application='SanastoWiki'*/; CREATE INDEX "index_entries_on_category" ON "entries" ("category") /*application='SanastoWiki'*/; -CREATE TABLE IF NOT EXISTS "comments" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "user_id" integer NOT NULL, "commentable_type" varchar NOT NULL, "commentable_id" integer NOT NULL, "body" text NOT NULL, "created_at" datetime(6) NOT NULL, "updated_at" datetime(6) NOT NULL, CONSTRAINT "fk_rails_03de2dc08c" +CREATE TABLE IF NOT EXISTS "comments" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "user_id" integer NOT NULL, "commentable_type" varchar NOT NULL, "commentable_id" integer NOT NULL, "body" text NOT NULL, "created_at" datetime(6) NOT NULL, "updated_at" datetime(6) NOT NULL, "language_code" varchar /*application='SanastoWiki'*/, CONSTRAINT "fk_rails_03de2dc08c" FOREIGN KEY ("user_id") REFERENCES "users" ("id") ); @@ -81,6 +81,7 @@ BEGIN END; CREATE TABLE IF NOT EXISTS "setup_states" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "installed" boolean DEFAULT FALSE NOT NULL, "installed_at" datetime(6), "created_at" datetime(6) NOT NULL, "updated_at" datetime(6) NOT NULL); INSERT INTO "schema_migrations" (version) VALUES +('20260123130957'), ('20260123125325'), ('20260122131000'), ('20260122130000'), diff --git a/test/controllers/comments_controller_test.rb b/test/controllers/comments_controller_test.rb new file mode 100644 index 0000000..5c1cf08 --- /dev/null +++ b/test/controllers/comments_controller_test.rb @@ -0,0 +1,42 @@ +require "test_helper" + +class CommentsControllerTest < ActionDispatch::IntegrationTest + setup do + @user = users(:contributor_user) + @entry = entries(:one) + @supported_language = supported_languages(:one) + end + + test "should not create comment if not logged in" do + assert_no_difference("Comment.count") do + post entry_comments_url(@entry), params: { comment: { body: "Test comment", language_code: @supported_language.code } } + end + assert_redirected_to new_user_session_url + end + + test "should create comment if logged in" do + login_as @user + assert_difference("Comment.count", 1) do + post entry_comments_url(@entry), params: { comment: { body: "Test comment", language_code: @supported_language.code } } + end + assert_redirected_to @entry + assert_equal "Test comment", Comment.last.body + assert_equal @supported_language.code, Comment.last.language_code + assert_equal @user, Comment.last.user + end + + # Assuming you want to test turbo stream responses as well + test "should create comment and respond with turbo stream" do + login_as @user + post entry_comments_url(@entry), params: { comment: { body: "Test turbo comment", language_code: @supported_language.code } }, as: :turbo_stream + assert_response :success + assert_match(/turbo-stream action=\"append\" target=\"comments-#{@supported_language.code}\"/, response.body) + assert_match(/Test turbo comment/, response.body) + end + + private + + def new_user_session_url + login_path + end +end