card-mod-follow 0.11.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,118 @@
1
+ # The Right::Follow set configures follow preferences (`[Set]+[User]+:follow`)
2
+ # While the user follow dashboard ([User]+:follow`) is also in this Set, its
3
+ # customizations are handled in TypePlusRight::User::Follow
4
+
5
+ event :cache_expired_for_new_preference, :integrate, when: :is_preference? do
6
+ Card.follow_caches_expired
7
+ end
8
+
9
+ def option_cards
10
+ Card::FollowOption.cards.compact
11
+ end
12
+
13
+ def options_rule_card
14
+ Card.new(
15
+ name: "follow_options_card",
16
+ type_code: :pointer,
17
+ content: option_cards.map { |oc| "[[#{oc.name}]]" }.join("\n")
18
+ )
19
+ end
20
+
21
+ def add_follow_item? condition
22
+ new_card? || !include_item?(condition)
23
+ end
24
+
25
+ def ok_to_update
26
+ permit :update
27
+ end
28
+
29
+ def ok_to_create
30
+ permit :create
31
+ end
32
+
33
+ def ok_to_delete
34
+ permit :delete
35
+ end
36
+
37
+ def permit action, verb=nil
38
+ if %i[create delete update].include?(action) && allowed_to_change_follow_status?
39
+ true
40
+ else
41
+ super action, verb
42
+ end
43
+ end
44
+
45
+ def allowed_to_change_follow_status?
46
+ Auth.signed_in? &&
47
+ ((user = rule_user) && Auth.current_id == user.id) || Auth.always_ok?
48
+ end
49
+
50
+ format :html do
51
+ # shows a follow item link for each of the current follow options
52
+ view :follow_status, cache: :never do
53
+ wrap { haml :follow_status }
54
+ end
55
+
56
+ # interface to view/alter a specific rule option
57
+ view :follow_item, cache: :never do
58
+ follow_item Env.params[:condition]
59
+ end
60
+
61
+ def follow_item condition, button=true
62
+ condition ||= "*always"
63
+ wrap do
64
+ card_form action: :update, success: { view: :follow_item } do
65
+ [
66
+ follow_item_hidden_tags(condition),
67
+ (follow_item_button(condition) if button),
68
+ follow_item_link(condition)
69
+ ].compact
70
+ end
71
+ end
72
+ end
73
+
74
+ def rule_form_args
75
+ super.merge "data-update-foreign-slot": ".card-slot.follow_section-view"
76
+ end
77
+
78
+ private
79
+
80
+ def follow_item_hidden_tags condition
81
+ condkey = card.add_follow_item?(condition) ? :add_item : :drop_item
82
+ hidden_tags condition: condition, condkey => condition
83
+ end
84
+
85
+ def follow_item_button condition
86
+ action = card.add_follow_item?(condition) ? :add : :delete
87
+ button_tag type: :submit, "aria-label": "Left Align",
88
+ class: "btn-sm btn-item #{follow_item_button_class action}" do
89
+ follow_item_icon action
90
+ end
91
+ end
92
+
93
+ def follow_item_button_class action
94
+ action == :add ? "btn-item-add" : "btn-item-delete btn-primary"
95
+ end
96
+
97
+ def follow_item_icon action
98
+ icon_tag(action == :add ? :add : :check)
99
+ end
100
+
101
+ def follow_item_link condition
102
+ link_to_card follow_item_link_target, follow_item_link_text(condition)
103
+ end
104
+
105
+ def follow_item_link_target
106
+ set = card.rule_set
107
+ setname = set.name
108
+ set.tag.codename == :self ? setname.left : setname.field("by name")
109
+ end
110
+
111
+ def follow_item_link_text condition
112
+ if (option_card = Card.fetch condition)
113
+ option_card.description card.rule_set
114
+ else
115
+ card.rule_set.follow_label
116
+ end
117
+ end
118
+ end
@@ -0,0 +1,9 @@
1
+ %h4
2
+ Get notified about changes
3
+ %ul.delete-list.list-group
4
+ - card.item_names.each do |option|
5
+ %li.list-group-item
6
+ = follow_item(option == "*never" ? "*always" : option)
7
+ = link_to_view :rule_form, "more options",
8
+ class: "btn update-follow-link slotter",
9
+ "data-card_key": card.set_prototype.key
@@ -0,0 +1,3 @@
1
+ event :follow_fields_changed, :integrate do
2
+ Card.follow_caches_expired
3
+ end
@@ -0,0 +1,23 @@
1
+ # -*- encoding : utf-8 -*-
2
+
3
+ # X+*followers provides a list of all users following X.
4
+
5
+ include_set Abstract::Pointer
6
+
7
+ format :html do
8
+ view :core, cache: :never do
9
+ super()
10
+ end
11
+ end
12
+
13
+ def content
14
+ left ? item_names.to_pointer_content : ""
15
+ end
16
+
17
+ def item_names _args={}
18
+ left ? left.follow_set_card.prototype.follower_names : []
19
+ end
20
+
21
+ def virtual?
22
+ new?
23
+ end
@@ -0,0 +1,50 @@
1
+ def virtual?
2
+ new?
3
+ end
4
+
5
+ format :html do
6
+ view :core do
7
+ if card.left && Auth.signed_in?
8
+ render_rule_editor
9
+ else
10
+ nest Card.fetch(card.name.left, :followers), view: :titled, items: { view: :link }
11
+ end
12
+ end
13
+
14
+ view :status do
15
+ if (rcard = current_follow_rule_card)
16
+ rcard.item_cards.map do |item|
17
+ %(<div class="alert alert-success" role="alert">
18
+ <strong>#{rcard.rule_set.follow_label}</strong>: #{item.title}
19
+ </div>)
20
+ end.join
21
+ else
22
+ "No following preference"
23
+ end
24
+ end
25
+
26
+ view :one_line_content do
27
+ ""
28
+ end
29
+
30
+ view :rule_editor, cache: :never do
31
+ rule_context = Card.fetch preference_name, new: { type_id: PointerID }
32
+ wrap_with :div, class: "edit-rule" do
33
+ follow_context = current_follow_rule_card || rule_context
34
+ subformat(follow_context).rule_form :open, rule_context, :modal
35
+ end
36
+ end
37
+
38
+ def preference_name
39
+ set_name = card.left.follow_set_card.name
40
+ Card::Name[set_name, Auth.current.name, :follow]
41
+ end
42
+
43
+ def edit_rule_success
44
+ { view: "status", id: card.name.url_key }
45
+ end
46
+
47
+ def current_follow_rule_card
48
+ card.left.preference :follow
49
+ end
50
+ end
@@ -0,0 +1,13 @@
1
+ include_set Abstract::FollowOption
2
+
3
+ follow_opts position: 2
4
+
5
+ follow_test { |_follower_id, _accounted_ids| true }
6
+
7
+ def title
8
+ "Following"
9
+ end
10
+
11
+ def label
12
+ "follow"
13
+ end
@@ -0,0 +1,19 @@
1
+ include_set Abstract::FollowOption
2
+
3
+ restrictive_follow_opts position: 1
4
+
5
+ follower_candidate_ids do |card|
6
+ [card.creator_id]
7
+ end
8
+
9
+ def title
10
+ "Following content you created"
11
+ end
12
+
13
+ def label
14
+ "follow if I created"
15
+ end
16
+
17
+ def description set_card
18
+ "#{set_card.follow_label} I created"
19
+ end
@@ -0,0 +1,20 @@
1
+ include_set Abstract::FollowOption
2
+
3
+ restrictive_follow_opts position: 2
4
+
5
+ follower_candidate_ids do |card|
6
+ # FIXME? - could optimize by not using cards table...
7
+ card.id ? Card.search(editor_of: card.id, return: :id) : []
8
+ end
9
+
10
+ def title
11
+ "Following content you edited"
12
+ end
13
+
14
+ def label
15
+ "follow if I edited"
16
+ end
17
+
18
+ def description set_card
19
+ "#{set_card.follow_label} I edited"
20
+ end
@@ -0,0 +1 @@
1
+ setting_opts group: :other, position: 7, rule_type_editable: false, preference: true
@@ -0,0 +1,88 @@
1
+ # DEPRECATED
2
+ #
3
+ # Despite its name (*follow defaults)card does not influence defaults for *follow rules.
4
+ # What it does is provide a mechanism (with interface) for updating all users so that
5
+ # they follow the items that are its content.
6
+ #
7
+ # PLAN:
8
+ # - actual defaults should be handled as much as possible with something like
9
+ # the *defaults rule
10
+ # - on the *admin page, we can have a link so sharks can update all the pristine cards
11
+ # to use whatever the actual defaults representation is (see previous point)
12
+ # - if you truly want to override existing follow rules, that may be monkey territory?
13
+ # - we will delete "*follow defaults" after the above are completed
14
+
15
+ event :update_follow_rules, :finalize, on: :save, when: :update_all_users do
16
+ Auth.as_bot do
17
+ Card.search(type: "user").each do |user|
18
+ follow_defaults.each do |set_card, option|
19
+ follow_rule = Card.fetch(set_card.follow_rule_name(user.name), new: {})
20
+ next unless follow_rule
21
+
22
+ follow_rule.drop_item "*never"
23
+ follow_rule.drop_item "*always"
24
+ follow_rule.add_item option
25
+ follow_rule.save!
26
+ end
27
+ end
28
+ end
29
+ Card.follow_caches_expired
30
+ end
31
+
32
+ def follow_defaults
33
+ item_names.map do |item|
34
+ if (set_card = Card.fetch item.to_name.left)&.type_code == :set
35
+ [set_card, follow_option(item)]
36
+ end
37
+ end.compact
38
+ end
39
+
40
+ def follow_option item
41
+ option_card =
42
+ Card.fetch(item.to_name.right) || Card[item.to_name.right.to_sym]
43
+ option_card.follow_option? ? option_card.name : "*always"
44
+ end
45
+
46
+ format :html do
47
+ view :edit, perms: :update, unknown: true do
48
+ frame_and_form :update, hidden: { success: "_self",
49
+ card: { update_all_users: false } } do
50
+ [
51
+ _render_content_formgroups,
52
+ _render_confirm_update_all,
53
+ _render_edit_buttons
54
+ ]
55
+ end
56
+ end
57
+
58
+ view :edit_buttons do
59
+ button_formgroup do
60
+ [submit_and_update_button, simple_submit_button, cancel_to_edit_button]
61
+ end
62
+ end
63
+
64
+ def submit_and_update_button
65
+ submit_button text: "Submit and update all users",
66
+ disable_with: "Updating", class: "follow-updater"
67
+ end
68
+
69
+ def simple_submit_button
70
+ button_tag "Submit", class: "follow"
71
+ end
72
+
73
+ def cancel_to_edit_button
74
+ cancel_button href: path(view: :edit, id: card.id)
75
+ end
76
+
77
+ view :confirm_update_all do
78
+ wrap do
79
+ alert "info" do
80
+ %(
81
+ <h1>Are you sure you want to change the default follow rules?</h1>
82
+ <p>You may choose to update all existing users.
83
+ This may take a while. </p>
84
+ )
85
+ end
86
+ end
87
+ end
88
+ end
@@ -0,0 +1 @@
1
+ setting_opts group: :other, position: 5, rule_type_editable: false
@@ -0,0 +1,13 @@
1
+ include_set Abstract::FollowOption
2
+
3
+ follow_opts position: 3
4
+
5
+ follow_test { |_follower_id, _accounted_ids| false }
6
+
7
+ def title
8
+ "Ignoring"
9
+ end
10
+
11
+ def label
12
+ "ignore"
13
+ end
@@ -0,0 +1,21 @@
1
+ def follow_label
2
+ follow_set_card.follow_label
3
+ end
4
+
5
+ def followed_by? user_id=nil
6
+ follow_set_card.all_members_followed_by? user_id
7
+ end
8
+
9
+ def follow_set_card
10
+ Card.fetch name, :type
11
+ end
12
+
13
+ def list_direct_followers?
14
+ true
15
+ end
16
+
17
+ format :html do
18
+ def related_by_type_items
19
+ super.unshift ["#{card.name} cards", [card, :type, :by_name], mark: :absolute]
20
+ end
21
+ end
@@ -0,0 +1,33 @@
1
+ card_reader :contextual_class
2
+ card_reader :disappear
3
+ card_reader :message
4
+
5
+ def deliver context
6
+ success.flash alert_message(context)
7
+ end
8
+
9
+ def alert_message context
10
+ mcard = message.present? ? message_card : self
11
+ format(:html).alert_message context, mcard
12
+ end
13
+
14
+ format :html do
15
+ def alert_message context, message_card
16
+ mformat = subformat message_card
17
+ alert card.alert_class, true, card.disappear? do
18
+ mformat.contextual_content context, view: alert_view(mformat)
19
+ end
20
+ end
21
+
22
+ def alert_view format
23
+ format.respond_to?(:notify) ? format.notify : :core
24
+ end
25
+ end
26
+
27
+ def disappear?
28
+ disappear.present? ? disappear_card.checked? : true
29
+ end
30
+
31
+ def alert_class
32
+ contextual_class.present? ? contextual_class_card.item_name : :success
33
+ end
@@ -0,0 +1,53 @@
1
+ event :cache_expired_for_new_set, :store, on: :create do
2
+ Card.follow_caches_expired
3
+ end
4
+
5
+ def list_direct_followers?
6
+ true
7
+ end
8
+
9
+ def follow_label
10
+ if (klass = subclass_for_set)
11
+ klass.short_label name.left_name
12
+ else
13
+ ""
14
+ end
15
+ end
16
+
17
+ def follow_rule_name user=nil
18
+ Card::Name[[name, user, :follow].compact]
19
+ end
20
+
21
+ def followed_by? user_id=nil
22
+ all_members_followed_by? user_id
23
+ end
24
+
25
+ def follow_set_card
26
+ self
27
+ end
28
+
29
+ def all_members_followed?
30
+ all_members_followed_by? Auth.current_id
31
+ end
32
+
33
+ def all_members_followed_by? user_id=nil
34
+ return false unless prototype.followed_by?(user_id)
35
+
36
+ directly_followed_by?(user_id) || broader_set_followed_by?(user_id)
37
+ end
38
+
39
+ def broader_set_followed_by? user_id
40
+ broader_sets.find do |set_name|
41
+ Card.fetch(set_name)&.directly_followed_by? user_id
42
+ end
43
+ end
44
+
45
+ def directly_followed?
46
+ directly_followed_by? Auth.current_id
47
+ end
48
+
49
+ def directly_followed_by? user_id=nil
50
+ return true if user_id && follow_rule?(user_id)
51
+
52
+ follow_rule?
53
+ end