mirror of
				https://github.com/lingble/chatwoot.git
				synced 2025-10-31 02:57:57 +00:00 
			
		
		
		
	| @@ -1,4 +1 @@ | ||||
| pusher_cluster= | ||||
| pusher_key= | ||||
|  | ||||
| fb_app_id= | ||||
|   | ||||
| @@ -43,7 +43,6 @@ module.exports = { | ||||
|   }, | ||||
|   globals: { | ||||
|     __WEBPACK_ENV__: true, | ||||
|     __PUSHER__: true, | ||||
|     __FB_APP_ID__: true, | ||||
|   }, | ||||
| }; | ||||
|   | ||||
| @@ -40,7 +40,7 @@ Lint/UselessAssignment: | ||||
|   Exclude: | ||||
|     - 'app/controllers/api/v1/callbacks_controller.rb' | ||||
|     - 'app/controllers/api/v1/facebook_indicators_controller.rb' | ||||
|     - 'app/listeners/pusher_listener.rb' | ||||
|     - 'app/listeners/action_cable_listener.rb' | ||||
|     - 'app/listeners/reporting_listener.rb' | ||||
|     - 'app/models/channel/facebook_page.rb' | ||||
|     - 'app/models/facebook_page.rb' | ||||
|   | ||||
							
								
								
									
										2
									
								
								Gemfile
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								Gemfile
									
									
									
									
									
								
							| @@ -39,7 +39,6 @@ gem 'devise_token_auth', git: 'https://github.com/lynndylanhurley/devise_token_a | ||||
| gem 'pundit' | ||||
|  | ||||
| ##--- gems for pubsub service ---## | ||||
| gem 'pusher' | ||||
| gem 'wisper', '2.0.0' | ||||
|  | ||||
| ##--- gems for reporting ---## | ||||
| @@ -72,6 +71,7 @@ group :development do | ||||
| end | ||||
|  | ||||
| group :test do | ||||
|   gem 'action-cable-testing' | ||||
|   gem 'mock_redis' | ||||
|   gem 'shoulda-matchers' | ||||
| end | ||||
|   | ||||
							
								
								
									
										19
									
								
								Gemfile.lock
									
									
									
									
									
								
							
							
						
						
									
										19
									
								
								Gemfile.lock
									
									
									
									
									
								
							| @@ -113,6 +113,8 @@ GIT | ||||
