diff --git a/app/controllers/internal/articles_controller.rb b/app/controllers/internal/articles_controller.rb index be7c6eee4..addc334db 100644 --- a/app/controllers/internal/articles_controller.rb +++ b/app/controllers/internal/articles_controller.rb @@ -101,6 +101,7 @@ class Internal::ArticlesController < Internal::ApplicationController where(featured: true). where("featured_number > ?", Time.now.to_i). includes(:user). + includes(:buffer_updates). limited_columns_internal_select. order("featured_number DESC") end diff --git a/app/controllers/internal/buffer_updates_controller.rb b/app/controllers/internal/buffer_updates_controller.rb index e34d2a071..db4fe3017 100644 --- a/app/controllers/internal/buffer_updates_controller.rb +++ b/app/controllers/internal/buffer_updates_controller.rb @@ -3,8 +3,11 @@ class Internal::BufferUpdatesController < Internal::ApplicationController article = Article.find(params[:article_id]) fb_post = params[:fb_post] tweet = params[:tweet] - if params[:social_channel] == "twitter" - Bufferizer.new(article, tweet).twitter_post! + if params[:social_channel] == "main_twitter" + Bufferizer.new(article, tweet).main_teet! + render body: nil + elsif params[:social_channel] == "satellite_twitter" + Bufferizer.new(article, tweet).satellite_tweet! render body: nil elsif params[:social_channel] == "facebook" Bufferizer.new(article, fb_post).facebook_post! diff --git a/app/dashboards/tag_dashboard.rb b/app/dashboards/tag_dashboard.rb index db383f45a..9ba3c7fce 100644 --- a/app/dashboards/tag_dashboard.rb +++ b/app/dashboards/tag_dashboard.rb @@ -28,6 +28,7 @@ class TagDashboard < Administrate::BaseDashboard alias_for: Field::String, keywords_for_search: Field::String, taggings_count: Field::Number, + buffer_profile_id_code: Field::String, }.freeze # COLLECTION_ATTRIBUTES @@ -87,6 +88,7 @@ class TagDashboard < Administrate::BaseDashboard bg_color_hex text_color_hex keywords_for_search + buffer_profile_id_code ].freeze # Overwrite this method to customize how tags are displayed diff --git a/app/labor/bufferizer.rb b/app/labor/bufferizer.rb index b0a2483fb..1c1d5d7b3 100644 --- a/app/labor/bufferizer.rb +++ b/app/labor/bufferizer.rb @@ -1,50 +1,42 @@ class Bufferizer + attr_accessor :article, :text def initialize(article, text) @article = article @text = text end - def twitter_post! - client = Buffer::Client.new(ApplicationConfig["BUFFER_ACCESS_TOKEN"]) - client.create_update( - body: { - text: - twitter_buffer_text, - profile_ids: [ - ApplicationConfig["BUFFER_TWITTER_ID"], - ], - }, - ) - @article.update(last_buffered: Time.now) + def satellite_tweet! + article.tags.each do |tag| + if tag.buffer_profile_id_code.present? + BufferUpdate.buff!(article.id, twitter_buffer_text, tag.buffer_profile_id_code, "twitter", tag.id) + end + end + article.update(last_buffered: Time.now) + end + + def main_teet! + BufferUpdate.buff!(article.id, twitter_buffer_text, ApplicationConfig["BUFFER_TWITTER_ID"], "twitter", nil) + article.update(last_buffered: Time.now) end def facebook_post! - client = Buffer::Client.new(ApplicationConfig["BUFFER_ACCESS_TOKEN"]) - client.create_update( - body: { - text: - fb_buffer_text, - profile_ids: [ - ApplicationConfig["BUFFER_FACEBOOK_ID"], # We're sending to LinkedIn and FB with this. - ApplicationConfig["BUFFER_LINKEDIN_ID"], # That's why there are two profile IDs - ], - }, - ) - @article.update(facebook_last_buffered: Time.now) + BufferUpdate.buff!(article.id, fb_buffer_text, ApplicationConfig["BUFFER_FACEBOOK_ID"], "facebook") + BufferUpdate.buff!(article.id, fb_buffer_text, ApplicationConfig["BUFFER_LINKEDIN_ID"], "linkedin") + article.update(facebook_last_buffered: Time.now) end private def twitter_buffer_text - twit_name = @article.user.twitter_username - if twit_name.present? && @text.size < 245 - "#{@text}\n{ author: @#{twit_name} }\nhttps://dev.to#{@article.path}" + twit_name = article.user.twitter_username + if twit_name.present? && text.size < 245 + "#{text}\n{ author: @#{twit_name} }\nhttps://dev.to#{article.path}" else - "#{@text} https://dev.to#{@article.path}" + "#{text} https://dev.to#{article.path}" end end def fb_buffer_text - "#{@text} https://dev.to#{@article.path}" + "#{text} https://dev.to#{article.path}" end end diff --git a/app/models/article.rb b/app/models/article.rb index da7953c43..7f05f29b3 100644 --- a/app/models/article.rb +++ b/app/models/article.rb @@ -14,6 +14,7 @@ class Article < ApplicationRecord belongs_to :organization, optional: true belongs_to :collection, optional: true has_many :comments, as: :commentable + has_many :buffer_updates has_many :reactions, as: :reactable, dependent: :destroy has_many :notifications, as: :notifiable diff --git a/app/models/buffer_update.rb b/app/models/buffer_update.rb new file mode 100644 index 000000000..c010f231c --- /dev/null +++ b/app/models/buffer_update.rb @@ -0,0 +1,41 @@ +class BufferUpdate < ApplicationRecord + + belongs_to :article + + validate :validate_body_text_recent_uniqueness + + + def self.buff!(article_id, text, buffer_profile_id_code, social_service_name="twitter", tag_id=nil) + buffer_response = send_to_buffer(text, buffer_profile_id_code) + self.create( + article_id: article_id, + tag_id: tag_id, + body_text: text, + buffer_profile_id_code: buffer_profile_id_code, + social_service_name: social_service_name, + buffer_response: buffer_response, + ) + end + + def self.send_to_buffer(text, buffer_profile_id_code) + client = Buffer::Client.new(ApplicationConfig["BUFFER_ACCESS_TOKEN"]) + client.create_update( + body: { + text: + text, + profile_ids: [ + buffer_profile_id_code, + ], + }, + ) + end + + private + + def validate_body_text_recent_uniqueness + if BufferUpdate.where(body_text: body_text, article_id: article_id, tag_id: tag_id, social_service_name: social_service_name). + where("created_at > ?", 2.minutes.ago).any? + errors.add(:body_text, "\"#{body_text}\" has already been submitted very recently") + end + end +end diff --git a/app/models/tag.rb b/app/models/tag.rb index e22f744e3..edf188a10 100644 --- a/app/models/tag.rb +++ b/app/models/tag.rb @@ -38,6 +38,12 @@ class Tag < ActsAsTaggableOn::Tag User.with_role(:tag_moderator, self).order("id ASC").pluck(:id) end + def self.bufferized_tags + Rails.cache.fetch("bufferized_tags_cache", expires_in: 2.hours) do + where.not(buffer_profile_id_code: nil).pluck(:name) + end + end + private def evaluate_markdown diff --git a/app/views/articles/show.html.erb b/app/views/articles/show.html.erb index 4899b4420..58234cbe5 100644 --- a/app/views/articles/show.html.erb +++ b/app/views/articles/show.html.erb @@ -52,6 +52,7 @@ "> + <% if @article.published %> diff --git a/app/views/internal/articles/_article_script.html.erb b/app/views/internal/articles/_article_script.html.erb new file mode 100644 index 000000000..caf02b24c --- /dev/null +++ b/app/views/internal/articles/_article_script.html.erb @@ -0,0 +1,89 @@ + diff --git a/app/views/internal/articles/_individual_article.html.erb b/app/views/internal/articles/_individual_article.html.erb index 6bced2bc4..eca0df218 100644 --- a/app/views/internal/articles/_individual_article.html.erb +++ b/app/views/internal/articles/_individual_article.html.erb @@ -23,7 +23,7 @@ <% end %> <%= article.title %> EDIT - <% article.tag_list.each do |tag| %> + <% article.decorate.cached_tag_list_array.each do |tag| %> #<%= tag %> <% end %> @<%= article.user&.username %> ❤️ <%= article.positive_reactions_count %> | 💬 <%= article.comments_count %> | ID: <%= article.id %> @@ -51,6 +51,13 @@     +
+ <% article.buffer_updates.order("created_at ASC").each do |buffer_update| %> +
+ <%= buffer_update.social_service_name %> <%= " MAIN" if buffer_update.buffer_profile_id_code == ApplicationConfig["BUFFER_TWITTER_ID"] %> <%= buffer_update.body_text %>
<%= time_ago_in_words(buffer_update.created_at) %> ago +
+ <% end %> +
<% if article.boosted_dev_digest_email %>

