card-mod-follow 0.11.0

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.
@@ -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