activity_notification 2.1.3 → 2.1.4

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 (44) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +13 -1
  3. data/Gemfile +0 -2
  4. data/activity_notification.gemspec +1 -1
  5. data/docs/Functions.md +2 -2
  6. data/docs/Setup.md +176 -63
  7. data/gemfiles/Gemfile.rails-5.0 +1 -0
  8. data/gemfiles/Gemfile.rails-5.1 +1 -0
  9. data/gemfiles/Gemfile.rails-5.2 +1 -0
  10. data/gemfiles/Gemfile.rails-6.0 +0 -2
  11. data/lib/activity_notification/apis/notification_api.rb +7 -0
  12. data/lib/activity_notification/common.rb +4 -1
  13. data/lib/activity_notification/models/concerns/notifiable.rb +10 -10
  14. data/lib/activity_notification/models/concerns/swagger/notification_schema.rb +34 -34
  15. data/lib/activity_notification/models/concerns/swagger/subscription_schema.rb +17 -17
  16. data/lib/activity_notification/optional_targets/action_cable_api_channel.rb +1 -1
  17. data/lib/activity_notification/optional_targets/action_cable_channel.rb +1 -1
  18. data/lib/activity_notification/orm/dynamoid.rb +10 -3
  19. data/lib/activity_notification/orm/dynamoid/notification.rb +48 -13
  20. data/lib/activity_notification/orm/dynamoid/subscription.rb +1 -1
  21. data/lib/activity_notification/orm/mongoid.rb +10 -3
  22. data/lib/activity_notification/orm/mongoid/notification.rb +4 -4
  23. data/lib/activity_notification/roles/acts_as_notifiable.rb +2 -1
  24. data/lib/activity_notification/version.rb +1 -1
  25. data/spec/concerns/models/notifiable_spec.rb +35 -35
  26. data/spec/config_spec.rb +26 -15
  27. data/spec/rails_app/app/controllers/users_controller.rb +5 -0
  28. data/spec/rails_app/app/javascript/App.vue +8 -72
  29. data/spec/rails_app/app/javascript/components/DeviseTokenAuth.vue +3 -4
  30. data/spec/rails_app/app/javascript/components/Top.vue +2 -3
  31. data/spec/rails_app/app/javascript/packs/spa.js +6 -3
  32. data/spec/rails_app/app/javascript/router/index.js +73 -0
  33. data/spec/rails_app/app/javascript/store/{auth.js → index.js} +0 -0
  34. data/spec/rails_app/app/models/dummy/dummy_group.rb +8 -0
  35. data/spec/rails_app/app/models/dummy/dummy_notifiable_target.rb +8 -0
  36. data/spec/rails_app/app/models/user.rb +2 -1
  37. data/spec/rails_app/config/application.rb +4 -1
  38. data/spec/rails_app/config/dynamoid.rb +11 -3
  39. data/spec/rails_app/config/environments/production.rb +3 -0
  40. data/spec/rails_app/config/initializers/activity_notification.rb +3 -3
  41. data/spec/rails_app/config/routes.rb +5 -1
  42. data/spec/rails_app/db/seeds.rb +9 -2
  43. data/spec/roles/acts_as_notifiable_spec.rb +5 -5
  44. metadata +6 -10
@@ -35,38 +35,49 @@ describe ActivityNotification::Config do
35
35
  describe "config.store_with_associated_records" do
36
36
  let(:target) { create(:confirmed_user) }
37
37
 
38
- context "false as default" do
39
- before do
40
- @notification = create(:notification, target: target)
41
- end
42
-
43
- it "stores notification without associated records" do
44
- expect(@notification.target).to eq(target)
45
- expect { @notification.target_record }.to raise_error(NoMethodError)
46
- end
47
- end
48
-
49
38
  context "when it is configured as true" do
50
39
  if ActivityNotification.config.orm == :active_record
51
40
  it "raises ActivityNotification::ConfigError when you use active_record ORM" do
52
41
  expect { ActivityNotification.config.store_with_associated_records = true }.to raise_error(ActivityNotification::ConfigError)
53
42
  end
54
-
55
43
  else
56
44
  before do
45
+ @original = ActivityNotification.config.store_with_associated_records
57
46
  ActivityNotification.config.store_with_associated_records = true
58
47
  load Rails.root.join("../../lib/activity_notification/orm/#{ActivityNotification.config.orm}/notification.rb").to_s
59
48
  @notification = create(:notification, target: target)
60
49
  end
61
50
 
62
51
  after do
