diff --git a/app/assets/images/notification-bell-access-only.svg b/app/assets/images/notification-bell-access-only.svg
new file mode 100644
index 000000000..b8fa159e8
--- /dev/null
+++ b/app/assets/images/notification-bell-access-only.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/app/assets/images/notification-bell-everything.svg b/app/assets/images/notification-bell-everything.svg
new file mode 100644
index 000000000..52a5611fb
--- /dev/null
+++ b/app/assets/images/notification-bell-everything.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/app/assets/images/notification-bell-watching.svg b/app/assets/images/notification-bell-watching.svg
new file mode 100644
index 000000000..05827531d
--- /dev/null
+++ b/app/assets/images/notification-bell-watching.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/app/assets/stylesheets/icons.css b/app/assets/stylesheets/icons.css
index 6fab09ef1..a07e8d574 100644
--- a/app/assets/stylesheets/icons.css
+++ b/app/assets/stylesheets/icons.css
@@ -12,6 +12,10 @@
user-select: none;
}
+img.icon {
+ background: none;
+}
+
.icon--activity { --svg: url("activity.svg "); }
.icon--add { --svg: url("add.svg "); }
.icon--alert { --svg: url("alert.svg "); }
@@ -49,6 +53,9 @@
.icon--logout { --svg: url("logout.svg "); }
.icon--menu-dots-horizontal { --svg: url("menu-dots-horizontal.svg "); }
.icon--minus { --svg: url("minus.svg "); }
+.icon--notification-bell-access-only { --svg: url("notification-bell-access-only.svg "); }
+.icon--notification-bell-everything { --svg: url("notification-bell-everything.svg "); }
+.icon--notification-bell-watching { --svg: url("notification-bell-watching.svg "); }
.icon--password { --svg: url("password.svg "); }
.icon--pencil { --svg: url("pencil.svg "); }
.icon--person { --svg: url("person.svg "); }
diff --git a/app/controllers/bubbles/watches_controller.rb b/app/controllers/bubbles/watches_controller.rb
index e5a1873b5..cecd292b5 100644
--- a/app/controllers/bubbles/watches_controller.rb
+++ b/app/controllers/bubbles/watches_controller.rb
@@ -1,10 +1,6 @@
class Bubbles::WatchesController < ApplicationController
include BubbleScoped, BucketScoped
- def show
- @watchers = @bubble.watchers_and_subscribers.sorted_with_user_first(Current.user)
- end
-
def create
set_watching_and_redirect(true)
end
diff --git a/app/controllers/buckets/involvements_controller.rb b/app/controllers/buckets/involvements_controller.rb
new file mode 100644
index 000000000..dbfcbb6d7
--- /dev/null
+++ b/app/controllers/buckets/involvements_controller.rb
@@ -0,0 +1,7 @@
+class Buckets::InvolvementsController < ApplicationController
+ include BucketScoped
+
+ def update
+ @bucket.access_for(Current.user).update!(involvement: params[:involvement])
+ end
+end
diff --git a/app/controllers/buckets/subscriptions_controller.rb b/app/controllers/buckets/subscriptions_controller.rb
deleted file mode 100644
index a5a3b92f7..000000000
--- a/app/controllers/buckets/subscriptions_controller.rb
+++ /dev/null
@@ -1,11 +0,0 @@
-class Buckets::SubscriptionsController < ApplicationController
- include BucketScoped
-
- def update
- if params[:subscribed]
- @bucket.subscribe(Current.user)
- else
- @bucket.unsubscribe(Current.user)
- end
- end
-end
diff --git a/app/helpers/accesses_helper.rb b/app/helpers/accesses_helper.rb
index e1fb3ad0f..58c23e72a 100644
--- a/app/helpers/accesses_helper.rb
+++ b/app/helpers/accesses_helper.rb
@@ -12,4 +12,36 @@ module AccessesHelper
locals: { selected: selected },
cached: ->(user) { [ user, selected ] }
end
+
+ def access_involvement_advance_button(bucket, user)
+ access = bucket.access_for(user)
+
+ turbo_frame_tag dom_id(bucket, :involvement_button) do
+ button_to bucket_involvement_path(bucket), method: :put,
+ aria: { labelledby: dom_id(bucket, :involvement_label) },
+ class: [ "btn", { "btn--reversed": access.involvement == "watching" || access.involvement == "everything" } ],
+ params: { involvement: next_involvement(access.involvement) },
+ title: involvement_access_label(bucket, access.involvement) do
+ icon_tag("notification-bell-#{access.involvement.dasherize}") +
+ tag.span(involvement_access_label(bucket, access.involvement), class: "for-screen-reader", id: dom_id(bucket, :involvement_label))
+ end
+ end
+ end
+
+ private
+ def next_involvement(involvement)
+ order = %w[ everything watching access_only ]
+ order[(order.index(involvement.to_s) + 1) % order.size]
+ end
+
+ def involvement_access_label(bucket, involvement)
+ case involvement
+ when "access_only"
+ "Notifications are off for #{bucket.name}"
+ when "everything"
+ "Notifying me about everything in #{bucket.name}"
+ when "watching"
+ "Notifying me only about @mentions and new items in #{bucket.name}"
+ end
+ end
end
diff --git a/app/helpers/translations_helper.rb b/app/helpers/translations_helper.rb
index 57107b8f5..5f6ae4223 100644
--- a/app/helpers/translations_helper.rb
+++ b/app/helpers/translations_helper.rb
@@ -18,7 +18,7 @@ module TranslationsHelper
def translation_button(translation_key)
tag.div(class: "position-relative", data: { controller: "popover", action: "keydown.esc->popover#close click@document->popover#closeOnClickOutside", popover_orientation_top_class: "popover-orientation-top" }) do
tag.button(type: "button", class: "btn", tabindex: -1, data: { action: "popover#toggle" }) do
- concat image_tag("globe.svg", size: 20, role: "presentation")
+ concat image_tag("globe.svg", class: "icon", role: "presentation")
concat tag.span("Translate", class: "for-screen-reader")
end +
tag.dialog(class: "lanuage-list-menu popover shadow", data: { popover_target: "menu" }) do
diff --git a/app/models/access.rb b/app/models/access.rb
index dbbb11590..1ca40d9e2 100644
--- a/app/models/access.rb
+++ b/app/models/access.rb
@@ -1,4 +1,6 @@
class Access < ApplicationRecord
belongs_to :bucket
belongs_to :user
+
+ enum :involvement, %i[ access_only watching everything ].index_by(&:itself)
end
diff --git a/app/models/bubble/watchable.rb b/app/models/bubble/watchable.rb
index efd2c5cb5..8ad47554d 100644
--- a/app/models/bubble/watchable.rb
+++ b/app/models/bubble/watchable.rb
@@ -9,15 +9,18 @@ module Bubble::Watchable
end
def watched_by?(user)
- watchers_and_subscribers.include?(user)
+ watchers_and_subscribers(include_only_watching: true).include?(user)
end
def set_watching(user, watching)
watches.where(user: user).first_or_create.update!(watching: watching)
end
- def watchers_and_subscribers
- User.where(id: bucket.subscribers.pluck(:id) +
+ def watchers_and_subscribers(include_only_watching: false)
+ involvements = include_only_watching ? [ :watching, :everything ] : :everything
+ subscribers = bucket.users.where(accesses: { involvement: involvements })
+
+ User.where(id: subscribers.pluck(:id) +
watches.watching.pluck(:user_id) - watches.not_watching.pluck(:user_id))
end
diff --git a/app/models/bucket.rb b/app/models/bucket.rb
index 2fcf38e13..20a7f0336 100644
--- a/app/models/bucket.rb
+++ b/app/models/bucket.rb
@@ -1,5 +1,5 @@
class Bucket < ApplicationRecord
- include Accessible, Broadcastable, Filterable, Subscribable
+ include Accessible, Broadcastable, Filterable
belongs_to :account
belongs_to :creator, class_name: "User", default: -> { Current.user }
diff --git a/app/models/bucket/accessible.rb b/app/models/bucket/accessible.rb
index 4b21c117b..3c72e9983 100644
--- a/app/models/bucket/accessible.rb
+++ b/app/models/bucket/accessible.rb
@@ -20,6 +20,7 @@ module Bucket::Accessible
end
has_many :users, through: :accesses
+ has_many :access_only_users, -> { merge(Access.access_only) }, through: :accesses, source: :user
scope :all_access, -> { where(all_access: true) }
@@ -27,6 +28,10 @@ module Bucket::Accessible
after_save_commit :grant_access_to_everyone
end
+ def access_for(user)
+ accesses.find_by(user: user)
+ end
+
private
def grant_access_to_everyone
accesses.grant_to(account.users) if all_access_previously_changed?(to: true)
diff --git a/app/models/concerns/subscribable.rb b/app/models/concerns/subscribable.rb
deleted file mode 100644
index 92cf92d1c..000000000
--- a/app/models/concerns/subscribable.rb
+++ /dev/null
@@ -1,22 +0,0 @@
-module Subscribable
- extend ActiveSupport::Concern
-
- TYPES = %w[ Bucket ]
-
- included do
- has_many :subscriptions, as: :subscribable, dependent: :destroy
- has_many :subscribers, through: :subscriptions, source: :user
- end
-
- def subscribe(user)
- subscriptions.create_or_find_by!(user: user)
- end
-
- def unsubscribe(user)
- subscriptions.find_by(user: user)&.destroy!
- end
-
- def subscribed_by?(user)
- subscriptions.exists?(user: user)
- end
-end
diff --git a/app/models/notifier.rb b/app/models/notifier.rb
index 10b1ba3c2..9c89d6bdf 100644
--- a/app/models/notifier.rb
+++ b/app/models/notifier.rb
@@ -27,7 +27,7 @@ class Notifier
end
def recipients
- bubble.watchers.without(creator)
+ bubble.watchers_and_subscribers.without(creator)
end
def resource
diff --git a/app/models/notifier/assigned.rb b/app/models/notifier/assigned.rb
index 283011b2a..3027ab56c 100644
--- a/app/models/notifier/assigned.rb
+++ b/app/models/notifier/assigned.rb
@@ -1,6 +1,6 @@
class Notifier::Assigned < Notifier
private
def recipients
- event.assignees
+ event.assignees.excluding(bubble.bucket.access_only_users)
end
end
diff --git a/app/models/notifier/published.rb b/app/models/notifier/published.rb
index d43b8c8e3..3aadc3c93 100644
--- a/app/models/notifier/published.rb
+++ b/app/models/notifier/published.rb
@@ -1,6 +1,6 @@
class Notifier::Published < Notifier
private
def recipients
- bubble.watchers_and_subscribers.without(creator)
+ bubble.watchers_and_subscribers(include_only_watching: true).without(creator)
end
end
diff --git a/app/models/subscription.rb b/app/models/subscription.rb
deleted file mode 100644
index 1a6ed8ad7..000000000
--- a/app/models/subscription.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-class Subscription < ApplicationRecord
- belongs_to :user
-
- delegated_type :subscribable, types: Subscribable::TYPES, inverse_of: :subscription
-end
diff --git a/app/models/user.rb b/app/models/user.rb
index 57a8e636c..54dca6b3b 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -9,7 +9,6 @@ class User < ApplicationRecord
has_many :accesses, dependent: :destroy
has_many :buckets, through: :accesses
has_many :accessible_bubbles, through: :buckets, source: :bubbles
- has_many :subscriptions, dependent: :destroy
has_many :filters, foreign_key: :creator_id, inverse_of: :creator, dependent: :destroy
diff --git a/app/views/buckets/involvements/update.html.erb b/app/views/buckets/involvements/update.html.erb
new file mode 100644
index 000000000..76bd04031
--- /dev/null
+++ b/app/views/buckets/involvements/update.html.erb
@@ -0,0 +1 @@
+<%= access_involvement_advance_button(@bucket, Current.user) %>
diff --git a/app/views/notifications/settings/_bucket.html.erb b/app/views/notifications/settings/_bucket.html.erb
index a03384467..16839b0c3 100644
--- a/app/views/notifications/settings/_bucket.html.erb
+++ b/app/views/notifications/settings/_bucket.html.erb
@@ -1,18 +1,13 @@
-<%= turbo_frame_tag dom_id(bucket, :subscription) do %>
- <%= form_with url: bucket_subscriptions_path(bucket), method: :put, data: { controller: "form"} do |form| %>
-
-
- <%= bucket.name %>
-
+<%= turbo_frame_tag dom_id(bucket, :involvement) do %>
+
+
+ <%= bucket.name %>
+
-
+
-
-
- <% end %>
+
+
<% end %>
diff --git a/config/routes.rb b/config/routes.rb
index 0ea331e8f..fd1ede5fa 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -36,6 +36,7 @@ Rails.application.routes.draw do
scope module: :buckets do
resource :subscriptions
resource :workflow, only: :update
+ resource :involvement
end
resources :bubbles do
diff --git a/db/migrate/20250319092704_add_involvement_to_accesses.rb b/db/migrate/20250319092704_add_involvement_to_accesses.rb
new file mode 100644
index 000000000..73c70a3a9
--- /dev/null
+++ b/db/migrate/20250319092704_add_involvement_to_accesses.rb
@@ -0,0 +1,7 @@
+class AddInvolvementToAccesses < ActiveRecord::Migration[8.1]
+ def change
+ change_table :accesses do |t|
+ t.string :involvement, null: false, default: "watching"
+ end
+ end
+end
diff --git a/db/migrate/20250319161627_drop_subscriptions.rb b/db/migrate/20250319161627_drop_subscriptions.rb
new file mode 100644
index 000000000..9734075c8
--- /dev/null
+++ b/db/migrate/20250319161627_drop_subscriptions.rb
@@ -0,0 +1,14 @@
+class DropSubscriptions < ActiveRecord::Migration[8.1]
+ def change
+ execute "
+ update accesses set involvement = 'access_only'
+ "
+ execute "
+ update accesses set involvement = 'watching'
+ from (select user_id, subscribable_id as bucket_id from subscriptions) as subscriptions
+ where subscriptions.user_id = accesses.user_id and subscriptions.bucket_id = accesses.bucket_id
+ "
+
+ drop_table :subscriptions
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index ce242daad..68ace61c5 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -14,6 +14,7 @@ ActiveRecord::Schema[8.1].define(version: 2025_04_03_094604) do
create_table "accesses", force: :cascade do |t|
t.integer "bucket_id", null: false
t.datetime "created_at", null: false
+ t.string "involvement", default: "watching", null: false
t.datetime "updated_at", null: false
t.integer "user_id", null: false
t.index ["bucket_id", "user_id"], name: "index_accesses_on_bucket_id_and_user_id", unique: true
@@ -229,6 +230,7 @@ ActiveRecord::Schema[8.1].define(version: 2025_04_03_094604) do
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "user_id", null: false
+ t.index ["bubble_id", "user_id"], name: "index_pins_on_bubble_id_and_user_id", unique: true
t.index ["bubble_id"], name: "index_pins_on_bubble_id"
t.index ["user_id"], name: "index_pins_on_user_id"
end
@@ -261,17 +263,6 @@ ActiveRecord::Schema[8.1].define(version: 2025_04_03_094604) do
t.index ["user_id"], name: "index_sessions_on_user_id"
end
- create_table "subscriptions", force: :cascade do |t|
- t.datetime "created_at", null: false
- t.integer "subscribable_id", null: false
- t.string "subscribable_type", null: false
- t.datetime "updated_at", null: false
- t.integer "user_id", null: false
- t.index ["subscribable_type", "subscribable_id", "user_id"], name: "idx_on_subscribable_type_subscribable_id_user_id_81936d569b", unique: true
- t.index ["subscribable_type", "subscribable_id"], name: "index_subscriptions_on_subscribable"
- t.index ["user_id"], name: "index_subscriptions_on_user_id"
- end
-
create_table "taggings", force: :cascade do |t|
t.integer "bubble_id", null: false
t.datetime "created_at", null: false
@@ -344,7 +335,6 @@ ActiveRecord::Schema[8.1].define(version: 2025_04_03_094604) do
add_foreign_key "pops", "bubbles"
add_foreign_key "pops", "users"
add_foreign_key "sessions", "users"
- add_foreign_key "subscriptions", "users"
add_foreign_key "taggings", "bubbles"
add_foreign_key "taggings", "tags"
add_foreign_key "users", "accounts"
diff --git a/db/schema_cache.yml b/db/schema_cache.yml
index c19033c8d..7e5d9cea3 100644
--- a/db/schema_cache.yml
+++ b/db/schema_cache.yml
@@ -70,12 +70,9 @@ columns:
default_function:
collation:
comment:
- accounts:
- - *5
- - *6
- !ruby/object:ActiveRecord::ConnectionAdapters::SQLite3::Column
auto_increment:
- name: join_code
+ name: involvement
cast_type: &7 !ruby/object:ActiveModel::Type::String
true: t
false: f
@@ -88,6 +85,19 @@ columns:
limit:
precision:
scale:
+ 'null': false
+ default: watching
+ default_function:
+ collation:
+ comment:
+ accounts:
+ - *5
+ - *6
+ - !ruby/object:ActiveRecord::ConnectionAdapters::SQLite3::Column
+ auto_increment:
+ name: join_code
+ cast_type: *7
+ sql_type_metadata: *8
'null': true
default:
default_function:
@@ -833,31 +843,6 @@ columns:
collation:
comment:
- *30
- subscriptions:
- - *5
- - *6
- - !ruby/object:ActiveRecord::ConnectionAdapters::SQLite3::Column
- auto_increment:
- name: subscribable_id
- cast_type: *1
- sql_type_metadata: *2
- 'null': false
- default:
- default_function:
- collation:
- comment:
- - !ruby/object:ActiveRecord::ConnectionAdapters::SQLite3::Column
- auto_increment:
- name: subscribable_type
- cast_type: *7
- sql_type_metadata: *8
- 'null': false
- default:
- default_function:
- collation:
- comment:
- - *9
- - *30
taggings:
- *5
- *25
@@ -982,7 +967,6 @@ primary_keys:
reactions: id
schema_migrations: version
sessions: id
- subscriptions: id
taggings: id
tags: id
users: id
@@ -1018,7 +1002,6 @@ data_sources:
reactions: true
schema_migrations: true
sessions: true
- subscriptions: true
taggings: true
tags: true
users: true
@@ -1801,6 +1784,23 @@ indexes:
nulls_not_distinct:
comment:
valid: true
+ - !ruby/object:ActiveRecord::ConnectionAdapters::IndexDefinition
+ table: pins
+ name: index_pins_on_bubble_id_and_user_id
+ unique: true
+ columns:
+ - bubble_id
+ - user_id
+ lengths: {}
+ orders: {}
+ opclasses: {}
+ where:
+ type:
+ using:
+ include:
+ nulls_not_distinct:
+ comment:
+ valid: true
pops:
- !ruby/object:ActiveRecord::ConnectionAdapters::IndexDefinition
table: pops
@@ -1885,58 +1885,6 @@ indexes:
nulls_not_distinct:
comment:
valid: true
- subscriptions:
- - !ruby/object:ActiveRecord::ConnectionAdapters::IndexDefinition
- table: subscriptions
- name: index_subscriptions_on_user_id
- unique: false
- columns:
- - user_id
- lengths: {}
- orders: {}
- opclasses: {}
- where:
- type:
- using:
- include:
- nulls_not_distinct:
- comment:
- valid: true
- - !ruby/object:ActiveRecord::ConnectionAdapters::IndexDefinition
- table: subscriptions
- name: index_subscriptions_on_subscribable
- unique: false
- columns:
- - subscribable_type
- - subscribable_id
- lengths: {}
- orders: {}
- opclasses: {}
- where:
- type:
- using:
- include:
- nulls_not_distinct:
- comment:
- valid: true
- - !ruby/object:ActiveRecord::ConnectionAdapters::IndexDefinition
- table: subscriptions
- name: idx_on_subscribable_type_subscribable_id_user_id_81936d569b
- unique: true
- columns:
- - subscribable_type
- - subscribable_id
- - user_id
- lengths: {}
- orders: {}
- opclasses: {}
- where:
- type:
- using:
- include:
- nulls_not_distinct:
- comment:
- valid: true
taggings:
- !ruby/object:ActiveRecord::ConnectionAdapters::IndexDefinition
table: taggings
diff --git a/test/controllers/buckets/involvements_controller_test.rb b/test/controllers/buckets/involvements_controller_test.rb
new file mode 100644
index 000000000..014b98f1e
--- /dev/null
+++ b/test/controllers/buckets/involvements_controller_test.rb
@@ -0,0 +1,18 @@
+require "test_helper"
+
+class Buckets::InvolvementsControllerTest < ActionDispatch::IntegrationTest
+ setup do
+ sign_in_as :kevin
+ end
+
+ test "update" do
+ bucket = buckets(:writebook)
+ bucket.access_for(users(:kevin)).access_only!
+
+ assert_changes -> { bucket.access_for(users(:kevin)).involvement }, from: "access_only", to: "watching" do
+ put bucket_involvement_url(bucket, involvement: "watching")
+ end
+
+ assert_response :success
+ end
+end
diff --git a/test/controllers/buckets/subscriptions_controller_test.rb b/test/controllers/buckets/subscriptions_controller_test.rb
deleted file mode 100644
index ccd019145..000000000
--- a/test/controllers/buckets/subscriptions_controller_test.rb
+++ /dev/null
@@ -1,25 +0,0 @@
-require "test_helper"
-
-class Buckets::SubscriptionsControllerTest < ActionDispatch::IntegrationTest
- setup do
- sign_in_as :david
- end
-
- test "subscribing to a bucket" do
- assert_changes -> { buckets(:writebook).subscribed_by?(users(:david)) }, from: false, to: true do
- put bucket_subscriptions_url(buckets(:writebook)), params: { subscribed: "1" }
- end
-
- assert_response :success
- end
-
- test "unsubscribing from a bucket" do
- buckets(:writebook).subscribe(users(:david))
-
- assert_changes -> { buckets(:writebook).subscribed_by?(users(:david)) }, from: true, to: false do
- put bucket_subscriptions_url(buckets(:writebook))
- end
-
- assert_response :success
- end
-end
diff --git a/test/fixtures/subscriptions.yml b/test/fixtures/subscriptions.yml
deleted file mode 100644
index 6ca23ecf3..000000000
--- a/test/fixtures/subscriptions.yml
+++ /dev/null
@@ -1,7 +0,0 @@
-writebook_kevin:
- subscribable: writebook (Bucket)
- user: kevin
-
-writebook_jz:
- subscribable: writebook (Bucket)
- user: jz
diff --git a/test/models/bubble/commentable_test.rb b/test/models/bubble/commentable_test.rb
index 43100006e..dc5f6903b 100644
--- a/test/models/bubble/commentable_test.rb
+++ b/test/models/bubble/commentable_test.rb
@@ -2,7 +2,7 @@ require "test_helper"
class Bubble::CommentableTest < ActiveSupport::TestCase
test "creating a comment on a bubble makes the creator watch the bubble" do
- buckets(:writebook).subscriptions.destroy_all
+ buckets(:writebook).access_for(users(:kevin)).access_only!
assert_not bubbles(:text).watched_by?(users(:kevin))
with_current_user(:kevin) do
diff --git a/test/models/bubble/watchable_test.rb b/test/models/bubble/watchable_test.rb
index 2f9c4a0f0..267bbf2d8 100644
--- a/test/models/bubble/watchable_test.rb
+++ b/test/models/bubble/watchable_test.rb
@@ -3,7 +3,7 @@ require "test_helper"
class Bubble::WatchableTest < ActiveSupport::TestCase
setup do
Watch.destroy_all
- Subscription.destroy_all
+ Access.all.update!(involvement: :access_only)
end
test "watched_by?" do
@@ -16,9 +16,8 @@ class Bubble::WatchableTest < ActiveSupport::TestCase
assert_not bubbles(:logo).watched_by?(users(:kevin))
end
- test "watched_by? when subscribed to the bucket" do
- buckets(:writebook).subscribe(users(:kevin))
-
+ test "watched_by? when notifications are set on the bucket" do
+ buckets(:writebook).access_for(users(:kevin)).watching!
assert bubbles(:text).watched_by?(users(:kevin))
bubbles(:logo).set_watching(users(:kevin), false)
@@ -26,16 +25,14 @@ class Bubble::WatchableTest < ActiveSupport::TestCase
end
test "bubbles are initially watched by their creator" do
- buckets(:writebook).unsubscribe(users(:kevin))
-
bubble = buckets(:writebook).bubbles.create!(creator: users(:kevin))
assert bubble.watched_by?(users(:kevin))
end
test "watchers_and_subscribers" do
- buckets(:writebook).subscribe(users(:kevin))
- buckets(:writebook).subscribe(users(:jz))
+ buckets(:writebook).access_for(users(:kevin)).watching!
+ buckets(:writebook).access_for(users(:jz)).everything!
bubbles(:logo).set_watching(users(:kevin), true)
bubbles(:logo).set_watching(users(:jz), false)
diff --git a/test/models/notifier_test.rb b/test/models/notifier_test.rb
index df6faa127..49050b20a 100644
--- a/test/models/notifier_test.rb
+++ b/test/models/notifier_test.rb
@@ -28,6 +28,14 @@ class NotifierTest < ActiveSupport::TestCase
assert_equal [ users(:kevin) ], notifications.map(&:user)
end
+ test "does not create a notification for access-only users" do
+ buckets(:writebook).access_for(users(:kevin)).access_only!
+
+ notifications = Notifier.for(events(:layout_commented)).generate
+
+ assert_equal [ users(:kevin) ], notifications.map(&:user)
+ end
+
test "the published event creates notifications for subscribers as well as watchers" do
notifications = Notifier.for(events(:logo_published)).generate
@@ -40,9 +48,20 @@ class NotifierTest < ActiveSupport::TestCase
assert_equal bubbles(:logo), Notification.last.resource
end
- test "for assignment events only create a notification for the assignee" do
+ test "assignment events only create a notification for the assignee" do
+ buckets(:writebook).access_for(users(:jz)).watching!
+ buckets(:writebook).access_for(users(:kevin)).everything!
+
notifications = Notifier.for(events(:logo_assignment_jz)).generate
assert_equal [ users(:jz) ], notifications.map(&:user)
end
+
+ test "assignment events do not notify users who are access-only for the collection" do
+ buckets(:writebook).access_for(users(:jz)).access_only!
+
+ notifications = Notifier.for(events(:logo_assignment_jz)).generate
+
+ assert_empty notifications
+ end
end