From a59ab6cf03abed6f570382e38fc9bb9b131aee5e Mon Sep 17 00:00:00 2001 From: "Jesse C. Fisher" Date: Mon, 4 Dec 2023 09:37:57 +0000 Subject: [PATCH] Add Messages to Rooms --- README.md | 2 + app/assets/stylesheets/application.css.sass | 1 + app/assets/stylesheets/rooms.sass | 14 ++ app/assets/stylesheets/rooms.scss | 3 - app/controllers/messages_controller.rb | 13 ++ app/controllers/rooms_controller.rb | 2 + app/models/message.rb | 5 + app/models/room.rb | 1 + app/models/user.rb | 1 + app/policies/message_policy.rb | 56 ++++++++ app/views/layouts/_new_message_form.html.haml | 3 + app/views/layouts/application.html.erb | 6 + app/views/messages/_message.html.haml | 6 + app/views/rooms/index.html.haml | 9 +- config/routes.rb | 4 +- db/migrate/20231204083004_create_messages.rb | 11 ++ db/schema.rb | 125 ++++++++++-------- spec/factories/messages.rb | 7 + spec/models/message_spec.rb | 5 + 19 files changed, 212 insertions(+), 62 deletions(-) create mode 100644 app/assets/stylesheets/rooms.sass delete mode 100644 app/assets/stylesheets/rooms.scss create mode 100644 app/controllers/messages_controller.rb create mode 100644 app/models/message.rb create mode 100644 app/policies/message_policy.rb create mode 100644 app/views/layouts/_new_message_form.html.haml create mode 100644 app/views/messages/_message.html.haml create mode 100644 db/migrate/20231204083004_create_messages.rb create mode 100644 spec/factories/messages.rb create mode 100644 spec/models/message_spec.rb diff --git a/README.md b/README.md index f9653292..2132fee0 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,8 @@ Development Environment Setup TODO ---- +- Continue to Private Chat https://www.honeybadger.io/blog/chat-app-rails-actioncable-turbo/ + - Implement video chat https://github.com/domchristie/webrtc-hotwire-rails - Abandon previous video chat solution diff --git a/app/assets/stylesheets/application.css.sass b/app/assets/stylesheets/application.css.sass index 14a4c6c5..7e382196 100644 --- a/app/assets/stylesheets/application.css.sass +++ b/app/assets/stylesheets/application.css.sass @@ -265,3 +265,4 @@ textarea @import tokens @import microposts @import projects +@import rooms diff --git a/app/assets/stylesheets/rooms.sass b/app/assets/stylesheets/rooms.sass new file mode 100644 index 00000000..a2b4d6e6 --- /dev/null +++ b/app/assets/stylesheets/rooms.sass @@ -0,0 +1,14 @@ +#messages + font-family: sans-serif + width: 100% + + .message + background: #ffffff44 + padding: 0.2em + margin: 0.2em 0 + h6 + margin: 0 + .from_name + padding: 0.15em + color: #aaa + text-shadow: none diff --git a/app/assets/stylesheets/rooms.scss b/app/assets/stylesheets/rooms.scss deleted file mode 100644 index 032a00ae..00000000 --- a/app/assets/stylesheets/rooms.scss +++ /dev/null @@ -1,3 +0,0 @@ -// Place all the styles related to the Rooms controller here. -// They will automatically be included in application.css. -// You can use Sass (SCSS) here: https://sass-lang.com/ diff --git a/app/controllers/messages_controller.rb b/app/controllers/messages_controller.rb new file mode 100644 index 00000000..bebd4f9f --- /dev/null +++ b/app/controllers/messages_controller.rb @@ -0,0 +1,13 @@ +class MessagesController < ApplicationController + def create + @message = current_user.messages.build(content: msg_params[:content], room_id: params[:room_id]) + authorize @message + @message.save + end + + private + + def msg_params + params.require(:message).permit(:content) + end +end diff --git a/app/controllers/rooms_controller.rb b/app/controllers/rooms_controller.rb index 59e3acd4..af9880d9 100644 --- a/app/controllers/rooms_controller.rb +++ b/app/controllers/rooms_controller.rb @@ -14,6 +14,8 @@ class RoomsController < ApplicationController def show authorize @room @rooms = Room.public_rooms + @message = Message.new + @messages = @room.messages render "index" end diff --git a/app/models/message.rb b/app/models/message.rb new file mode 100644 index 00000000..89bc05cb --- /dev/null +++ b/app/models/message.rb @@ -0,0 +1,5 @@ +class Message < ActiveRecord::Base + belongs_to :user + belongs_to :room + after_create_commit { broadcast_append_to self.room } +end diff --git a/app/models/room.rb b/app/models/room.rb index 427c72ec..be458810 100644 --- a/app/models/room.rb +++ b/app/models/room.rb @@ -1,4 +1,5 @@ class Room < ActiveRecord::Base + has_many :messages validates_uniqueness_of :name scope :public_rooms, -> {where(is_private: false)} after_create_commit { broadcast_append_to "rooms" } diff --git a/app/models/user.rb b/app/models/user.rb index 57f2c002..6c1b1caa 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -15,6 +15,7 @@ class User < ActiveRecord::Base has_many :following_projects, through: :active_relationships, source: :followable, source_type: "Project" has_many :microposts, as: :micropostable has_many :bots + has_many :messages def icid stp = SoftTokenPrincipal.where(soft_token: self.soft_token).first_or_initialize diff --git a/app/policies/message_policy.rb b/app/policies/message_policy.rb new file mode 100644 index 00000000..15cc04e1 --- /dev/null +++ b/app/policies/message_policy.rb @@ -0,0 +1,56 @@ +class MessagePolicy + attr_reader :user, :model + + def initialize(user, model) + @user = user || User.new + @message = model + end + + class Scope + def initialize(user, scope) + @user = user + @scope = scope + end + + def resolve + if user.admin? + scope.all + else + #TODO: private chats + scope.all + end + end + + private + + attr_reader :user, :scope + end + + def index? + true + end + + def show? + true + end + + def new? + @user.admin? + end + + def create? + @user.admin? + end + + def edit? + @user.admin? + end + + def update? + @user.admin? + end + + def destroy? + @user.admin? + end +end diff --git a/app/views/layouts/_new_message_form.html.haml b/app/views/layouts/_new_message_form.html.haml new file mode 100644 index 00000000..d37583cd --- /dev/null +++ b/app/views/layouts/_new_message_form.html.haml @@ -0,0 +1,3 @@ += form_with(model: [@room, @message], remote: true) do |f| + = f.text_field :content, id: 'chat-text', class: "form-control msg-content", autocomplete: 'off' + = f.submit data: { disable_with: false } diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb index 9e1852a9..55c63a4e 100644 --- a/app/views/layouts/application.html.erb +++ b/app/views/layouts/application.html.erb @@ -13,6 +13,12 @@ <%= javascript_importmap_tags %> <%= csrf_meta_tags %> <%= yield :head %> + diff --git a/app/views/messages/_message.html.haml b/app/views/messages/_message.html.haml new file mode 100644 index 00000000..c92fab09 --- /dev/null +++ b/app/views/messages/_message.html.haml @@ -0,0 +1,6 @@ +.message{class: "from-#{message.user.id}"} + - unless message.room.is_private + %h6 + %span.from_name{style: "background: ##{(message.user.display_name.to_i(36) % 16777215).to_s(16)};" } + = message.user.display_name + = message.content diff --git a/app/views/rooms/index.html.haml b/app/views/rooms/index.html.haml index 6c462390..d81fde30 100644 --- a/app/views/rooms/index.html.haml +++ b/app/views/rooms/index.html.haml @@ -1,9 +1,16 @@ - if @room %h4= @room.name + = turbo_stream_from @room + .contain + #messages + = render @messages + = render partial: 'layouts/new_message_form' + %h1 Rooms index -= render partial: "layouts/new_room_form" +- if policy(Room).new? + = render partial: "layouts/new_room_form" = turbo_stream_from "rooms" #rooms diff --git a/config/routes.rb b/config/routes.rb index 0b843645..d8a35f91 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,5 +1,7 @@ Rails.application.routes.draw do - resources :rooms + resources :rooms do + resources :messages + end resources :commands do member do get 'run' diff --git a/db/migrate/20231204083004_create_messages.rb b/db/migrate/20231204083004_create_messages.rb new file mode 100644 index 00000000..482670bd --- /dev/null +++ b/db/migrate/20231204083004_create_messages.rb @@ -0,0 +1,11 @@ +class CreateMessages < ActiveRecord::Migration[7.1] + def change + create_table :messages do |t| + t.references :user, null: false, foreign_key: true + t.references :room, null: false, foreign_key: true + t.text :content + + t.timestamps + end + end +end diff --git a/db/schema.rb b/db/schema.rb index 9f3327d8..6f26b50a 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,8 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 2023_12_03_160243) do - +ActiveRecord::Schema[7.1].define(version: 2023_12_04_083004) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -21,8 +20,8 @@ ActiveRecord::Schema.define(version: 2023_12_03_160243) do t.string "discord_api_token" t.bigint "user_id", null: false t.bigint "profile_id" - t.datetime "created_at", precision: 6, null: false - t.datetime "updated_at", precision: 6, null: false + t.datetime "created_at", null: false + t.datetime "updated_at", null: false t.text "telegram_subscriber_ids" t.index ["profile_id"], name: "index_bots_on_profile_id" t.index ["user_id"], name: "index_bots_on_user_id" @@ -37,8 +36,8 @@ ActiveRecord::Schema.define(version: 2023_12_03_160243) do t.string "icid" t.string "name" t.bigint "user_id" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false + t.datetime "created_at", precision: nil, null: false + t.datetime "updated_at", precision: nil, null: false t.index ["user_id"], name: "index_canisters_on_user_id" end @@ -46,8 +45,8 @@ ActiveRecord::Schema.define(version: 2023_12_03_160243) do t.string "name" t.string "trigger" t.text "body" - t.datetime "created_at", precision: 6, null: false - t.datetime "updated_at", precision: 6, null: false + t.datetime "created_at", null: false + t.datetime "updated_at", null: false end create_table "delayed_jobs", force: :cascade do |t| @@ -55,13 +54,13 @@ ActiveRecord::Schema.define(version: 2023_12_03_160243) do t.integer "attempts", default: 0, null: false t.text "handler", null: false t.text "last_error" - t.datetime "run_at" - t.datetime "locked_at" - t.datetime "failed_at" + t.datetime "run_at", precision: nil + t.datetime "locked_at", precision: nil + t.datetime "failed_at", precision: nil t.string "locked_by" t.string "queue" - t.datetime "created_at", precision: 6 - t.datetime "updated_at", precision: 6 + t.datetime "created_at" + t.datetime "updated_at" t.index ["priority", "run_at"], name: "delayed_jobs_priority" end @@ -69,8 +68,8 @@ ActiveRecord::Schema.define(version: 2023_12_03_160243) do t.text "body" t.bigint "user_id" t.boolean "is_public" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false + t.datetime "created_at", precision: nil, null: false + t.datetime "updated_at", precision: nil, null: false t.boolean "is_global", default: false t.index ["user_id"], name: "index_doodads_on_user_id" end @@ -80,7 +79,7 @@ ActiveRecord::Schema.define(version: 2023_12_03_160243) do t.integer "sluggable_id", null: false t.string "sluggable_type", limit: 50 t.string "scope" - t.datetime "created_at" + t.datetime "created_at", precision: nil t.index ["slug", "sluggable_type", "scope"], name: "index_friendly_id_slugs_on_slug_and_sluggable_type_and_scope", unique: true t.index ["slug", "sluggable_type"], name: "index_friendly_id_slugs_on_slug_and_sluggable_type" t.index ["sluggable_type", "sluggable_id"], name: "index_friendly_id_slugs_on_sluggable_type_and_sluggable_id" @@ -88,8 +87,8 @@ ActiveRecord::Schema.define(version: 2023_12_03_160243) do create_table "games", force: :cascade do |t| t.string "title" - t.datetime "created_at" - t.datetime "updated_at" + t.datetime "created_at", precision: nil + t.datetime "updated_at", precision: nil t.string "status" t.integer "controlling_player_id" t.integer "play_to_beat_id" @@ -98,27 +97,37 @@ ActiveRecord::Schema.define(version: 2023_12_03_160243) do t.index ["play_to_beat_id"], name: "index_games_on_play_to_beat_id" end + create_table "messages", force: :cascade do |t| + t.bigint "user_id", null: false + t.bigint "room_id", null: false + t.text "content" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index ["room_id"], name: "index_messages_on_room_id" + t.index ["user_id"], name: "index_messages_on_user_id" + end + create_table "microposts", force: :cascade do |t| t.text "content" t.string "micropostable_type" t.bigint "micropostable_id" - t.datetime "created_at", precision: 6, null: false - t.datetime "updated_at", precision: 6, null: false + t.datetime "created_at", null: false + t.datetime "updated_at", null: false t.index ["micropostable_type", "micropostable_id"], name: "index_microposts_on_micropostable" end create_table "play_to_beats", force: :cascade do |t| t.integer "game_id" t.integer "play_id" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false + t.datetime "created_at", precision: nil, null: false + t.datetime "updated_at", precision: nil, null: false end create_table "player_cards", force: :cascade do |t| t.integer "player_id" t.integer "card_id" - t.datetime "created_at" - t.datetime "updated_at" + t.datetime "created_at", precision: nil + t.datetime "updated_at", precision: nil t.integer "value" t.string "rank" t.string "suit" @@ -130,8 +139,8 @@ ActiveRecord::Schema.define(version: 2023_12_03_160243) do create_table "players", force: :cascade do |t| t.integer "game_id" t.integer "user_id" - t.datetime "created_at" - t.datetime "updated_at" + t.datetime "created_at", precision: nil + t.datetime "updated_at", precision: nil t.string "soft_token" t.boolean "is_bot", default: false t.index ["game_id"], name: "index_players_on_game_id" @@ -141,8 +150,8 @@ ActiveRecord::Schema.define(version: 2023_12_03_160243) do create_table "plays", force: :cascade do |t| t.integer "game_id" t.integer "player_id" - t.datetime "created_at" - t.datetime "updated_at" + t.datetime "created_at", precision: nil + t.datetime "updated_at", precision: nil t.index ["game_id"], name: "index_plays_on_game_id" t.index ["player_id"], name: "index_plays_on_player_id" end @@ -152,8 +161,8 @@ ActiveRecord::Schema.define(version: 2023_12_03_160243) do t.string "name" t.string "summary" t.text "about" - t.datetime "created_at", precision: 6, null: false - t.datetime "updated_at", precision: 6, null: false + t.datetime "created_at", null: false + t.datetime "updated_at", null: false t.index ["user_id"], name: "index_profiles_on_user_id" end @@ -161,16 +170,16 @@ ActiveRecord::Schema.define(version: 2023_12_03_160243) do t.string "title" t.text "description" t.bigint "user_id", null: false - t.datetime "created_at", precision: 6, null: false - t.datetime "updated_at", precision: 6, null: false + t.datetime "created_at", null: false + t.datetime "updated_at", null: false t.index ["user_id"], name: "index_projects_on_user_id" end create_table "relationships", force: :cascade do |t| t.integer "follower_id" t.integer "followed_id" - t.datetime "created_at", precision: 6, null: false - t.datetime "updated_at", precision: 6, null: false + t.datetime "created_at", null: false + t.datetime "updated_at", null: false t.string "followable_type" t.bigint "followable_id" t.index ["followable_type", "followable_id"], name: "index_relationships_on_followable" @@ -182,15 +191,15 @@ ActiveRecord::Schema.define(version: 2023_12_03_160243) do create_table "rooms", force: :cascade do |t| t.string "name" t.boolean "is_private", default: false - t.datetime "created_at", precision: 6, null: false - t.datetime "updated_at", precision: 6, null: false + t.datetime "created_at", null: false + t.datetime "updated_at", null: false end create_table "seats", force: :cascade do |t| t.integer "table_id" t.integer "user_id" - t.datetime "created_at" - t.datetime "updated_at" + t.datetime "created_at", precision: nil + t.datetime "updated_at", precision: nil t.integer "position" t.string "user_soft_token" t.integer "game_id" @@ -202,8 +211,8 @@ ActiveRecord::Schema.define(version: 2023_12_03_160243) do create_table "social_links", force: :cascade do |t| t.bigint "profile_id", null: false t.string "url" - t.datetime "created_at", precision: 6, null: false - t.datetime "updated_at", precision: 6, null: false + t.datetime "created_at", null: false + t.datetime "updated_at", null: false t.index ["profile_id"], name: "index_social_links_on_profile_id" end @@ -214,8 +223,8 @@ ActiveRecord::Schema.define(version: 2023_12_03_160243) do create_table "tables", force: :cascade do |t| t.string "title" - t.datetime "created_at" - t.datetime "updated_at" + t.datetime "created_at", precision: nil + t.datetime "updated_at", precision: nil t.integer "current_game_id" t.string "skyspace_url" t.string "slug" @@ -226,8 +235,8 @@ ActiveRecord::Schema.define(version: 2023_12_03_160243) do t.string "telegram_id", null: false t.string "icp_id" t.string "icp_principal" - t.datetime "created_at", precision: 6, null: false - t.datetime "updated_at", precision: 6, null: false + t.datetime "created_at", null: false + t.datetime "updated_at", null: false end create_table "tokens", force: :cascade do |t| @@ -238,8 +247,8 @@ ActiveRecord::Schema.define(version: 2023_12_03_160243) do t.bigint "total_supply" t.integer "decimals" t.bigint "transfer_fee" - t.datetime "created_at", precision: 6, null: false - t.datetime "updated_at", precision: 6, null: false + t.datetime "created_at", null: false + t.datetime "updated_at", null: false t.string "logo_url" t.index ["canister_id"], name: "index_tokens_on_canister_id", unique: true end @@ -248,25 +257,25 @@ ActiveRecord::Schema.define(version: 2023_12_03_160243) do t.string "email", default: "", null: false t.string "encrypted_password", default: "" t.string "reset_password_token" - t.datetime "reset_password_sent_at" - t.datetime "remember_created_at" + t.datetime "reset_password_sent_at", precision: nil + t.datetime "remember_created_at", precision: nil t.integer "sign_in_count", default: 0, null: false - t.datetime "current_sign_in_at" - t.datetime "last_sign_in_at" + t.datetime "current_sign_in_at", precision: nil + t.datetime "last_sign_in_at", precision: nil t.inet "current_sign_in_ip" t.inet "last_sign_in_ip" - t.datetime "created_at" - t.datetime "updated_at" + t.datetime "created_at", precision: nil + t.datetime "updated_at", precision: nil t.string "name" t.string "confirmation_token" - t.datetime "confirmed_at" - t.datetime "confirmation_sent_at" + t.datetime "confirmed_at", precision: nil + t.datetime "confirmation_sent_at", precision: nil t.string "unconfirmed_email" t.integer "role" t.string "invitation_token" - t.datetime "invitation_created_at" - t.datetime "invitation_sent_at" - t.datetime "invitation_accepted_at" + t.datetime "invitation_created_at", precision: nil + t.datetime "invitation_sent_at", precision: nil + t.datetime "invitation_accepted_at", precision: nil t.integer "invitation_limit" t.integer "invited_by_id" t.string "invited_by_type" @@ -284,6 +293,8 @@ ActiveRecord::Schema.define(version: 2023_12_03_160243) do add_foreign_key "bots", "users" add_foreign_key "canisters", "users" add_foreign_key "doodads", "users" + add_foreign_key "messages", "rooms" + add_foreign_key "messages", "users" add_foreign_key "profiles", "users" add_foreign_key "projects", "users" add_foreign_key "social_links", "profiles" diff --git a/spec/factories/messages.rb b/spec/factories/messages.rb new file mode 100644 index 00000000..78a07720 --- /dev/null +++ b/spec/factories/messages.rb @@ -0,0 +1,7 @@ +FactoryGirl.define do + factory :message do + user nil + room nil + content "MyText" + end +end diff --git a/spec/models/message_spec.rb b/spec/models/message_spec.rb new file mode 100644 index 00000000..d74b6a8e --- /dev/null +++ b/spec/models/message_spec.rb @@ -0,0 +1,5 @@ +require 'rails_helper' + +RSpec.describe Message, type: :model do + pending "add some examples to (or delete) #{__FILE__}" +end