63
- ActivityNotification.config.store_with_associated_records = false
52
+ ActivityNotification.config.store_with_associated_records = @original
64
53
  load Rails.root.join("../../lib/activity_notification/orm/#{ActivityNotification.config.orm}/notification.rb").to_s
65
54
  end
66
55
 
67
- it "stores notification without associated records" do
56
+ it "stores notification with associated records" do
68
57
  expect(@notification.target).to eq(target)
69
- expect(@notification.target_record).to eq(target.to_json)
58
+ expect(@notification.stored_target["id"].to_s).to eq(target.id.to_s)
59
+ end
60
+ end
61
+ end
62
+
63
+ context "when it is configured as false" do
64
+ before do
65
+ @original = ActivityNotification.config.store_with_associated_records
66
+ ActivityNotification.config.store_with_associated_records = false
67
+ load Rails.root.join("../../lib/activity_notification/orm/#{ActivityNotification.config.orm}/notification.rb").to_s
68
+ @notification = create(:notification, target: target)
69
+ end
70
+
71
+ after do
72
+ ActivityNotification.config.store_with_associated_records = @original
73
+ load Rails.root.join("../../lib/activity_notification/orm/#{ActivityNotification.config.orm}/notification.rb").to_s
74
+ end
75
+
76
+ it "does not store notification with associated records" do
77
+ expect(@notification.target).to eq(target)
78
+ begin
79
+ expect(@notification.stored_target).to be_nil
80
+ rescue NoMethodError
70
81
  end
71
82
  end
72
83
  end
@@ -13,6 +13,11 @@ class UsersController < ApplicationController
13
13
  render json: @user
14
14
  end
15
15
 
16
+ # GET /users/find
17
+ def find
18
+ render json: User.find_by_email!(params[:email])
19
+ end
20
+
16
21
  private
17
22
  # Use callbacks to share common setup or constraints between actions.
18
23
  def set_user
@@ -6,85 +6,15 @@
6
6
 
7
7
  <script>
8
8
  import Vue from 'vue'
9
- import VueRouter from 'vue-router'
10
9
  import VueMoment from 'vue-moment'
11
10
  import moment from 'moment-timezone'
12
11
  import VuePluralize from 'vue-pluralize'
13
12
  import ActionCableVue from 'actioncable-vue'
14
13
  import axios from 'axios'
15
14
  import env from './config/environment'
16
- import authStore from "./store/auth"
17
- import Top from './components/Top.vue'
18
- import DeviseTokenAuth from './components/DeviseTokenAuth.vue'
19
- import NotificationsIndex from './components/notifications/Index.vue'
20
- import SubscriptionsIndex from './components/subscriptions/Index.vue'
21
15
 
22
- const router = new VueRouter({
23
- routes: [
24
- { path: '/', component: Top },
25
- { path: '/login', component: DeviseTokenAuth },
26
- { path: '/logout', component: DeviseTokenAuth, props: { isLogout: true } },
27
- // Routes for single page application working with activity_notification REST API backend for users
28
- {
29
- path: '/notifications',
30
- name: 'AuthenticatedUserNotificationsIndex',
31
- component: NotificationsIndex,
32
- props: () => ({ target_type: 'users', target: authStore.getters.currentUser }),
33
- meta: { requiresAuth: true }
34
- },
35
- {
36
- path: '/subscriptions',
37
- name: 'AuthenticatedUserSubscriptionsIndex',
38
- component: SubscriptionsIndex,
39
- props: () => ({ target_type: 'users', target: authStore.getters.currentUser }),
40
- meta: { requiresAuth: true }
41
- },
42
- // Routes for single page application working with activity_notification REST API backend for admins
43
- {
44
- path: '/admins/notifications',
45
- name: 'AuthenticatedAdminNotificationsIndex',
46
- component: NotificationsIndex,
47
- props: () => ({ target_type: 'admins', targetApiPath: 'admins', target: authStore.getters.currentUser.admin }),
48
- meta: { requiresAuth: true }
49
- },
50
- {
51
- path: '/admins/subscriptions',
52
- name: 'AuthenticatedAdminSubscriptionsIndex',
53
- component: SubscriptionsIndex,
54
- props: () => ({ target_type: 'admins', targetApiPath: 'admins', target: authStore.getters.currentUser.admin }),
55
- meta: { requiresAuth: true }
56
- },
57
- // Routes for single page application working with activity_notification REST API backend for unauthenticated targets
58
- {
59
- path: '/:target_type/:target_id/notifications',
60
- name: 'UnauthenticatedTargetNotificationsIndex',
61
- component: NotificationsIndex,
62
- props : true
63
- },
64
- {
65
- path: '/:target_type/:target_id/subscriptions',
66
- name: 'UnauthenticatedTargetSubscriptionsIndex',
67
- component: SubscriptionsIndex,
68
- props : true
69
- }
70
- ]
71
- })
72
-
73
- router.beforeEach((to, from, next) => {
74
- if (to.matched.some(record => record.meta.requiresAuth) && !authStore.getters.userSignedIn) {
75
- next({ path: '/login', query: { redirect: to.fullPath }});
76
- } else {
77
- next();
78
- }
79
- })
16
+ axios.defaults.baseURL = "/api/v2"
80
17
 
