activity_notification 2.1.3 → 2.1.4

Sign up to get free protection for your applications and to get access to all the features.
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