| GEM | ||||
|   remote: https://rubygems.org/ | ||||
|   specs: | ||||
|     action-cable-testing (0.6.0) | ||||
|       actioncable (>= 5.0) | ||||
|     addressable (2.7.0) | ||||
|       public_suffix (>= 2.0.2, < 5.0) | ||||
|     ast (2.4.0) | ||||
| @@ -161,13 +163,6 @@ GEM | ||||
|     coderay (1.1.2) | ||||
|     coercible (1.0.0) | ||||
|       descendants_tracker (~> 0.0.1) | ||||
|     coffee-rails (5.0.0) | ||||
|       coffee-script (>= 2.2.0) | ||||
|       railties (>= 5.2.0) | ||||
|     coffee-script (2.4.1) | ||||
|       coffee-script-source | ||||
|       execjs | ||||
|     coffee-script-source (1.12.2) | ||||
|     concurrent-ruby (1.1.5) | ||||
|     connection_pool (2.2.2) | ||||
|     crass (1.0.5) | ||||
| @@ -211,7 +206,6 @@ GEM | ||||
|     httparty (0.17.1) | ||||
|       mime-types (~> 3.0) | ||||
|       multi_xml (>= 0.5.2) | ||||
|     httpclient (2.8.3) | ||||
|     i18n (1.7.0) | ||||
|       concurrent-ruby (~> 1.0) | ||||
|     ice_nine (0.11.2) | ||||
| @@ -269,7 +263,6 @@ GEM | ||||
|     minitest (5.12.2) | ||||
|     mock_redis (0.22.0) | ||||
|     msgpack (1.3.1) | ||||
|     multi_json (1.14.1) | ||||
|     multi_xml (0.6.0) | ||||
|     multipart-post (2.1.1) | ||||
|     naught (1.1.0) | ||||
| @@ -292,11 +285,6 @@ GEM | ||||
|     puma (3.12.1) | ||||
|     pundit (2.1.0) | ||||
|       activesupport (>= 3.0.0) | ||||
|     pusher (1.3.3) | ||||
|       httpclient (~> 2.7) | ||||
|       multi_json (~> 1.0) | ||||
|       pusher-signature (~> 0.1.8) | ||||
|     pusher-signature (0.1.8) | ||||
|     rack (2.0.7) | ||||
|     rack-cache (1.9.0) | ||||
|       rack (>= 0.4) | ||||
| @@ -452,6 +440,7 @@ PLATFORMS | ||||
|   ruby | ||||
|  | ||||
| DEPENDENCIES | ||||
|   action-cable-testing | ||||
|   acts-as-taggable-on! | ||||
|   attr_extras | ||||
|   bootsnap | ||||
| @@ -459,7 +448,6 @@ DEPENDENCIES | ||||
|   byebug | ||||
|   carrierwave-aws | ||||
|   chargebee (~> 2) | ||||
|   coffee-rails | ||||
|   devise! | ||||
|   devise_token_auth! | ||||
|   facebook-messenger | ||||
| @@ -480,7 +468,6 @@ DEPENDENCIES | ||||
|   pry-rails | ||||
|   puma (~> 3.0) | ||||
|   pundit | ||||
|   pusher | ||||
|   rack-cors | ||||
|   rails (~> 6)! | ||||
|   redis | ||||
|   | ||||
							
								
								
									
										2
									
								
								app/channels/application_cable/channel.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								app/channels/application_cable/channel.rb
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,2 @@ | ||||
| class ApplicationCable::Channel < ActionCable::Channel::Base | ||||
| end | ||||
							
								
								
									
										2
									
								
								app/channels/application_cable/connection.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								app/channels/application_cable/connection.rb
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,2 @@ | ||||
| class ApplicationCable::Connection < ActionCable::Connection::Base | ||||
| end | ||||
							
								
								
									
										5
									
								
								app/channels/room_channel.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								app/channels/room_channel.rb
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | ||||
| class RoomChannel < ApplicationCable::Channel | ||||
|   def subscribed | ||||
|     stream_from params[:pubsub_token] | ||||
|   end | ||||
| end | ||||
| @@ -5,6 +5,6 @@ class SyncDispatcher < BaseDispatcher | ||||
|   end | ||||
|  | ||||
|   def listeners | ||||
|     [PusherListener.instance] | ||||
|     [ActionCableListener.instance] | ||||
|   end | ||||
| end | ||||
|   | ||||
| @@ -1,6 +1,5 @@ | ||||
| export default { | ||||
|   APP_BASE_URL: '/', | ||||
|   PUSHER: __PUSHER__, | ||||
|   get apiURL() { | ||||
|     return `${this.APP_BASE_URL}/`; | ||||
|   }, | ||||
|   | ||||
							
								
								
									
										70
									
								
								app/javascript/dashboard/helper/actionCable.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								app/javascript/dashboard/helper/actionCable.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,70 @@ | ||||
| import { createConsumer } from '@rails/actioncable'; | ||||
|  | ||||
| import AuthAPI from '../api/auth'; | ||||
|  | ||||
| class ActionCableConnector { | ||||
|   constructor(app, pubsubToken) { | ||||
|     const consumer = createConsumer(); | ||||
|     consumer.subscriptions.create( | ||||
|       { | ||||
|         channel: 'RoomChannel', | ||||
|         pubsub_token: pubsubToken, | ||||
|       }, | ||||
|       { | ||||
|         received: this.onReceived, | ||||
|       } | ||||
|     ); | ||||
|     this.app = app; | ||||
|     this.events = { | ||||
|       'message.created': this.onMessageCreated, | ||||
|       'conversation.created': this.onConversationCreated, | ||||
|       'status_change:conversation': this.onStatusChange, | ||||
|       'user:logout': this.onLogout, | ||||
|       'page:reload': this.onReload, | ||||
|       'assignee.changed': this.onAssigneeChanged, | ||||
|     }; | ||||
|   } | ||||
|  | ||||
|   onAssigneeChanged = payload => { | ||||
|     const { meta = {}, id } = payload; | ||||
|     const { assignee } = meta || {}; | ||||
|     if (id) { | ||||
|       this.app.$store.dispatch('updateAssignee', { id, assignee }); | ||||
|     } | ||||
|   }; | ||||
|  | ||||
|   onConversationCreated = data => { | ||||
|     this.app.$store.dispatch('addConversation', data); | ||||
|   }; | ||||
|  | ||||
|   onLogout = () => AuthAPI.logout(); | ||||
|  | ||||
|   onMessageCreated = data => { | ||||
|     this.app.$store.dispatch('addMessage', data); | ||||
|   }; | ||||
|  | ||||
|   onReceived = ({ event, data } = {}) => { | ||||
|     if (this.events[event]) { | ||||
|       this.events[event](data); | ||||
|     } | ||||
|   }; | ||||
|  | ||||
|   onReload = () => window.location.reload(); | ||||
|  | ||||
|   onStatusChange = data => { | ||||
|     this.app.$store.dispatch('addConversation', data); | ||||
|   }; | ||||
| } | ||||
|  | ||||
| export default { | ||||
|   init() { | ||||
|     if (AuthAPI.isLoggedIn()) { | ||||
|       const actionCable = new ActionCableConnector( | ||||
|         window.WOOT, | ||||
|         AuthAPI.getPubSubToken() | ||||
|       ); | ||||
|       return actionCable; | ||||
|     } | ||||
|     return null; | ||||
|   }, | ||||
| }; | ||||
| @@ -1,71 +0,0 @@ | ||||
| /* eslint-env browser */ | ||||
| /* eslint no-console: 0 */ | ||||
| import Pusher from 'pusher-js'; | ||||
| import AuthAPI from '../api/auth'; | ||||
| import CONSTANTS from '../constants'; | ||||
|  | ||||
| class VuePusher { | ||||
|   constructor(apiKey, options) { | ||||
|     this.app = options.app; | ||||
|     this.pusher = new Pusher(apiKey, options); | ||||
|     this.channels = []; | ||||
|   } | ||||
|  | ||||
|   subscribe(channelName) { | ||||
|     const channel = this.pusher.subscribe(channelName); | ||||
|     if (!this.channels.includes(channel)) { | ||||
|       this.channels.push(channelName); | ||||
|     } | ||||
|     this.bindEvent(channel); | ||||
|   } | ||||
|  | ||||
|   unsubscribe(channelName) { | ||||
|     this.pusher.unsubscribe(channelName); | ||||
|   } | ||||
|  | ||||
|   bindEvent(channel) { | ||||
|     channel.bind('message.created', data => { | ||||
|       this.app.$store.dispatch('addMessage', data); | ||||
|     }); | ||||
|  | ||||
|     channel.bind('conversation.created', data => { | ||||
|       this.app.$store.dispatch('addConversation', data); | ||||
|     }); | ||||
|  | ||||
|     channel.bind('status_change:conversation', data => { | ||||
|       this.app.$store.dispatch('addConversation', data); | ||||
|     }); | ||||
|  | ||||
|     channel.bind('assignee.changed', payload => { | ||||
|       const { meta = {}, id } = payload; | ||||
|       const { assignee } = meta || {}; | ||||
|       if (id) { | ||||
|         this.app.$store.dispatch('updateAssignee', { id, assignee }); | ||||
|       } | ||||
|     }); | ||||
|  | ||||
|     channel.bind('user:logout', () => AuthAPI.logout()); | ||||
|     channel.bind('page:reload', () => window.location.reload()); | ||||
|   } | ||||
| } | ||||
|  | ||||
| /* eslint no-param-reassign: ["error", { "props": false }] */ | ||||
| export default { | ||||
|   init() { | ||||
|     // Log only if env is testing or development. | ||||
|     Pusher.logToConsole = CONSTANTS.PUSHER.logToConsole || true; | ||||
|     // Init Pusher | ||||
|     const options = { | ||||
|       encrypted: true, | ||||
|       app: window.WOOT, | ||||
|       cluster: CONSTANTS.PUSHER.cluster, | ||||
|     }; | ||||
|     const pusher = new VuePusher(CONSTANTS.PUSHER.token, options); | ||||
|     // Add to global Obj | ||||
|     if (AuthAPI.isLoggedIn()) { | ||||
|       pusher.subscribe(AuthAPI.getPubSubToken()); | ||||
|       return pusher.pusher; | ||||
|     } | ||||
|     return null; | ||||
|   }, | ||||
| }; | ||||
| @@ -14,7 +14,6 @@ jest.mock('./login/login.routes', () => ({ | ||||
| jest.mock('../constants', () => { | ||||
|   return { | ||||
|     APP_BASE_URL: '/', | ||||
|     PUSHER: false, | ||||
|     get apiUrl() { | ||||
|       return `${this.APP_BASE_URL}/`; | ||||
|     }, | ||||
|   | ||||
| @@ -8,7 +8,7 @@ import * as types from '../mutation-types'; | ||||
| import router from '../../routes'; | ||||
| import authAPI from '../../api/auth'; | ||||
| import createAxios from '../../helper/APIHelper'; | ||||
| import vuePusher from '../../helper/pusher'; | ||||
| import actionCable from '../../helper/actionCable'; | ||||
| // initial state | ||||
| const state = { | ||||
|   currentUser: { | ||||
| @@ -61,7 +61,7 @@ const actions = { | ||||
|         .then(() => { | ||||
|           commit(types.default.SET_CURRENT_USER); | ||||
|           window.axios = createAxios(axios); | ||||
|           window.pusher = vuePusher.init(Vue); | ||||
|           actionCable.init(Vue); | ||||
|           router.replace({ name: 'home' }); | ||||
|           resolve(); | ||||
|         }) | ||||
|   | ||||
| @@ -168,7 +168,7 @@ const mutations = { | ||||
|     _state.chatStatusFilter = data; | ||||
|   }, | ||||
|  | ||||
|   // Update assignee on pusher message | ||||
|   // Update assignee on action cable message | ||||
|   [types.default.UPDATE_ASSIGNEE](_state, payload) { | ||||
|     const [chat] = _state.allConversations.filter(c => c.id === payload.id); | ||||
|     chat.meta.assignee = payload.assignee; | ||||
|   | ||||
| @@ -24,7 +24,7 @@ import createAxios from '../dashboard/helper/APIHelper'; | ||||
| import commonHelpers from '../dashboard/helper/commons'; | ||||
| import router from '../dashboard/routes'; | ||||
| import store from '../dashboard/store'; | ||||
| import vuePusher from '../dashboard/helper/pusher'; | ||||
| import vueActionCable from '../dashboard/helper/actionCable'; | ||||
| import constants from '../dashboard/constants'; | ||||
|  | ||||
| Vue.config.env = process.env; | ||||
| @@ -58,7 +58,7 @@ window.onload = () => { | ||||
|     components: { App }, | ||||
|     template: '<App/>', | ||||
|   }).$mount('#app'); | ||||
|   window.pusher = vuePusher.init(); | ||||
|   vueActionCable.init(); | ||||
| }; | ||||
|  | ||||
| if ('serviceWorker' in navigator) { | ||||
|   | ||||
| @@ -1,46 +1,53 @@ | ||||
| class PusherListener < BaseListener | ||||
| class ActionCableListener < BaseListener | ||||
|   include Events::Types | ||||
| 
 | ||||
|   def conversation_created(event) | ||||
|     conversation, account, timestamp = extract_conversation_and_account(event) | ||||
|     members = conversation.inbox.members.pluck(:pubsub_token) | ||||
|     Pusher.trigger(members, CONVERSATION_CREATED, conversation.push_event_data) if members.present? | ||||
|     send_to_members(members, CONVERSATION_CREATED, conversation.push_event_data) | ||||
|   end | ||||
| 
 | ||||
|   def conversation_read(event) | ||||
|     conversation, account, timestamp = extract_conversation_and_account(event) | ||||
|     members = conversation.inbox.members.pluck(:pubsub_token) | ||||
|     Pusher.trigger(members, CONVERSATION_READ, conversation.push_event_data) if members.present? | ||||
|     send_to_members(members, CONVERSATION_READ, conversation.push_event_data) | ||||
|   end | ||||
| 
 | ||||
|   def message_created(event) | ||||
|     message, account, timestamp = extract_message_and_account(event) | ||||
|     conversation = message.conversation | ||||
|     members = conversation.inbox.members.pluck(:pubsub_token) | ||||
| 
 | ||||
|     Pusher.trigger(members, MESSAGE_CREATED, message.push_event_data) if members.present? | ||||
|     send_to_members(members, MESSAGE_CREATED, message.push_event_data) | ||||
|   end | ||||
| 
 | ||||
|   def conversation_reopened(event) | ||||
|     conversation, account, timestamp = extract_conversation_and_account(event) | ||||
|     members = conversation.inbox.members.pluck(:pubsub_token) | ||||
|     Pusher.trigger(members, CONVERSATION_REOPENED, conversation.push_event_data) if members.present? | ||||
|     send_to_members(members, CONVERSATION_REOPENED, conversation.push_event_data) | ||||
|   end | ||||
| 
 | ||||
|   def conversation_lock_toggle(event) | ||||
|     conversation, account, timestamp = extract_conversation_and_account(event) | ||||
|     members = conversation.inbox.members.pluck(:pubsub_token) | ||||
|     Pusher.trigger(members, CONVERSATION_LOCK_TOGGLE, conversation.lock_event_data) if members.present? | ||||
|     send_to_members(members, CONVERSATION_LOCK_TOGGLE, conversation.lock_event_data) | ||||
|   end | ||||
| 
 | ||||
|   def assignee_changed(event) | ||||
|     conversation, account, timestamp = extract_conversation_and_account(event) | ||||
|     members = conversation.inbox.members.pluck(:pubsub_token) | ||||
|     Pusher.trigger(members, ASSIGNEE_CHANGED, conversation.push_event_data) if members.present? | ||||
|     send_to_members(members, ASSIGNEE_CHANGED, conversation.push_event_data) | ||||
|   end | ||||
| 
 | ||||
|   private | ||||
| 
 | ||||
|   def send_to_members(members, event_name, data) | ||||
|     return if members.blank? | ||||
| 
 | ||||
|     members.each do |member| | ||||
|       ActionCable.server.broadcast(member, event: event_name, data: data) | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   def push(pubsub_token, data) | ||||
|     # Enqueue sidekiq job to push event to corresponding channel | ||||
|   end | ||||
| @@ -4,7 +4,7 @@ module Pubsubable | ||||
|   extend ActiveSupport::Concern | ||||
|  | ||||
|   included do | ||||
|     # Used by the pusher/PubSub Service we use for real time communications | ||||
|     # Used by the actionCable/PubSub Service we use for real time communications | ||||
|     has_secure_token :pubsub_token | ||||
|   end | ||||
| end | ||||
|   | ||||
| @@ -12,7 +12,7 @@ class User < ApplicationRecord | ||||
|          :validatable, | ||||
|          :confirmable | ||||
|  | ||||
|   # Used by the pusher/PubSub Service we use for real time communications | ||||
|   # Used by the actionCable/PubSub Service we use for real time communications | ||||
|   has_secure_token :pubsub_token | ||||
|  | ||||
|   validates_uniqueness_of :email, scope: :account_id | ||||
|   | ||||
							
								
								
									
										13
									
								
								config/cable.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								config/cable.yml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,13 @@ | ||||
| development: | ||||
|   adapter: async | ||||
|  | ||||
| test: | ||||
|   adapter: test | ||||
|  | ||||
| staging: | ||||
|   adapter: redis | ||||
|   url: <%= ENV.fetch('REDIS_URL', 'redis://127.0.0.1:6379') %> | ||||
|  | ||||
| production: | ||||
|   adapter: redis | ||||
|   url: <%= ENV.fetch('REDIS_URL', 'redis://127.0.0.1:6379') %> | ||||
| @@ -1,6 +0,0 @@ | ||||
| Pusher.app_id = ENV['pusher_app_id'] | ||||
| Pusher.key    = ENV['pusher_key'] | ||||
| Pusher.secret = ENV['pusher_secret'] | ||||
| Pusher.encrypted = true | ||||
| Pusher.logger = Rails.logger | ||||
| Pusher.cluster = ENV['pusher_cluster'] | ||||
| @@ -17,19 +17,11 @@ environment.loaders.append('audio', { | ||||
|  | ||||
| environment.config.merge({ resolve }); | ||||
|  | ||||
| const { | ||||
|   pusher_cluster: cluster, | ||||
|   pusher_key: token, | ||||
|   fb_app_id: fbAppID, | ||||
| } = process.env; | ||||
| const { fb_app_id: fbAppID } = process.env; | ||||
|  | ||||
| environment.plugins.prepend( | ||||
|   'DefinePlugin', | ||||
|   new webpack.DefinePlugin({ | ||||
|     __PUSHER__: { | ||||
|       token: `"${token}"`, | ||||
|       cluster: `"${cluster}"`, | ||||
|     }, | ||||
|     __FB_ID__: `"${fbAppID}"`, | ||||
|   }) | ||||
| ); | ||||
|   | ||||
| @@ -26,17 +26,6 @@ development: | ||||
|  | ||||
| Following changes has to be in `config/application.yml` | ||||
|  | ||||
| ### Configure Pusher | ||||
|  | ||||
| Chatwoot uses [Pusher](https://pusher.com/) to handle realtime messages. Create a free account on Pusher and fill the following environment values. | ||||
|  | ||||
| ```yml | ||||
| pusher_app_id: '' | ||||
| pusher_key: '' | ||||
| pusher_secret: '' | ||||
| pusher_cluster: '' | ||||
| ``` | ||||
|  | ||||
| ### Configure FB Channel | ||||
|  | ||||
| To use FB Channel, you have to create an Facebook app in developer portal. You can find more details about creating FB channels [here](https://developers.facebook.com/docs/apps/#register) | ||||
|   | ||||
| @@ -12,6 +12,7 @@ | ||||
|   }, | ||||
|   "dependencies": { | ||||
|     "@babel/polyfill": "^7.6.0", | ||||
|     "@rails/actioncable": "^6.0.0", | ||||
|     "@rails/webpacker": "^4.0.7", | ||||
|     "axios": "^0.19.0", | ||||
|     "babel-helper-vue-jsx-merge-props": "^2.0.3", | ||||
| @@ -27,7 +28,6 @@ | ||||
|     "js-cookie": "~2.1.3", | ||||
|     "md5": "~2.2.1", | ||||
|     "moment": "~2.19.3", | ||||
|     "pusher-js": "~4.0.0", | ||||
|     "query-string": "5", | ||||
|     "spinkit": "~1.2.5", | ||||
|     "tween.js": "~16.6.0", | ||||
|   | ||||
| @@ -1,10 +1,3 @@ | ||||
| #pusher | ||||
|  | ||||
| pusher_app_id: '' | ||||
| pusher_key: '' | ||||
| pusher_secret: '' | ||||
| pusher_cluster: '' | ||||
|  | ||||
| #fb app | ||||
| fb_verify_token: '' | ||||
| fb_app_secret: '' | ||||
|   | ||||
							
								
								
									
										15
									
								
								spec/controllers/room_channel_spec.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								spec/controllers/room_channel_spec.rb
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,15 @@ | ||||
| require 'rails_helper' | ||||
|  | ||||
| RSpec.describe RoomChannel, type: :channel do | ||||
|   let!(:user) { create(:user) } | ||||
|  | ||||
|   before do | ||||
|     stub_connection | ||||
|   end | ||||
|  | ||||
|   it 'subscribes to a stream when pubsub_token is provided' do | ||||
|     subscribe(pubsub_token: user.uid) | ||||
|     expect(subscription).to be_confirmed | ||||
|     expect(subscription).to have_stream_for(user.uid) | ||||
|   end | ||||
| end | ||||
| @@ -4,6 +4,8 @@ require File.expand_path('../config/environment', __dir__) | ||||
| # Prevent database truncation if the environment is production | ||||
| abort('The Rails environment is running in production mode!') if Rails.env.production? | ||||
| require 'rspec/rails' | ||||
| require 'action_cable/testing/rspec' | ||||
|  | ||||
| # Add additional requires below this line. Rails is not loaded until this point! | ||||
|  | ||||
| # Requires supporting ruby files with custom matchers and macros, etc, in | ||||
|   | ||||
							
								
								
									
										25
									
								
								yarn.lock
									
									
									
									
									
								
							
							
						
						
									
										25
									
								
								yarn.lock
									
									
									
									
									
								
							| @@ -966,6 +966,11 @@ | ||||
|     "@nodelib/fs.scandir" "2.1.3" | ||||
|     fastq "^1.6.0" | ||||
|  | ||||
| "@rails/actioncable@^6.0.0": | ||||
|   version "6.0.0" | ||||
|   resolved "https://registry.yarnpkg.com/@rails/actioncable/-/actioncable-6.0.0.tgz#8bff9c902be1531ef7a9e191562e9771efcfdfe1" | ||||
|   integrity sha512-DieouotYHpI6k2EGTCnh1eMvD3W8p3zqjWXEYj4z0khJ+A0qQ5tHxihjTEkio54MVwqHt1DcpUm2woh2n/alCA== | ||||
|  | ||||
| "@rails/webpacker@^4.0.7": | ||||
|   version "4.0.7" | ||||
|   resolved "https://registry.yarnpkg.com/@rails/webpacker/-/webpacker-4.0.7.tgz#268571bf974e78ce57eca9fa478f5bd97fd5182c" | ||||
| @@ -4431,13 +4436,6 @@ fastq@^1.6.0: | ||||
|   dependencies: | ||||
|     reusify "^1.0.0" | ||||
|  | ||||
| faye-websocket@0.9.4: | ||||
|   version "0.9.4" | ||||
|   resolved "https://registry.yarnpkg.com/faye-websocket/-/faye-websocket-0.9.4.tgz#885934c79effb0409549e0c0a3801ed17a40cdad" | ||||
|   integrity sha1-iFk0x57/sECVSeDAo4Ae0XpAza0= | ||||
|   dependencies: | ||||
|     websocket-driver ">=0.5.1" | ||||
|  | ||||
| faye-websocket@^0.10.0: | ||||
|   version "0.10.0" | ||||
|   resolved "https://registry.yarnpkg.com/faye-websocket/-/faye-websocket-0.10.0.tgz#4e492f8d04dfb6f89003507f6edbf2d501e7c6f4" | ||||
| @@ -8730,14 +8728,6 @@ punycode@^2.1.0, punycode@^2.1.1: | ||||
|   resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" | ||||
|   integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== | ||||
|  | ||||
| pusher-js@~4.0.0: | ||||
|   version "4.0.0" | ||||
|   resolved "https://registry.yarnpkg.com/pusher-js/-/pusher-js-4.0.0.tgz#3f53f9a8e2cb55b89b7724881615f891f200ab8e" | ||||
|   integrity sha1-P1P5qOLLVbibdySIFhX4kfIAq44= | ||||
|   dependencies: | ||||
|     faye-websocket "0.9.4" | ||||
|     xmlhttprequest "^1.8.0" | ||||
|  | ||||
| q@^1.1.2: | ||||
|   version "1.5.1" | ||||
|   resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7" | ||||
| @@ -10975,11 +10965,6 @@ xml-name-validator@^3.0.0: | ||||
|   resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-3.0.0.tgz#6ae73e06de4d8c6e47f9fb181f78d648ad457c6a" | ||||
|   integrity sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw== | ||||
|  | ||||
| xmlhttprequest@^1.8.0: | ||||
|   version "1.8.0" | ||||
|   resolved "https://registry.yarnpkg.com/xmlhttprequest/-/xmlhttprequest-1.8.0.tgz#67fe075c5c24fef39f9d65f5f7b7fe75171968fc" | ||||
|   integrity sha1-Z/4HXFwk/vOfnWX197f+dRcZaPw= | ||||
|  | ||||
| xtend@^4.0.0, xtend@~4.0.1: | ||||
|   version "4.0.2" | ||||
|   resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Pranav Raj S
					Pranav Raj S