81
- if (authStore.getters.userSignedIn) {
82
- for (var authHeader of Object.keys(authStore.getters.authHeaders)) {
83
- axios.defaults.headers.common[authHeader] = authStore.getters.authHeaders[authHeader];
84
- }
85
- }
86
-
87
- Vue.use(VueRouter)
88
18
  Vue.use(VueMoment, { moment })
89
19
  Vue.use(VuePluralize)
90
20
  Vue.use(ActionCableVue, {
@@ -96,7 +26,13 @@ Vue.use(ActionCableVue, {
96
26
 
97
27
  export default {
98
28
  name: 'App',
99
- router
29
+ mounted () {
30
+ if (this.$store.getters.userSignedIn) {
31
+ for (var authHeader of Object.keys(this.$store.getters.authHeaders)) {
32
+ axios.defaults.headers.common[authHeader] = this.$store.getters.authHeaders[authHeader];
33
+ }
34
+ }
35
+ }
100
36
  }
101
37
  </script>
102
38
 
@@ -19,7 +19,6 @@
19
19
 
20
20
  <script>
21
21
  import axios from 'axios'
22
- import authStore from "../store/auth"
23
22
 
24
23
  export default {
25
24
  name: 'DeviseTokenAuth',
@@ -53,7 +52,7 @@ export default {
53
52
  authHeaders[authHeader] = response.headers[authHeader];
54
53
  axios.defaults.headers.common[authHeader] = authHeaders[authHeader];
55
54
  }
56
- authStore.commit('signIn', { user: response.data.data, authHeaders: authHeaders });
55
+ this.$store.commit('signIn', { user: response.data.data, authHeaders: authHeaders });
57
56
  if (this.$route.query.redirect) {
58
57
  this.$router.push(this.$route.query.redirect);
59
58
  } else {
@@ -69,10 +68,10 @@ export default {
69
68
  })
70
69
  },
71
70
  logout () {
72
- for (var authHeader of Object.keys(authStore.getters.authHeaders)) {
71
+ for (var authHeader of Object.keys(this.$store.getters.authHeaders)) {
73
72
  delete axios.defaults.headers.common[authHeader];
74
73
  }
75
- authStore.commit('signOut');
74
+ this.$store.commit('signOut');
76
75
  this.$router.push('/');
77
76
  }
78
77
  }
@@ -70,14 +70,13 @@
70
70
 
71
71
  <script>
72
72
  import axios from 'axios'
73
- import authStore from "../store/auth"
74
73
 
75
74
  export default {
76
75
  name: 'Top',
77
76
  data () {
78
77
  return {
79
- userSignedIn: authStore.getters.userSignedIn,
80
- currentUser: authStore.getters.currentUser,
78
+ userSignedIn: this.$store.getters.userSignedIn,
79
+ currentUser: this.$store.getters.currentUser,
81
80
  users: [],
82
81
  admins: []
83
82
  }
@@ -1,11 +1,14 @@
1
1
  import Vue from 'vue'
2
- import axios from 'axios'
3
2
  import App from '../App.vue'
3
+ import router from '../router'
4
+ import store from '../store'
4
5
 
5
- axios.defaults.baseURL = "/api/v2"
6
+ Vue.config.productionTip = false
6
7
 
7
8
  document.addEventListener('DOMContentLoaded', () => {
8
- const app = new Vue({
9
+ new Vue({
10
+ router,
11
+ store,
9
12
  render: h => h(App)
10
13
  }).$mount('#spa')
11
14
  })
@@ -0,0 +1,73 @@
1
+ import Vue from 'vue'
2
+ import VueRouter from 'vue-router'
3
+ import store from '../store'
4
+ import DeviseTokenAuth from '../components/DeviseTokenAuth.vue'
5
+ import Top from '../components/Top.vue'
6
+ import NotificationsIndex from '../components/notifications/Index.vue'
7
+ import SubscriptionsIndex from '../components/subscriptions/Index.vue'
8
+
9
+ Vue.use(VueRouter)
10
+
11
+ const routes = [
12
+ // Routes for common components
13
+ { path: '/', component: Top },
14
+ { path: '/login', component: DeviseTokenAuth },
15
+ { path: '/logout', component: DeviseTokenAuth, props: { isLogout: true } },
16
+ // Routes for single page application working with activity_notification REST API backend for users
17
+ {
18
+ path: '/notifications',
19
+ name: 'AuthenticatedUserNotificationsIndex',
20
+ component: NotificationsIndex,
21
+ props: () => ({ target_type: 'users', target: store.getters.currentUser }),
22
+ meta: { requiresAuth: true }
23
+ },
24
+ {
25
+ path: '/subscriptions',
26
+ name: 'AuthenticatedUserSubscriptionsIndex',
27
+ component: SubscriptionsIndex,
28
+ props: () => ({ target_type: 'users', target: store.getters.currentUser }),
29
+ meta: { requiresAuth: true }
30
+ },
31
+ // Routes for single page application working with activity_notification REST API backend for admins
32
+ {
33
+ path: '/admins/notifications',
34
+ name: 'AuthenticatedAdminNotificationsIndex',
35
+ component: NotificationsIndex,
36
+ props: () => ({ target_type: 'admins', targetApiPath: 'admins', target: store.getters.currentUser.admin }),
37
+ meta: { requiresAuth: true }
38
+ },
39
+ {
40
+ path: '/admins/subscriptions',
41
+ name: 'AuthenticatedAdminSubscriptionsIndex',
42
+ component: SubscriptionsIndex,
43
+ props: () => ({ target_type: 'admins', targetApiPath: 'admins', target: store.getters.currentUser.admin }),
44
+ meta: { requiresAuth: true }
45
+ },
46
+ // Routes for single page application working with activity_notification REST API backend for unauthenticated targets
47
+ {
48
+ path: '/:target_type/:target_id/notifications',
49
+ name: 'UnauthenticatedTargetNotificationsIndex',
50
+ component: NotificationsIndex,
51
+ props : true
52
+ },
53
+ {
54
+ path: '/:target_type/:target_id/subscriptions',
55
+ name: 'UnauthenticatedTargetSubscriptionsIndex',
56
+ component: SubscriptionsIndex,
57
+ props : true
58
+ }
59
+ ]
60
+
61
+ const router = new VueRouter({
62
+ routes
63
+ })
64
+
65
+ router.beforeEach((to, from, next) => {
66
+ if (to.matched.some(record => record.meta.requiresAuth) && !store.getters.userSignedIn) {
67
+ next({ path: '/login', query: { redirect: to.fullPath }});
68
+ } else {
69
+ next();
70
+ }
71
+ })
72
+
73
+ export default router
@@ -3,6 +3,14 @@ unless ENV['AN_TEST_DB'] == 'mongodb'
3
3
  self.table_name = :articles
4
4
  include ActivityNotification::Group
5
5
  end
6
+
7
+ def printable_target_name
8
+ "dummy"
9
+ end
10
+
11
+ def printable_group_name
12
+ "dummy"
13
+ end
6
14
  else
7
15
  class Dummy::DummyGroup
8
16
  include Mongoid::Document
@@ -3,6 +3,10 @@ unless ENV['AN_TEST_DB'] == 'mongodb'
3
3
  self.table_name = :users
4
4
  acts_as_target
5
5
  acts_as_notifiable :dummy_notifiable_targets, targets: -> (n, key) { Dummy::DummyNotifiableTarget.all }, tracked: true
6
+
7
+ def notifiable_path(target_type, key = nil)
8
+ "dummy_path"
9
+ end
6
10
  end
7
11
  else
8
12
  class Dummy::DummyNotifiableTarget
@@ -15,5 +19,9 @@ else
15
19
  include ActivityNotification::Models
16
20
  acts_as_target
17
21
  acts_as_notifiable :dummy_notifiable_targets, targets: -> (n, key) { Dummy::DummyNotifiableTarget.all }, tracked: true
22
+
23
+ def notifiable_path(target_type, key = nil)
24
+ "dummy_path"
25
+ end
18
26
  end
19
27
  end
@@ -21,7 +21,8 @@ module UserModel
21
21
  admin.present?
22
22
  end
23
23
 
24
- def as_json(options = {})
24
+ def as_json(_options = {})
25
+ options = _options.deep_dup
25
26
  options[:include] = (options[:include] || {}).merge(admin: { methods: [:printable_target_name, :notification_action_cable_allowed?, :notification_action_cable_with_devise?] })
26
27
  options[:methods] = (options[:methods] || []).push(:printable_target_name, :notification_action_cable_allowed?, :notification_action_cable_with_devise?)
27
28
  super(options)
@@ -44,7 +44,10 @@ module Dummy
44
44
  config.middleware.insert_before 0, Rack::Cors do
45
45
  allow do
46
46
  origins '*'
47
- resource '*', :headers => :any, :methods => [:get, :post, :put, :delete]
47
+ resource '*',
48
+ headers: :any,
49
+ expose: ['access-token', 'client', 'uid'],
50
+ methods: [:get, :post, :put, :delete]
48
51
  end
49
52
  end
50
53
  end
@@ -1,5 +1,13 @@
1
1
  Dynamoid.configure do |config|
2
- config.namespace = "activity_notification_#{Rails.env}"
3
- config.endpoint = 'http://localhost:8000'
4
- # config.store_datetime_as_string = true
2
+ config.namespace = ENV['AN_NO_DYNAMODB_NAMESPACE'] ? "" : "activity_notification_#{Rails.env}"
3
+ # TODO Update Dynamoid v3.4.0+
4
+ # config.capacity_mode = :on_demand
5
+ config.read_capacity = 5
6
+ config.write_capacity = 5
7
+ unless Rails.env.production?
8
+ config.endpoint = 'http://localhost:8000'
9
+ end
10
+ unless Rails.env.test?
11
+ config.store_datetime_as_string = true
12
+ end
5
13
  end
@@ -79,4 +79,7 @@ Rails.application.configure do
79
79
 
80
80
  # Do not dump schema after migrations.
81
81
  config.active_record.dump_schema_after_migration = false
82
+
83
+ # Allow Action Cable connection from any host
84
+ config.action_cable.disable_request_forgery_protection = true
82
85
  end
@@ -10,10 +10,10 @@ ActivityNotification.configure do |config|
10
10
  config.orm = ENV['AN_ORM'].to_sym
11
11
 
12
12
  # Configure table name to store notification data.
13
- config.notification_table_name = "notifications"
13
+ config.notification_table_name = ENV['AN_NOTIFICATION_TABLE_NAME'] || "notifications"
14
14
 
15
15
  # Configure table name to store subscription data.
16
- config.subscription_table_name = "subscriptions"
16
+ config.subscription_table_name = ENV['AN_SUBSCRIPTION_TABLE_NAME'] || "subscriptions"
17
17
 
18
18
  # Configure if email notification is enabled as default.
19
19
  # Note that you can configure them for each model by acts_as roles.
@@ -64,7 +64,7 @@ ActivityNotification.configure do |config|
64
64
 
65
65
  # Configure if activity_notification stores notificaion records including associated records like target and notifiable..
66
66
  # This store_with_associated_records option can be set true only when you use mongoid or dynamoid ORM.
67
- config.store_with_associated_records = false
67
+ config.store_with_associated_records = (config.orm != :active_record)
68
68
 
69
69
  # Configure if WebSocket subscription using ActionCable is enabled.
70
70
  # Note that you can configure them for each model by acts_as roles.
@@ -29,7 +29,11 @@ Rails.application.routes.draw do
29
29
  notify_to :users, api_mode: true, with_subscription: true
30
30
  notify_to :users, api_mode: true, with_devise: :users, devise_default_routes: true, with_subscription: true
31
31
  resources :apidocs, only: [:index], controller: 'activity_notification/apidocs'
32
- resources :users, only: [:index, :show]
32
+ resources :users, only: [:index, :show] do
33
+ collection do
34
+ get :find
35
+ end
36
+ end
33
37
  end
34
38
  end
35
39
 
@@ -2,8 +2,15 @@
2
2
  # This file is seed file for test data on development environment.
3
3
 
4
4
  def clean_database
5
- [ActivityNotification::Notification, ActivityNotification::Subscription, Comment, Article, Admin, User].each do |model_class|
6
- model_class.delete_all
5
+ models = [Comment, Article, Admin, User]
6
+ if ENV['AN_USE_EXISTING_DYNAMODB_TABLE']
7
+ ActivityNotification::Notification.where('id.not_null': true).delete_all
8
+ ActivityNotification::Subscription.where('id.not_null': true).delete_all
9
+ else
10
+ models.concat([ActivityNotification::Notification, ActivityNotification::Subscription])
11
+ end
12
+ models.each do |model|
13
+ model.delete_all
7
14
  end
8
15
  end
9
16