@@ -67,27 +74,30 @@ <% unless params[:state]&.include?("classic") %>
+
<%= form_tag "/internal/buffer_updates" do %> - + -

Twitter

+

Twitter MAIN

- <% if article.last_buffered %> - - <% else %> - + + <% end %> + <% if (article.decorate.cached_tag_list_array & Tag.bufferized_tags).any? %> + <%= form_tag "/internal/buffer_updates" do %> + + +

Twitter Satellite

+ + <% end %> <% end %> +
<%= form_tag "/internal/buffer_updates" do %>

Facebook & LinkedIn

- <% if article.facebook_last_buffered %> - - <% else %> - - <% end %> + <% end %>
<% end %> diff --git a/app/views/internal/articles/index.html.erb b/app/views/internal/articles/index.html.erb index fc5c8f6ce..6020e5f49 100644 --- a/app/views/internal/articles/index.html.erb +++ b/app/views/internal/articles/index.html.erb @@ -60,92 +60,4 @@ <%= paginate @articles %> - +<%= render "article_script" %> diff --git a/app/views/internal/articles/show.html.erb b/app/views/internal/articles/show.html.erb index 5e6194021..f649ac60f 100644 --- a/app/views/internal/articles/show.html.erb +++ b/app/views/internal/articles/show.html.erb @@ -1,92 +1,2 @@ <%= render "individual_article", article: @article %> - - - +<%= render "article_script" %> diff --git a/app/views/moderations/mod.html.erb b/app/views/moderations/mod.html.erb index 55aa67919..7ca4c1133 100644 --- a/app/views/moderations/mod.html.erb +++ b/app/views/moderations/mod.html.erb @@ -23,7 +23,7 @@
-

MODERATE: <%= @moderatable.title %>>

+

MODERATE: <%= @moderatable.title %>

-

- All negative reactions are 100% private. -

Use the thumbsdown(👎) to move something "down" for any reason (quality, usefulness, code of conduct grey area). -

The vomit(🤢) is for code of conduct violations (harassment, being an asshole, spam, etc.). -

The DEV team will be notified about vomits and take appropriate action, but leaving a level-headed comment addressing the behavior is welcome if you feel up for it. -

+ + <% if current_user.has_role?(:super_admin) && @moderatable.class.name == "Article" %> +

Admin Functionality!

+ + <%= render "internal/articles/individual_article", article: @moderatable %> + <%= render "internal/articles/article_script" %> + <% else %> +

+ All negative reactions are 100% private. +

Use the thumbsdown(👎) to move something "down" for any reason (quality, usefulness, code of conduct grey area). +

The vomit(🤢) is for code of conduct violations (harassment, being an asshole, spam, etc.). +

The DEV team will be notified about vomits and take appropriate action, but leaving a level-headed comment addressing the behavior is welcome if you feel up for it. +

+ <% end %>