messaged 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +85 -0
  3. data/Rakefile +8 -0
  4. data/app/assets/config/messaged_manifest.js +1 -0
  5. data/app/assets/stylesheets/messaged/application.css +15 -0
  6. data/app/controllers/messaged/application_controller.rb +54 -0
  7. data/app/controllers/messaged/messages_controller.rb +71 -0
  8. data/app/javascript/application.js +2 -0
  9. data/app/jobs/messaged/application_job.rb +4 -0
  10. data/app/models/messaged/application_record.rb +5 -0
  11. data/app/models/messaged/message.rb +36 -0
  12. data/app/models/messaged/null_tenant.rb +15 -0
  13. data/app/models/messaged/null_user.rb +23 -0
  14. data/app/models/messaged/room.rb +27 -0
  15. data/app/models/messaged/user_extender.rb +15 -0
  16. data/app/views/layouts/messaged/application.html.erb +16 -0
  17. data/config/importmap.rb +4 -0
  18. data/config/locales/en.yml +9 -0
  19. data/config/routes.rb +3 -0
  20. data/db/migrate/20221001034722_create_messaged.rb +33 -0
  21. data/lib/generators/messaged/install/USAGE.md +8 -0
  22. data/lib/generators/messaged/install/install_generator.rb +18 -0
  23. data/lib/generators/messaged/install/templates/initializer.rb +20 -0
  24. data/lib/generators/messaged/views/USAGE.md +8 -0
  25. data/lib/generators/messaged/views/templates/messages/_form.html.erb +8 -0
  26. data/lib/generators/messaged/views/templates/messages/_message.html.erb +12 -0
  27. data/lib/generators/messaged/views/templates/messages/create.turbostream.erb +2 -0
  28. data/lib/generators/messaged/views/templates/messages/edit.html.erb +3 -0
  29. data/lib/generators/messaged/views/templates/messages/index.html.erb +21 -0
  30. data/lib/generators/messaged/views/templates/messages/new.html.erb +3 -0
  31. data/lib/generators/messaged/views/templates/messages/show.html.erb +1 -0
  32. data/lib/generators/messaged/views/views_generator.rb +42 -0
  33. data/lib/messaged/base_migration.rb +17 -0
  34. data/lib/messaged/engine.rb +15 -0
  35. data/lib/messaged/version.rb +3 -0
  36. data/lib/messaged.rb +50 -0
  37. data/lib/tasks/messaged_tasks.rake +4 -0
  38. metadata +125 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 2607ebea948e9c5464a9fba7e3153def8d1e0093fccc7c72570b9aeced8b910f
4
+ data.tar.gz: 4ab6464c09f420b6f18e6761317e0638d60d6fa30f0263f9cb67d7e174a5753d
5
+ SHA512:
6
+ metadata.gz: 68b45ab5fa04546608da02a3aaf1cd945b497be9ea599ac9518ab4c0c076b8bf2f0885cbf2bb478ae0eb30e9f473bc455e3f9aa856be688477976bf92b39e42f
7
+ data.tar.gz: bcdcdebc54df17cfe5107e4926f57947c445b7ea14e217ed8bb006ccc741fec622fd51983ed15b06e870a9cf502340d3ddefd5e64c43ca775793cc92d4b110df
data/README.md ADDED
@@ -0,0 +1,85 @@
1
+ # Messaged
2
+ A Rails Engine for Hotwire Turbo-powered instant messaging.
3
+
4
+ The author would personally recommend against using this Gem if your Rails application is not built for Turbo Rails.
5
+
6
+ ## Installation
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem "messaged"
11
+ ```
12
+
13
+ And then execute:
14
+ ```bash
15
+ bundle
16
+ ```
17
+
18
+ Or install it yourself as:
19
+ ```bash
20
+ gem install messaged
21
+ ```
22
+
23
+ Generate the needed migrations and initializer:
24
+ ```bash
25
+ rails generate messaged:install
26
+ rails messaged:install:migrations
27
+ ```
28
+
29
+ ## Usage
30
+ Messages broadcast to the DOM element id `messages`
31
+ ```html
32
+ <div id="messages"></div>
33
+ ```
34
+
35
+ To get started with a basic HTML structure, run in your terminal: `rails generate messaged:views`
36
+
37
+ If you're using this engine or `turbo-rails` for the first time, it is recommended to generate the views to familiarize yourself with how turbo tags are used when turbo streaming.
38
+
39
+ ### Users
40
+ Messaged assumes you have a user model. You may customize the user model name in the initializer. For example, if your user model is called Member:
41
+ ```ruby
42
+ # config/initializers/messaged.rb
43
+ Messaged.user_class = 'Member'
44
+ Messaged.current_user_method = :current_member
45
+ ```
46
+
47
+ ### Tenants
48
+ Messaged does not assume the application is multi-tenant, but does support it. By default, `Messaged.tenant_class` is set to `nil`.
49
+ ```ruby
50
+ # config/initializers/messaged.rb
51
+ Messaged.tenant_class = 'Account'
52
+ Messaged.current_tenant_method = :current_account
53
+ ```
54
+
55
+ ## Dependencies
56
+ It is recommended, particularly for development, to have a websockets compatible web server. This is true for production as well, but puma adds an easy way to support websockets without needing additional infrastructure from external services.
57
+ ```ruby
58
+ gem "puma"
59
+ ```
60
+
61
+ By default, Messaged is powered by:
62
+ ```ruby
63
+ gem "rails", ">= 7.0.2.3"
64
+ gem "importmap-rails", "1.1.5"
65
+ gem "turbo-rails", "1.3.0"
66
+ ```
67
+ If your application cannot support these gems, it is recommended that you do not use the Messaged engine. Alternatively, feel free to work this engine and add support for your desired setup. Pull requests are welcome, see: [CONTRIBUTING.md](https://github.com/ianrandmckenzie/messaged/blob/main/CONTRIBUTING.md)
68
+
69
+ ## Contributing
70
+ See [CONTRIBUTING.md](https://github.com/ianrandmckenzie/messaged/blob/main/CONTRIBUTING.md)
71
+
72
+ ## License
73
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
74
+ See also: [LICENSE.txt](https://github.com/ianrandmckenzie/messaged/blob/main/LICENSE.txt)
75
+
76
+ ## Other Info
77
+ Messaged is intended to be named through the nomenclature used in [Noticed](https://github.com/excid3/noticed), in part because Collin and I met through the GoRails Discord server (owned by @excid3).
78
+ —Ian
79
+
80
+ ## TODO
81
+ * Add dynamic configurations for message broadcasting to tenants (like an organization chat room), rooms (like a Discord channel), or users (like direct messages in most direct-messaging apps such as Signal)
82
+ * Figure out how to support permissioning/authorization (such as Pundit/Cancancan) without being opinionated
83
+ * Complete adding rich_text support
84
+ * Ensure I18n support for hard-coded English strings that are seen by the end-user
85
+ * Create and finish the test suite
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ require "bundler/setup"
2
+
3
+ APP_RAKEFILE = File.expand_path("test/dummy/Rakefile", __dir__)
4
+ load "rails/tasks/engine.rake"
5
+
6
+ load "rails/tasks/statistics.rake"
7
+
8
+ require "bundler/gem_tasks"
@@ -0,0 +1 @@
1
+ //= link_directory ../stylesheets/messaged .css
@@ -0,0 +1,15 @@
1
+ /*
2
+ * This is a manifest file that'll be compiled into application.css, which will include all the files
3
+ * listed below.
4
+ *
5
+ * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
6
+ * or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path.
7
+ *
8
+ * You're free to add application-wide styles to this file and they'll appear at the bottom of the
9
+ * compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS
10
+ * files in this directory. Styles in this file should be added after the last require_* statement.
11
+ * It is generally better to create a new file per style scope.
12
+ *
13
+ *= require_tree .
14
+ *= require_self
15
+ */
@@ -0,0 +1,54 @@
1
+ module Messaged
2
+ class ApplicationController < ActionController::Base
3
+ helper Messaged::Engine.helpers
4
+ helper_method \
5
+ :messaged_current_user,
6
+ :messaged_current_tenant
7
+
8
+ protected
9
+
10
+ # The `current_user` and `signed_in?` methods are prefixed with `messaged_`
11
+ # to avoid conflicts with methods from the parent controller.
12
+
13
+ def messaged_current_user
14
+ send(Messaged.current_user_method) || NullUser.new
15
+ end
16
+
17
+ def messaged_user_signed_in?
18
+ !messaged_current_user.messaged_anonymous?
19
+ end
20
+
21
+ # The `current_tenant` and `signed_in?` methods are prefixed with `messaged_`
22
+ # to avoid conflicts with methods from the parent controller.
23
+
24
+ def messaged_current_tenant
25
+ send(Messaged.current_tenant_method) || NullTenant.new
26
+ end
27
+
28
+ def messaged_tenant_signed_in?
29
+ !messaged_current_tenant.messaged_anonymous?
30
+ end
31
+
32
+ def messaged_current_room
33
+ @room = nil
34
+ return unless params && params[:room_id]
35
+ @room = Room.find(params[:room_id])
36
+ return @room
37
+ end
38
+
39
+ # Here we define an owner in the event that there is a current_tenant or
40
+ # current_user, but perhaps not necessarily both without assuming one or the other.
41
+ # Like in models/message.rb, we default to user and fallback to other models.
42
+ def messaged_current_owner
43
+ return messaged_current_user if messaged_current_user
44
+ return messaged_current_room if messaged_current_room
45
+ return messaged_current_tenant if messaged_current_tenant
46
+ return nil
47
+ end
48
+
49
+ def messaged_require_login!
50
+ fail Messaged::Errors::LoginRequired if messaged_current_user.messaged_anonymous?
51
+ fail Messaged::Errors::LoginRequired if messaged_current_tenant.messaged_anonymous?
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,71 @@
1
+ module Messaged
2
+ class MessagesController < ApplicationController
3
+ # TODO: How does the enginer user require authnetication without assuming Devise?
4
+ # before_action :authenticate_user!
5
+ before_action :set_message, only: [:destroy, :edit, :show, :update]
6
+
7
+ def index
8
+ # TODO: How does the enginer user require authnetication without assuming Devise / ActsAsTenant?
9
+ # @messages = Message.where(account: current_account)
10
+ @messages = Message.all
11
+ @new_message = Message.new
12
+ @new_message = messaged_current_owner.messages.build if messaged_current_owner
13
+ end
14
+
15
+ def show; end
16
+
17
+ def new
18
+ @message = Message.new
19
+ @message = messaged_current_owner.messages.build if messaged_current_owner
20
+ end
21
+
22
+ def create
23
+ # TODO: How does the enginer user require authnetication without assuming Devise / ActsAsTenant?
24
+ # @message = Message.new(message_params.merge(account: current_account, user: current_user))
25
+ @message = Message.new(message_params)
26
+ if @message.save
27
+ @new_message = messaged_current_owner.messages.build if messaged_current_owner
28
+ respond_to do |format|
29
+ format.turbo_stream do
30
+ render turbo_stream: turbo_stream.append(:messages, partial: "messaged/messages/message",
31
+ locals: { message: @message })
32
+ end
33
+ format.html { redirect_to messages_url }
34
+ end
35
+ else
36
+ render :new, status: :unprocessable_entity
37
+ end
38
+ end
39
+
40
+ def edit; end
41
+
42
+ def update
43
+ # TODO: (Security risk) How to authenticate user agnostically?
44
+ if @message.update(message_params)
45
+ render @message
46
+ else
47
+ render :edit, status: :unprocessable_entity
48
+ end
49
+ end
50
+
51
+ def destroy
52
+ # TODO: (Security risk) How to authenticate user agnostically?
53
+ @message.destroy
54
+ respond_to do |format|
55
+ format.turbo_stream { render turbo_stream: turbo_stream.remove(@message) }
56
+ format.html { redirect_to messages_url }
57
+ end
58
+ end
59
+
60
+ private
61
+
62
+ def set_message
63
+ # TODO: (Security risk) How to authenticate user agnostically before declaring?
64
+ @message = Message.find(params[:id])
65
+ end
66
+
67
+ def message_params
68
+ params.require(:message).permit(:content, :user_id, :tenant_id, :messaged_room_id)
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,2 @@
1
+ // Configure your import map in config/importmap.rb. Read more: https://github.com/rails/importmap-rails
2
+ import "@hotwired/turbo-rails"
@@ -0,0 +1,4 @@
1
+ module Messaged
2
+ class ApplicationJob < ActiveJob::Base
3
+ end
4
+ end
@@ -0,0 +1,5 @@
1
+ module Messaged
2
+ class ApplicationRecord < ActiveRecord::Base
3
+ self.abstract_class = true
4
+ end
5
+ end
@@ -0,0 +1,36 @@
1
+ module Messaged
2
+ class Message < ApplicationRecord
3
+ include ActionView::RecordIdentifier
4
+
5
+ # User association
6
+ belongs_to :user,
7
+ class_name: Messaged.user_class_name,
8
+ inverse_of: :messages,
9
+ optional: true
10
+ # Multi-tenant option
11
+ if Messaged.tenant_class_name
12
+ belongs_to :tenant,
13
+ class_name: Messaged.tenant_class_name,
14
+ inverse_of: :messages,
15
+ optional: true
16
+ end
17
+ belongs_to :room, optional: true
18
+
19
+ has_rich_text :content
20
+ validates :content, presence: true
21
+
22
+ # TODO: This needs to be added to a generator
23
+ after_create_commit -> { broadcast_append_later_to ["messages"], target: "messages", partial: "messaged/messages/message" }
24
+ after_update_commit -> { broadcast_replace_later_to ["messages"], target: "#{dom_id(self)}", partial: "messaged/messages/message" }
25
+ after_destroy_commit -> { broadcast_remove_to ["messages"] }
26
+
27
+ # Messages should default to the person sending them, otherwise
28
+ # fallback to the chat room, and finally tenant if they exist.
29
+ def owner
30
+ return user if user
31
+ return room if room
32
+ return tenant if Messaged.tenant_class_name && tenant
33
+ return nil # replace with user, tenant, or room
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,15 @@
1
+ module Messaged
2
+ class NullTenant
3
+ def id
4
+ nil
5
+ end
6
+
7
+ def valid?
8
+ false
9
+ end
10
+
11
+ def messaged_anonymous?
12
+ true
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,23 @@
1
+ module Messaged
2
+ class NullUser
3
+ def id
4
+ nil
5
+ end
6
+
7
+ def email
8
+ nil
9
+ end
10
+
11
+ def name
12
+ I18n.t('messaged.null_user_name')
13
+ end
14
+
15
+ def valid?
16
+ false
17
+ end
18
+
19
+ def messaged_anonymous?
20
+ true
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,27 @@
1
+ module Messaged
2
+ class Room < ApplicationRecord
3
+ # User association
4
+ belongs_to :user,
5
+ class_name: Messaged.user_class_name,
6
+ inverse_of: :messages,
7
+ optional: true
8
+ # Multi-tenant option
9
+ if Messaged.tenant_class_name
10
+ belongs_to :tenant,
11
+ class_name: Messaged.tenant_class_name,
12
+ inverse_of: :messages,
13
+ optional: true
14
+ end
15
+ validates :title, presence: true
16
+
17
+ has_many :messages, dependent: :destroy
18
+
19
+ # Messages should default to the person sending them, otherwise
20
+ # fallback to the chat room, and finally tenant if they exist.
21
+ def owner
22
+ return user if user
23
+ return tenant if Messaged.tenant_class_name && tenant
24
+ return nil # replace with user, tenant, or room
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,15 @@
1
+ module Messaged
2
+ module UserExtender
3
+ extend ActiveSupport::Concern
4
+ included do
5
+ with_options dependent: :nullify, foreign_key: 'user_id', inverse_of: :user do
6
+ has_many :messages, class_name: 'Messaged::Message', dependent: :destroy
7
+ has_many :rooms, class_name: 'Messaged::Room', dependent: :destroy
8
+ end
9
+ end
10
+
11
+ def messaged_anonymous?
12
+ false
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,16 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>Messaged</title>
5
+ <%= csrf_meta_tags %>
6
+ <%= csp_meta_tag %>
7
+
8
+ <%= stylesheet_link_tag "messaged/application", media: "all" %>
9
+ <%= javascript_importmap_tags %>
10
+ </head>
11
+ <body>
12
+
13
+ <%= yield %>
14
+
15
+ </body>
16
+ </html>
@@ -0,0 +1,4 @@
1
+ # Pin npm packages by running ./bin/importmap
2
+
3
+ pin "application", preload: true
4
+ pin "@hotwired/turbo-rails", to: "turbo.min.js", preload: true
@@ -0,0 +1,9 @@
1
+ en:
2
+ messaged:
3
+ send_a_message: 'Send a message'
4
+ type_your_message: 'Type your message here'
5
+ confirm: 'Are you sure?'
6
+ edit: 'Edit'
7
+ delete: 'Delete'
8
+ header: Messages
9
+ null_user_name: 'Deleted User'
data/config/routes.rb ADDED
@@ -0,0 +1,3 @@
1
+ Messaged::Engine.routes.draw do
2
+ resources :messages
3
+ end
@@ -0,0 +1,33 @@
1
+ require 'messaged/base_migration'
2
+ class CreateMessaged < Messaged::BaseMigration
3
+ def change
4
+ create_table :messaged_messages do |t|
5
+ t.references :tenant, type: user_id_type, index: false
6
+ t.index [:tenant_id], name: :index_messaged_messages_on_tenant_id
7
+
8
+ t.references :user, type: tenant_id_type, index: false
9
+ t.index [:user_id], name: :index_messaged_messages_on_user_id
10
+
11
+ t.references :messaged_room, foreign_key: true
12
+
13
+ t.text :content
14
+
15
+ # Choose an association: room, user, tenant
16
+ t.string :delivery_target
17
+
18
+ t.timestamps
19
+ end
20
+
21
+ create_table :messaged_rooms do |t|
22
+ t.references :tenant, type: user_id_type, index: false
23
+ t.index [:tenant_id], name: :index_messaged_rooms_on_tenant_id
24
+
25
+ t.references :user, type: tenant_id_type, index: false
26
+ t.index [:user_id], name: :index_messaged_rooms_on_user_id
27
+
28
+ t.string :title
29
+
30
+ t.timestamps
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,8 @@
1
+ Description:
2
+ Create an initializer with description of configuration and defaults.
3
+
4
+ Example:
5
+ rails generate messaged:install
6
+
7
+ This will create:
8
+ config/initializers/messaged.rb
@@ -0,0 +1,18 @@
1
+ module Messaged
2
+ module Generators
3
+ class InstallGenerator < Rails::Generators::Base
4
+ def set_source_paths
5
+ @source_paths = [
6
+ File.expand_path('templates', __dir__),
7
+ File.expand_path('../../../..', __dir__),
8
+ ]
9
+ end
10
+
11
+ def copy_initializer_file
12
+ copy_file \
13
+ 'initializer.rb',
14
+ 'config/initializers/messaged.rb'
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,20 @@
1
+ # Messaged configuration
2
+
3
+ # ==> User Configuration
4
+ # The name of the class your app uses for your users.
5
+ # By default the engine will use 'User' but if you have another name
6
+ # for your user class - change it here.
7
+ Messaged.user_class = 'User'
8
+
9
+ # This method is used by Messaged controllers and views to fetch the currently signed-in user
10
+ Messaged.current_user_method = :"current_#{Messaged.user_class_name.demodulize.underscore}"
11
+
12
+ # ==> Multi-tenant Configuration
13
+ # The name of the class your app uses for your tenants.
14
+ # By default the engine will use nil (in other words, tenancy in the
15
+ # application is not assumed). If you have another name
16
+ # for your tenant class - change it here. Example: 'Account'
17
+ Messaged.tenant_class = nil
18
+
19
+ # This method is used by Messaged controllers and views to fetch the currently signed-in user
20
+ # Messaged.current_tenant_method = :"current_#{Messaged.tenant_class_name.demodulize.underscore}"
@@ -0,0 +1,8 @@
1
+ Description:
2
+ Create an initializer with description of configuration and defaults.
3
+
4
+ Example:
5
+ rails generate messaged:views
6
+
7
+ This will create:
8
+ config/initializers/messaged.rb
@@ -0,0 +1,8 @@
1
+ <%= form_with model: message, class: 'messaged-form' do |f| %>
2
+ <%= f.label :content, t('messaged.send_a_message') %>
3
+ <%= f.hidden_field :user_id %>
4
+ <%= f.hidden_field :tenant_id %>
5
+ <%= f.hidden_field :messaged_room_id %>
6
+ <%= f.text_area :content %>
7
+ <%= f.submit nil, class: 'messaged-button' %>
8
+ <% end %>
@@ -0,0 +1,12 @@
1
+ <%= turbo_frame_tag dom_id(message) do %>
2
+ <div class="messaged-message-container">
3
+ <div>
4
+ <span class="messaged-timestamp"><%= time_ago_in_words(message.created_at) %> ago</span>
5
+ <p class="messaged-body"><%= message.content %></p>
6
+ <div class="messaged-options">
7
+ <span><%= link_to t('messaged.edit'), messaged.edit_message_path(message), class: "messaged-edit-link", "data-turbo-action": "replace" %></span>
8
+ <%= button_to t('messaged.delete'), messaged.message_path(message), method: :delete, form: { data: { turbo_confirm: t('messaged.confirm') } }, class: "messaged-delete-link", "data-turbo-action": "delete" %>
9
+ </div>
10
+ </div>
11
+ </div>
12
+ <% end %>
@@ -0,0 +1,2 @@
1
+ <%= turbo_stream.append "messages", @message %>
2
+ <%= turbo_stream.update "new_message", partial: "form", locals: { message: @new_message } %>
@@ -0,0 +1,3 @@
1
+ <%= turbo_frame_tag dom_id(@message) do %>
2
+ <%= render "form", message: @message %>
3
+ <% end %>
@@ -0,0 +1,21 @@
1
+ <div class="messaged-index-container">
2
+ <div class="messaged-outer-wrapper">
3
+ <div class="messaged-inner-wrapper">
4
+ <div class="messaged-index">
5
+ <% if t('messaged.header').present? %>
6
+ <h1 class="messaged-header"><%= t('messaged.header') %></h1>
7
+ <% end %>
8
+ <% # TODO: How do we make current_user model agnostic? %>
9
+ <%#= turbo_stream_from current_account, "messages" %>
10
+ <%= turbo_stream_from "messages" %>
11
+ <div class="messaged-messages" id="messages">
12
+ <%= render @messages %>
13
+ </div>
14
+
15
+ <%= turbo_frame_tag "new_message" do %>
16
+ <%= render "form", message: @new_message %>
17
+ <% end %>
18
+ </div>
19
+ </div>
20
+ </div>
21
+ </div>
@@ -0,0 +1,3 @@
1
+ <%= turbo_frame_tag @new_message do %>
2
+ <%= render "form", message: @message %>
3
+ <% end %>
@@ -0,0 +1 @@
1
+ <%= render @message %>
@@ -0,0 +1,42 @@
1
+ module Messaged
2
+ module Generators
3
+ class ViewsGenerator < Rails::Generators::Base
4
+ def set_source_paths
5
+ @source_paths = [
6
+ File.expand_path('templates', __dir__),
7
+ File.expand_path('../../../..', __dir__),
8
+ ]
9
+ end
10
+
11
+ def copy_view_templates
12
+ copy_file \
13
+ 'messages/_form.html.erb',
14
+ 'app/views/messaged/messages/_form.html.erb'
15
+
16
+ copy_file \
17
+ 'messages/_message.html.erb',
18
+ 'app/views/messaged/messages/_message.html.erb'
19
+
20
+ copy_file \
21
+ 'messages/create.turbostream.erb',
22
+ 'app/views/messaged/messages/create.turbostream.erb'
23
+
24
+ copy_file \
25
+ 'messages/edit.html.erb',
26
+ 'app/views/messaged/messages/edit.html.erb'
27
+
28
+ copy_file \
29
+ 'messages/index.html.erb',
30
+ 'app/views/messaged/messages/index.html.erb'
31
+
32
+ copy_file \
33
+ 'messages/new.html.erb',
34
+ 'app/views/messaged/messages/new.html.erb'
35
+
36
+ copy_file \
37
+ 'messages/show.html.erb',
38
+ 'app/views/messaged/messages/show.html.erb'
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,17 @@
1
+ module Messaged
2
+ class BaseMigration < ActiveRecord::Migration[7.0]
3
+ protected
4
+
5
+ def user_id_type
6
+ Messaged.user_class.columns.find { |c| c.name == Messaged.user_class.primary_key }.sql_type
7
+ end
8
+
9
+ def tenant_id_type
10
+ if Messaged&.tenant_class
11
+ Messaged.tenant_class.columns.find { |c| c.name == Messaged.tenant_class.primary_key }.sql_type
12
+ else
13
+ Messaged.user_class.columns.find { |c| c.name == Messaged.user_class.primary_key }.sql_type
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,15 @@
1
+ module Messaged
2
+ class Engine < ::Rails::Engine
3
+ require "importmap-rails"
4
+ require "turbo-rails"
5
+ isolate_namespace Messaged
6
+
7
+ config.to_prepare do
8
+ Messaged.user_class&.send(:include, Messaged::UserExtender)
9
+ end
10
+
11
+ # initializer "messaged.assets.precompile" do |app|
12
+ # app.config.assets.precompile += %w( messaged/application.css )
13
+ # end
14
+ end
15
+ end
@@ -0,0 +1,3 @@
1
+ module Messaged
2
+ VERSION = "0.1.0"
3
+ end
data/lib/messaged.rb ADDED
@@ -0,0 +1,50 @@
1
+ require "messaged/version"
2
+ require "messaged/engine"
3
+
4
+ module Messaged
5
+ class << self
6
+ # @return [String] The name of the user class
7
+ attr_reader :user_class_name
8
+
9
+ # @return [String] The name of the tenant class
10
+ attr_reader :tenant_class_name
11
+
12
+ # @return [Symbol] The name of the method used by Messaged controllers and views to get the currently signed-in user
13
+ attr_accessor :current_user_method
14
+
15
+ # @return [Symbol] The name of the method used by Messaged controllers and views to get the currently signed-in tenant
16
+ attr_accessor :current_tenant_method
17
+
18
+ # @param user_class_name [String]
19
+ def user_class=(user_class_name)
20
+ return nil if user_class_name.nil?
21
+ unless user_class_name.is_a?(String)
22
+ fail "Messaged.user_class must be set to a String, got #{user_class_name.inspect}"
23
+ end
24
+ @user_class_name = user_class_name
25
+ end
26
+
27
+ # @return [Class<Messaged::UserExtender>] the user class from the host application.
28
+ def user_class
29
+ # This is nil before the initializer is installed.
30
+ return nil if @user_class_name.nil?
31
+ @user_class_name.constantize
32
+ end
33
+
34
+ # @param tenant_class_name [String]
35
+ def tenant_class=(tenant_class_name)
36
+ return nil if tenant_class_name.nil?
37
+ unless tenant_class_name.is_a?(String)
38
+ fail "Messaged.tenant_class must be set to a String, got #{tenant_class_name.inspect}"
39
+ end
40
+ @tenant_class_name = tenant_class_name
41
+ end
42
+
43
+ # @return [Class<Messaged::TenantExtender>] the tenant class from the host application.
44
+ def tenant_class
45
+ # This is nil before the initializer is installed.
46
+ return nil if @tenant_class_name.nil?
47
+ @tenant_class_name.constantize
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :messaged do
3
+ # # Task goes here
4
+ # end
metadata ADDED
@@ -0,0 +1,125 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: messaged
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - cjilbert504, ianrandmckenzie
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2023-01-29 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rails
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 7.0.2.3
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: 7.0.2.3
27
+ - !ruby/object:Gem::Dependency
28
+ name: importmap-rails
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '='
32
+ - !ruby/object:Gem::Version
33
+ version: 1.1.5
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '='
39
+ - !ruby/object:Gem::Version
40
+ version: 1.1.5
41
+ - !ruby/object:Gem::Dependency
42
+ name: turbo-rails
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '='
46
+ - !ruby/object:Gem::Version
47
+ version: 1.3.0
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '='
53
+ - !ruby/object:Gem::Version
54
+ version: 1.3.0
55
+ description: A quick and easy way to implement an instant-messaging module using Turbo
56
+ Rails.
57
+ email:
58
+ - admin@ianrandmckenzie.com
59
+ executables: []
60
+ extensions: []
61
+ extra_rdoc_files: []
62
+ files:
63
+ - README.md
64
+ - Rakefile
65
+ - app/assets/config/messaged_manifest.js
66
+ - app/assets/stylesheets/messaged/application.css
67
+ - app/controllers/messaged/application_controller.rb
68
+ - app/controllers/messaged/messages_controller.rb
69
+ - app/javascript/application.js
70
+ - app/jobs/messaged/application_job.rb
71
+ - app/models/messaged/application_record.rb
72
+ - app/models/messaged/message.rb
73
+ - app/models/messaged/null_tenant.rb
74
+ - app/models/messaged/null_user.rb
75
+ - app/models/messaged/room.rb
76
+ - app/models/messaged/user_extender.rb
77
+ - app/views/layouts/messaged/application.html.erb
78
+ - config/importmap.rb
79
+ - config/locales/en.yml
80
+ - config/routes.rb
81
+ - db/migrate/20221001034722_create_messaged.rb
82
+ - lib/generators/messaged/install/USAGE.md
83
+ - lib/generators/messaged/install/install_generator.rb
84
+ - lib/generators/messaged/install/templates/initializer.rb
85
+ - lib/generators/messaged/views/USAGE.md
86
+ - lib/generators/messaged/views/templates/messages/_form.html.erb
87
+ - lib/generators/messaged/views/templates/messages/_message.html.erb
88
+ - lib/generators/messaged/views/templates/messages/create.turbostream.erb
89
+ - lib/generators/messaged/views/templates/messages/edit.html.erb
90
+ - lib/generators/messaged/views/templates/messages/index.html.erb
91
+ - lib/generators/messaged/views/templates/messages/new.html.erb
92
+ - lib/generators/messaged/views/templates/messages/show.html.erb
93
+ - lib/generators/messaged/views/views_generator.rb
94
+ - lib/messaged.rb
95
+ - lib/messaged/base_migration.rb
96
+ - lib/messaged/engine.rb
97
+ - lib/messaged/version.rb
98
+ - lib/tasks/messaged_tasks.rake
99
+ homepage: https://github.com/ianrandmckenzie/messaged
100
+ licenses:
101
+ - MIT
102
+ metadata:
103
+ homepage_uri: https://github.com/ianrandmckenzie/messaged
104
+ source_code_uri: https://github.com/ianrandmckenzie/messaged
105
+ changelog_uri: https://github.com/ianrandmckenzie/messaged/blob/main/CHANGELOG.md
106
+ post_install_message:
107
+ rdoc_options: []
108
+ require_paths:
109
+ - lib
110
+ required_ruby_version: !ruby/object:Gem::Requirement
111
+ requirements:
112
+ - - ">="
113
+ - !ruby/object:Gem::Version
114
+ version: '0'
115
+ required_rubygems_version: !ruby/object:Gem::Requirement
116
+ requirements:
117
+ - - ">="
118
+ - !ruby/object:Gem::Version
119
+ version: '0'
120
+ requirements: []
121
+ rubygems_version: 3.3.7
122
+ signing_key:
123
+ specification_version: 4
124
+ summary: A Rails Engine for Hotwire Turbo-powered instant messaging.
125
+ test_files: []