Remove buffer gem and related code: step 1 (#12993)

* Remove buffer gem and related code

* Remove more Buffer-related code

* Remove one more Buffer spec

* Remove DUS

* Remove more Buffer code
This commit is contained in:
Michael Kohl 2021-03-24 02:58:38 +00:00 committed by GitHub
parent 0beacb19c9
commit 7c31a9cc98
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
54 changed files with 44 additions and 1128 deletions

View file

@ -19,7 +19,6 @@ gem "ahoy_matey", "~> 3.2" # Tracking analytics for Rails
gem "ancestry", "~> 3.2" # Ancestry allows the records of a ActiveRecord model to be organized in a tree structure
gem "blazer", "~> 2.4.2" # Allows admins to query data
gem "bootsnap", ">= 1.1.0", require: false # Boot large ruby/rails apps faster
gem "buffer", "~> 0.1" # Buffer is a Ruby Wrapper for the Buffer API
gem "carrierwave", "~> 2.2" # Upload files in your Ruby applications, map them to a range of ORMs, store them on different backends
gem "carrierwave-bombshelter", "~> 0.2" # Protect your carrierwave from image bombs
gem "cloudinary", "~> 1.19" # Client library for easily using the Cloudinary service

View file

@ -149,15 +149,6 @@ GEM
brpoplpush-redis_script (0.1.2)
concurrent-ruby (~> 1.0, >= 1.0.5)
redis (>= 1.0, <= 5.0)
buffer (0.1.3)
addressable
environs
faraday
faraday_middleware
hashie
multi_json
rake
yajl-ruby
buftok (0.2.0)
builder (3.2.4)
bullet (6.1.4)
@ -262,7 +253,6 @@ GEM
email_validator (2.2.2)
activemodel
emoji_regex (3.2.2)
environs (1.1.0)
equalizer (0.0.11)
errbase (0.2.1)
erubi (1.10.0)
@ -284,8 +274,6 @@ GEM
multipart-post (>= 1.2, < 3)
ruby2_keywords
faraday-net_http (1.0.1)
faraday_middleware (1.0.0)
faraday (~> 1.0)
fastimage (2.2.1)
fastly (3.0.1)
feedjira (3.1.2)
@ -859,7 +847,6 @@ GEM
websocket-extensions (0.1.5)
xpath (3.2.0)
nokogiri (~> 1.8)
yajl-ruby (1.4.1)
yard (0.9.26)
yard-activerecord (0.0.16)
yard (>= 0.8.3)
@ -888,7 +875,6 @@ DEPENDENCIES
blazer (~> 2.4.2)
bootsnap (>= 1.1.0)
brakeman (~> 5.0)
buffer (~> 0.1)
bullet (~> 6.1)
bundler-audit (~> 0.8)
capybara (~> 3.35.3)

View file

@ -211,7 +211,7 @@ label {
// rendered from boostrap. We want to remove these to be
// consistent with links in the crayons design system.
.crayons-link,
.crayons-tabs__item {
.crayons-tabs__item {
text-decoration: none;
&:hover {

View file

@ -7,22 +7,10 @@ module Admin
end
def index
@pending_buffer_updates = BufferUpdate.where(status: "pending").includes(:article)
@user_buffer_updates = BufferUpdate.where(status: "sent_direct", approver_user_id: current_user.id).where(
"created_at > ?", 24.hours.ago
)
case params[:state]
when /not-buffered/
days_ago = params[:state].split("-")[2].to_f
@articles = articles_not_buffered(days_ago)
when /top-/
months_ago = params[:state].split("-")[1].to_i.months.ago
@articles = articles_top(months_ago)
when "satellite"
@articles = articles_satellite
when "satellite-not-buffered"
@articles = articles_satellite.where(last_buffered: nil)
when "boosted-additional-articles"
@articles = articles_boosted_additional
when "chronological"
@ -49,17 +37,6 @@ module Admin
private
def articles_not_buffered(days_ago)
Article.published
.where(last_buffered: nil)
.where("published_at > ? OR crossposted_at > ?", days_ago.days.ago, days_ago.days.ago)
.includes(:user)
.limited_columns_internal_select
.order(public_reactions_count: :desc)
.page(params[:page])
.per(50)
end
def articles_top(months_ago)
Article.published
.where("published_at > ?", months_ago)
@ -70,19 +47,9 @@ module Admin
.per(50)
end
def articles_satellite
Article.published.where(last_buffered: nil)
.includes(:user, :buffer_updates)
.tagged_with(Tag.bufferized_tags, any: true).unscope(:select)
.limited_columns_internal_select
.order(hotness_score: :desc)
.page(params[:page])
.per(60)
end
def articles_boosted_additional
Article.boosted_via_additional_articles
.includes(:user, :buffer_updates)
.includes(:user)
.limited_columns_internal_select
.order(published_at: :desc)
.page(params[:page])
@ -111,7 +78,7 @@ module Admin
Article.published.or(Article.where(published_from_feed: true))
.where(featured: true)
.where("featured_number > ?", Time.current.to_i)
.includes(:user, :buffer_updates)
.includes(:user)
.limited_columns_internal_select
.order(featured_number: :desc)
end
@ -128,7 +95,6 @@ module Admin
featured_number
user_id
co_author_ids_list
last_buffered
published_at]
params.require(:article).permit(allowed_params)
end

View file

@ -1,38 +0,0 @@
module Admin
class BufferUpdatesController < Admin::ApplicationController
def create
article_id = params[:article_id]
article = Article.find(article_id) if article_id.present?
fb_post = params[:fb_post]
tweet = params[:tweet]
listing_id = params[:listing_id]
listing = Listing.find(params[:listing_id]) if listing_id.present?
article&.update(featured: true)
case params[:social_channel]
when "main_twitter"
Bufferizer::MainTweet.call(article, tweet, current_user.id)
render body: nil
when "satellite_twitter"
Bufferizer::SatelliteTweet.call(article, tweet, current_user.id)
render body: nil
when "facebook"
Bufferizer::FacebookPost.call(article, fb_post, current_user.id)
render body: nil
when "listings_twitter"
Bufferizer::ListingsTweet.call(listing, tweet, current_user.id)
render body: nil
end
end
def update
BufferUpdate.upbuff!(params[:id], current_user.id, params[:body_text], params[:status])
render body: nil
end
private
def authorize_admin
authorize BufferUpdate, :access?, policy_class: InternalPolicy
end
end
end

View file

@ -75,7 +75,6 @@ class ArticlesController < ApplicationController
@article = @article.decorate
@user = @article.user
@rating_vote = RatingVote.where(article_id: @article.id, user_id: @user.id).first
@buffer_updates = BufferUpdate.where(composer_user_id: @user.id, article_id: @article.id)
@organizations = @user&.organizations
# TODO: fix this for multi orgs
@org_members = @organization.users.pluck(:name, :id) if @organization

View file

@ -1,63 +0,0 @@
class BufferUpdatesController < ApplicationController
after_action :verify_authorized
def create
@article = Article.find(params[:buffer_update][:article_id])
authorize @article, policy_class: BufferUpdatePolicy
create_main_tweet
create_satellite_tweets
create_facebook_post
redirect_back(fallback_location: "/mod")
end
def create_main_tweet
BufferUpdate.create(
article_id: @article.id,
composer_user_id: current_user.id,
body_text: modified_body_text,
social_service_name: "twitter",
buffer_profile_id_code: ApplicationConfig["BUFFER_TWITTER_ID"],
status: "pending",
)
end
def create_satellite_tweets
tags_names = @article.decorate.cached_tag_list_array
tags_names.each do |name|
tag = Tag.find_by(name: name)
next if tag&.buffer_profile_id_code.blank?
BufferUpdate.create(
article_id: @article.id,
composer_user_id: current_user.id,
body_text: modified_body_text,
social_service_name: "twitter",
buffer_profile_id_code: tag.buffer_profile_id_code,
tag_id: tag.id,
status: "pending",
)
end
end
def create_facebook_post
BufferUpdate.create(
article_id: @article.id,
composer_user_id: current_user.id,
body_text: "#{params[:buffer_update][:body_text]} #{URL.article(@article)}",
social_service_name: "facebook",
buffer_profile_id_code: ApplicationConfig["BUFFER_FACEBOOK_ID"],
status: "pending",
)
end
def modified_body_text
@user = @article.user
[
params[:buffer_update][:body_text],
("\n\n{ author: @#{@user.twitter_username} }" if @user.twitter_username.present?),
(" #{SiteConfig.twitter_hashtag}" if SiteConfig.twitter_hashtag.present?),
"\n#{URL.article(@article)}",
].compact.join
end
end

View file

@ -1,54 +0,0 @@
import { Application } from 'stimulus';
import BufferController from '../../controllers/buffer_controller';
describe('BufferController', () => {
beforeEach(() => {
document.body.innerHTML = `
<div data-controller="buffer"
data-buffer-bg-highlighted-class="bg-highlighted"
data-buffer-border-highlighted-class="border-highlighted">
<h2 data-buffer-target="header"></h2>
<button data-action="buffer#tagBufferUpdateConfirmed"></button>
<button data-action="buffer#tagBufferUpdateDismissed"></button>
<button data-action="buffer#highlightElement"></button>
</div>`;
const application = Application.start();
application.register('buffer', BufferController);
});
describe('#tagBufferUpdateConfirmed', () => {
it('adds a badge to the header', () => {
const button = document.getElementsByTagName('button')[0];
const header = document.getElementsByTagName('h2')[0];
button.click();
expect(header.firstChild.textContent).toMatch(/Confirm/);
});
});
describe('#tagBufferUpdateDismissed', () => {
it('adds a badge to the header', () => {
const button = document.getElementsByTagName('button')[1];
const header = document.getElementsByTagName('h2')[0];
button.click();
expect(header.firstChild.textContent).toMatch(/Dismiss/);
});
});
describe('#highlightElement', () => {
it('adds a class to the controller element', () => {
const button = document.getElementsByTagName('button')[2];
const element = document.querySelector("[data-controller='buffer']");
button.click();
expect(
element.classList.contains('bg-highlighted', 'border-highlighted'),
).toBe(true);
});
});
});

View file

@ -85,16 +85,16 @@ describe('SidebarController', () => {
describe('#disableCurrentNavItem', () => {
it('sets the disabled attribute on the open menu button', () => {
window.dispatchEvent(new Event('load'))
window.dispatchEvent(new Event('load'));
const button = document.getElementById('apps_button');
expect(button.getAttribute("disabled")).toEqual("true");
expect(button.getAttribute('disabled')).toEqual('true');
});
});
describe('#expandDropdown', () => {
beforeEach(() => {
let assignMock = jest.fn();
const assignMock = jest.fn();
delete window.location;
window.location = { href: assignMock };
@ -108,15 +108,14 @@ describe('SidebarController', () => {
const button = document.getElementById('advanced_button');
button.click();
expect(window.location.href).toEqual("/admin/advanced/broadcasts")
expect(window.location.href).toEqual('/admin/advanced/broadcasts');
});
it('closes other menu items', () => {
const button = document.getElementById('advanced_button');
button.click();
expect(document.getElementById('apps').classList).toContain("hide");
expect(document.getElementById('apps').classList).toContain('hide');
});
})
});
});

View file

@ -1,46 +0,0 @@
import { Controller } from 'stimulus';
const CONFIRM_BADGE_HTML =
'<span class="ml-2 badge badge-success">Confirm</span>';
const DISMISS_BADGE_HTML =
'<span class="ml-2 badge badge-danger">Dismiss</span>';
export default class BufferController extends Controller {
static classes = ['bgHighlighted', 'borderHighlighted'];
static targets = ['header', 'bodyText'];
tagBufferUpdateConfirmed() {
this.clearPreviousBadge();
this.headerTarget.innerHTML += CONFIRM_BADGE_HTML;
}
tagBufferUpdateDismissed() {
this.clearPreviousBadge();
this.headerTarget.innerHTML += DISMISS_BADGE_HTML;
}
highlightElement() {
this.element.classList.add(
this.bgHighlightedClass,
this.borderHighlightedClass,
);
setTimeout(() => {
this.element.classList.remove(this.bgHighlightedClass);
}, 350);
}
autosizeBodyText() {
this.bodyTextTarget.rows = this.bodyTextTarget.value.split(
/\r\n|\r|\n/,
).length;
}
clearPreviousBadge() {
const badge = this.headerTarget.getElementsByClassName('badge')[0];
if (badge) {
badge.remove();
}
}
}

View file

@ -2,14 +2,14 @@ import { Controller } from 'stimulus';
// eslint-disable-next-line no-restricted-syntax
export default class SidebarController extends Controller {
static targets = [
'submenu'
];
static targets = ['submenu'];
disableCurrentNavItem() {
const activeMenuId = this.submenuTargets.filter((item) => item.classList.contains("show"))[0].id
const activeMenuId = this.submenuTargets.filter((item) =>
item.classList.contains('show'),
)[0].id;
const activeButton = document.getElementById(`${activeMenuId}_button`);
activeButton.setAttribute("disabled", true)
activeButton.setAttribute('disabled', true);
}
expandDropdown(event) {
@ -26,7 +26,7 @@ export default class SidebarController extends Controller {
const collapsedList = ['collapse', 'hide'];
this.submenuTargets.map((item) => {
if (item.classList.contains("show")) {
if (item.classList.contains('show')) {
item.classList.remove(...expandedList);
item.classList.add(...collapsedList);
}

View file

@ -1,8 +1,12 @@
## Mention autocomplete
The `MentionAutocompleteTextArea` component uses the [Reach UI Combobox](https://reach.tech/combobox/) under the hood. It works by _replacing_ the textarea you pass in props with one enhanced with the `@mention` functionality.
The `MentionAutocompleteTextArea` component uses the
[Reach UI Combobox](https://reach.tech/combobox/) under the hood. It works by
_replacing_ the textarea you pass in props with one enhanced with the `@mention`
functionality.
The autocomplete will begin fetching suggestions once a user has typed `@` plus at least two characters. A user&apos;s selection is confirmed when they either:
The autocomplete will begin fetching suggestions once a user has typed `@` plus
at least two characters. A user&apos;s selection is confirmed when they either:
- Click on a search option
- Hit enter on a search option
@ -11,8 +15,15 @@ The autocomplete will begin fetching suggestions once a user has typed `@` plus
### Mention autocomplete accessibility
The component replaces the given textarea with one generated using [Reach UI Combobox](https://reach.tech/combobox/). The underlying behavior then conforms to the [WAI_ARIA guidelines on comboboxes](https://www.w3.org/TR/wai-aria-practices-1.2/#combobox).
The component replaces the given textarea with one generated using
[Reach UI Combobox](https://reach.tech/combobox/). The underlying behavior then
conforms to the
[WAI_ARIA guidelines on comboboxes](https://www.w3.org/TR/wai-aria-practices-1.2/#combobox).
An `aria-live` region communicates to a screen reader user when the list has been populated with suggestions.
An `aria-live` region communicates to a screen reader user when the list has
been populated with suggestions.
Please note: When using the `MentionAutocompleteTextArea`, you must have either an `aria-labelledby` or `aria-label` attribute on the textarea you pass as a prop. These attributes are copied across to the Reach UI Combobox input, ensuring it is labelled correctly for accessibility.
Please note: When using the `MentionAutocompleteTextArea`, you must have either
an `aria-labelledby` or `aria-label` attribute on the textarea you pass as a
prop. These attributes are copied across to the Reach UI Combobox input,
ensuring it is labelled correctly for accessibility.

View file

@ -17,7 +17,6 @@ module Constants
"Resource Admin: Badge",
"Resource Admin: BadgeAchievement",
"Resource Admin: Broadcast",
"Resource Admin: BufferUpdate",
"Resource Admin: ChatChannel",
"Resource Admin: Comment",
"Resource Admin: Config",

View file

@ -1,4 +1,6 @@
class Article < ApplicationRecord
self.ignored_columns = %w[facebook_last_buffered last_buffered].freeze
include CloudinaryHelper
include ActionView::Helpers
include Storext.model
@ -29,7 +31,6 @@ class Article < ApplicationRecord
counter_culture :user
counter_culture :organization
has_many :buffer_updates, dependent: :destroy
has_many :comments, as: :commentable, inverse_of: :commentable, dependent: :nullify
has_many :html_variant_successes, dependent: :nullify
has_many :html_variant_trials, dependent: :nullify
@ -115,9 +116,8 @@ class Article < ApplicationRecord
# data in the column. However, since `published_at` is a *very* diverse
# column and can scope down the result set significantly, the query planner
# can make heavy use of it.
scope :published, -> {
self
.where(published: true)
scope :published, lambda {
where(published: true)
.where("published_at <= ?", Time.current)
}
scope :unpublished, -> { where(published: false) }
@ -165,8 +165,7 @@ class Article < ApplicationRecord
:video, :user_id, :organization_id, :video_source_url, :video_code,
:video_thumbnail_url, :video_closed_caption_track_url, :social_image,
:published_from_feed, :crossposted_at, :published_at, :featured_number,
:last_buffered, :facebook_last_buffered, :created_at, :body_markdown,
:email_digest_eligible, :processed_html, :co_author_ids)
:created_at, :body_markdown, :email_digest_eligible, :processed_html, :co_author_ids)
}
scope :boosted_via_additional_articles, lambda {

View file

@ -2,6 +2,7 @@ class Listing < ApplicationRecord
# We used to use both "classified listing" and "listing" throughout the app.
# We standardized on the latter, but keeping the table name was easier.
self.table_name = "classified_listings"
self.ignored_columns = ["last_buffered"].freeze
include Searchable

View file

@ -1,6 +1,8 @@
require_relative "../lib/acts_as_taggable_on/tag"
class Tag < ActsAsTaggableOn::Tag
self.ignored_columns = ["buffer_profile_id_code"].freeze
attr_accessor :points, :tag_moderator_id, :remove_moderator_id
acts_as_followable
@ -21,7 +23,6 @@ class Tag < ActsAsTaggableOn::Tag
belongs_to :badge, optional: true
belongs_to :mod_chat_channel, class_name: "ChatChannel", optional: true
has_many :buffer_updates, dependent: :nullify
has_many :articles, through: :taggings, source: :taggable, source_type: "Article"
has_one :sponsorship, as: :sponsorable, inverse_of: :sponsorable, dependent: :destroy
@ -66,12 +67,6 @@ class Tag < ActsAsTaggableOn::Tag
User.with_role(:tag_moderator, self).order(id: :asc).ids
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
def self.valid_categories
ALLOWED_CATEGORIES
end

View file

@ -131,10 +131,6 @@ class User < ApplicationRecord
inverse_of: :blocked, dependent: :delete_all
has_many :blocker_blocks, class_name: "UserBlock", foreign_key: :blocker_id,
inverse_of: :blocker, dependent: :delete_all
has_many :buffer_updates_approved, class_name: "BufferUpdate", foreign_key: :approver_user_id,
inverse_of: :approver_user, dependent: :nullify
has_many :buffer_updates_composed, class_name: "BufferUpdate", foreign_key: :composer_user_id,
inverse_of: :composer_user, dependent: :nullify
has_many :chat_channel_memberships, dependent: :destroy
has_many :chat_channels, through: :chat_channel_memberships
has_many :collections, dependent: :destroy

View file

@ -1,11 +0,0 @@
class BufferUpdatePolicy < ApplicationPolicy
def create?
user_is_trusted? || user_is_author?
end
private
def user_is_author?
record.user_id == user.id
end
end

View file

@ -1,37 +0,0 @@
module Bufferizer
class FacebookPost
def self.call(article, post, admin_id)
return unless article && post && admin_id
BufferUpdate.buff!(
article.id,
fb_buffer_text(post, article),
social_service_name: "facebook",
admin_id: admin_id,
)
BufferUpdate.buff!(
article.id,
fb_buffer_text(post, article) + social_tags(article),
social_service_name: "linkedin",
admin_id: admin_id,
)
article.update(facebook_last_buffered: Time.current)
end
def self.fb_buffer_text(post, article)
"#{post} #{URL.article(article)}"
end
private_class_method :fb_buffer_text
def self.social_tags(article)
# for linkedin's followable tags
tags = article.tag_list.map { |tag| "##{tag}" }.join(" ")
" #programming #softwareengineering #{tags}"
end
private_class_method :social_tags
end
end

View file

@ -1,24 +0,0 @@
module Bufferizer
class ListingsTweet
TWEET_SIZE_LIMIT = 255
def self.call(listing, tweet)
return unless listing && tweet
buffer_listings_id = ApplicationConfig["BUFFER_LISTINGS_PROFILE"]
BufferUpdate.send_to_buffer(
listings_twitter_text(tweet, listing),
buffer_listings_id,
)
listing.update(last_buffered: Time.current)
end
def self.listings_twitter_text(tweet, listing)
"#{tweet} #{URL.url(listing.path)}" if tweet.size <= TWEET_SIZE_LIMIT
end
private_class_method :listings_twitter_text
end
end

View file

@ -1,23 +0,0 @@
module Bufferizer
class MainTweet
TWEET_SIZE_LIMIT = 255
def self.call(article, tweet, admin_id)
return unless article && tweet && admin_id
BufferUpdate.buff!(
article.id,
twitter_buffer_text(tweet, article),
admin_id: admin_id,
)
article.update(last_buffered: Time.current)
end
def self.twitter_buffer_text(tweet, article)
"#{tweet} #{URL.article(article)}" if tweet.size <= TWEET_SIZE_LIMIT
end
private_class_method :twitter_buffer_text
end
end

View file

@ -1,39 +0,0 @@
module Bufferizer
class SatelliteTweet
TWEET_SIZE_LIMIT = 255
TEXT_SIZE_LIMIT = 250
def self.call(article, tweet, admin_id)
return unless article && tweet && admin_id
article.tags.find_each do |tag|
next if tag.buffer_profile_id_code.blank?
text = twitter_buffer_text(tweet, article)
if text.length < TEXT_SIZE_LIMIT && SiteConfig.twitter_hashtag
text = text.gsub(
" #{SiteConfig.twitter_hashtag}",
" #{SiteConfig.twitter_hashtag} ##{tag.name}",
)
end
BufferUpdate.buff!(
article.id,
text,
buffer_profile_id_code: tag.buffer_profile_id_code,
tag_id: tag.id,
admin_id: admin_id,
)
end
article.update(last_buffered: Time.current)
end
def self.twitter_buffer_text(tweet, article)
"#{tweet} #{URL.article(article)}" if tweet.size <= TWEET_SIZE_LIMIT
end
private_class_method :twitter_buffer_text
end
end

View file

@ -8,7 +8,6 @@ module Users
virtual_articles = user.articles.map { |article| Article.new(article.attributes) }
user.articles.find_each do |article|
article.reactions.delete_all
article.buffer_updates.delete_all
article.comments.includes(:user).find_each do |comment|
comment.reactions.delete_all
EdgeCache::BustComment.call(comment.commentable)

View file

@ -126,36 +126,12 @@
<%= f.check_box :boosted_additional_articles, id: "boosted_additional_articles-#{article.id}" %>
<label for="boosted_additional_articles-<%= article.id %>">Boosted</label>
</div>
<% unless article.last_buffered %>
<div class="form-check col">
<%= f.check_box :last_buffered, id: "last_buffered-#{article.id}" %>
<label for="last_buffered-<%= article.id %>">Mark as buffered</label>
</div>
<% end %>
<div class="col">
<button class="btn btn-primary float-right">Submit</button>
</div>
</div>
<% end %>
<% if article.last_buffered %>
<div class="mt-5">
<em>Last Buffered <%= article.last_buffered %></em>
<% article.buffer_updates.order(created_at: :asc).each do |buffer_update| %>
<h5>
<a href="https://buffer.com/app/profile/<%= buffer_update.buffer_profile_id_code %>/buffer/queue/list">
<%= buffer_update.social_service_name %>
<%= " MAIN" if buffer_update.buffer_profile_id_code == ApplicationConfig["BUFFER_TWITTER_ID"] %>
</a>
</h5>
<%= time_ago_in_words(buffer_update.created_at) %> ago
<p class="bg-warning">
<%= buffer_update.body_text %>
</p>
<% end %>
</div>
<% end %>
<% if article.boosted_dev_digest_email %>
<br /><br />
<% phrase = "#{article.path}?booster_org=#{article.organization&.slug || 'generic'}" %>
@ -173,53 +149,5 @@
<%= EmailMessage.where("subject LIKE ?", "%#{phrase}%").where.not(opened_at: nil).where.not(opened_at: nil).where("sent_at > ?", 1.week.ago).size %>
OPENED EMAILS IN THE PAST WEEK</b>
<% end %>
<div class="d-flex justify-content-between" style="padding-top:15px;">
<button class="btn btn-dark btn-lg btn-block" data-toggle="collapse" data-target="#article-<%= article.id %>-buffer-area"
area-expanded="false" area-controls="article-<%= article.id %>-buffer-area">
Social Distribution
</button>
</div>
<div id="article-<%= article.id %>-buffer-area" class="buffering-area-for-single-article collapse" style="padding-top:25px;">
<div class="row">
<div class="article-body-html col col-7" style="background:white;max-height: 800px;padding-top:8px;overflow:auto;border-radius: 3px;">
<%= article.processed_html&.html_safe %>
</div>
<div class="col col-5">
<%= form_with url: admin_buffer_updates_path, html: { data: { action: "submit->article#highlightElement" } } do %>
<input type="hidden" name="social_channel" value="main_twitter" />
<input type="hidden" name="article_id" value="<%= article.id %>" />
<h5>Twitter MAIN</h5>
<div class="form-group">
<textarea rows="5" wrap="hard" name="tweet" maxlength="255" class="form-control"><%= BufferUpdate.twitter_default_text(article) %></textarea>
</div>
<button class="btn btn-primary mb-2">🦅 Tweet to @<%= SiteConfig.social_media_handles["twitter"] %></button>
<% end %>
<% if (article.decorate.cached_tag_list_array & Tag.bufferized_tags).any? %>
<%= form_with url: admin_buffer_updates_path, html: { data: { action: "submit->article#highlightElement" } } do %>
<input type="hidden" name="social_channel" value="satellite_twitter" />
<input type="hidden" name="article_id" value="<%= article.id %>" />
<h5>Twitter Satellite</h5>
<div class="form-group">
<textarea rows="5" wrap="hard" name="tweet" maxlength="255" class="form-control"><%= BufferUpdate.twitter_default_text(article) %></textarea>
</div>
<button class="btn btn-primary mb-2">🐦 Tweet to satellites</button>
<% end %>
<% end %>
<%= form_with url: admin_buffer_updates_path, html: { data: { action: "submit->article#highlightElement" } } do %>
<input type="hidden" name="social_channel" value="facebook" />
<input type="hidden" name="article_id" value="<%= article.id %>" />
<h5>Facebook & LinkedIn</h5>
<div class="form-group">
<textarea rows="5" wrap="hard" name="fb_post" class="form-control" required></textarea>
</div>
<button class="btn btn-primary mb-2">📘 Post to Facebook</button>
<% end %>
</div>
</div>
</div>
</div>
</div>

View file

@ -1,19 +1,3 @@
<% if ENV["BUFFER_ACCESS_TOKEN"].blank? %>
<div class="crayons-notice crayons-notice--info mb-6" role="alert">
<p><strong>All references to "Buffering" are legacy and social media functionality is not currently operational.</strong></p>
<p>Buffer, the social media scheduling tool, has discontinued its API, so send-to-buffer functionality only works for legacy clients.</p>
<p>We will replace this functionality in the future with a functional alternative.</p>
</div>
<% elsif @user_buffer_updates.any? %>
<div class="crayons-notice crayons-notice--success mb-6" role="alert">
You have sent <strong><%= @user_buffer_updates.size %></strong> buffers so far in the past 24 hours. Keep it up!
</div>
<% else %>
<div class="crayons-notice crayons-notice--warning mb-6" role="alert">
You haven't sent any buffers in the past 24 hours, let's get to work!
</div>
<% end %>
<main class="row">
<div class="col-12">
<ul class="nav nav-tabs nav-fill">
@ -30,29 +14,6 @@
href="<%= admin_articles_path(state: :satellite) %>"
class="nav-link <%= "active" if params[:state] == "satellite" %>">Satellite</a>
</li>
<li class="nav-item">
<span class="nav-link disabled">Not Buffered:</span>
</li>
<li class="nav-item">
<a
href="<%= admin_articles_path(state: "not-buffered-0.25") %>"
class="nav-link <%= "active" if params[:state] == "not-buffered-0.25" %>">6hr</a>
</li>
<li class="nav-item">
<a
href="<%= admin_articles_path(state: "not-buffered-1") %>"
class="nav-link <%= "active" if params[:state] == "not-buffered-1" %>">1d</a>
</li>
<li class="nav-item">
<a
href="<%= admin_articles_path(state: "not-buffered-7") %>"
class="nav-link <%= "active" if params[:state] == "not-buffered-7" %>">7d</a>
</li>
<li class="nav-item">
<a
href="<%= admin_articles_path(state: "satellite-not-buffered") %>"
class="nav-link <%= "active" if params[:state] == "satellite-not-buffered" %>">Satellite</a>
</li>
</ul>
<% if params[:state] && params[:state].include?("top-") && params[:state] != "top-3" && params[:state] != "top-6" %>
<h1 style="color:red">
@ -60,73 +21,6 @@
</h1>
<% end %>
</div>
<% if @pending_buffer_updates.any? %>
<div class="col-12 mb-2">
<details>
<summary style="font-size: 1.3em; cursor: pointer;">Suggested Tweets (<%= @pending_buffer_updates.size %>)</summary>
<% @pending_buffer_updates.each do |buffer_update| %>
<% next unless buffer_update.article %>
<div
class="card my-3"
id="suggested-tweet-<%= buffer_update.id %>"
data-controller="buffer"
data-action="load@window->buffer#autosizeBodyText"
data-buffer-bg-highlighted-class="bg-highlighted"
data-buffer-border-highlighted-class="border-highlighted">
<div class="card-header">
<h2 class="my-0" data-buffer-target="header"><%= buffer_update.article.title %></h2>
</div>
<div class="card-body">
<h4>Score: <%= buffer_update.article.score %></h4>
<div class="blockquote">
<%= HTML_Truncator.truncate(
buffer_update.article.processed_html,
50,
ellipsis: "<a class=\"comment-read-more\" href=\"#{buffer_update.article.path}\">... Read Entire Post</a>",
).html_safe %>
</div>
<hr />
<code><b><%= Tag.find_by(id: buffer_update.tag_id)&.name || buffer_update.social_service_name %>:</b></code>
<%= form_with(
url: admin_buffer_update_path(buffer_update.id),
class: "buffer-form buffer-confirm",
html: { data: { action: "submit->buffer#highlightElement" } },
) do |f| %>
<div class="form-group">
<input name="utf8" type="hidden" value="✓">
<input type="hidden" name="authenticity_token" value="<%= form_authenticity_token %>" />
<input type="hidden" name="_method" value="patch" />
<input type="hidden" name="status" value="confirmed" />
<textarea
class="w-100 suggested-tweet-body-text"
name="body_text"
class="form-control"
data-buffer-target="bodyText"><%= buffer_update.body_text %></textarea>
</div>
<button value="confirmed" name="status" class="btn btn-success" data-action="buffer#tagBufferUpdateConfirmed">Confirm</button>
<% end %>
<%= form_with(
url: admin_buffer_update_path(buffer_update.id),
class: "buffer-form buffer-dismiss",
html: { data: { action: "submit->buffer#highlightElement" } },
) do |f| %>
<div class="form-group">
<input name="utf8" type="hidden" value="✓">
<input type="hidden" name="authenticity_token" value="<%= form_authenticity_token %>" />
<input type="hidden" name="_method" value="patch" />
<input type="hidden" name="status" value="dismissed" />
</div>
<button value="dismissed" name="status" class="btn btn-danger" data-action="buffer#tagBufferUpdateDismissed">Dismiss</button>
<% end %>
</div>
</div>
<% end %>
</details>
</div>
<% end %>
<div class="col-12">
<% if @featured_articles.present? %>
<h2>Manually Featured Articles</h2>

View file

@ -58,45 +58,6 @@
<td><%= listing.published ? "Yes" : "No" %></td>
<td><%= listing.bumped_at ? "#{time_ago_in_words(listing.bumped_at)} ago" : "Draft" %></td>
</tr>
<tr>
<td
class="buffer-cell border-0"
colspan="7"
data-controller="buffer"
data-action="load@window->buffer#autosizeBodyText"
data-buffer-bg-highlighted-class="bg-highlighted"
data-buffer-border-highlighted-class="border-highlighted">
<button
class="btn btn-secondary"
data-toggle="collapse"
data-target="#buffering-area-for-listing-<%= listing.id %>"
aria-expanded="false"
aria-controls="buffering-area-for-listing-<%= listing.id %>">
Share to Buffer
</button>
<% if listing.last_buffered.present? %>
<em class="ml-1">
Last shared: <%= listing.last_buffered.strftime("%d %B %Y") %>
</em>
<% end %>
<div id="buffering-area-for-listing-<%= listing.id %>" class="collapse buffer-area mt-3">
<p><strong><%= listing.title %></strong></p>
<p><%= listing.processed_html&.html_safe %></p>
<%= form_with url: admin_buffer_updates_path, html: { data: { action: "submit->buffer#highlightElement" } } do %>
<input type="hidden" name="social_channel" value="listings_twitter" />
<input type="hidden" name="listing_id" value="<%= listing.id %>" />
<textarea class="form-control" wrap="hard" name="tweet" maxlength="255" data-buffer-target="bodyText">
📋 New <%= community_name %> Listing!&#013&#013Category: <%= listing.category %>&#013&#013<%= listing.title %>&#013&#013
<% if listing.user.twitter_username? %>
Posted by @<%= listing.user.twitter_username %>
<% end %>
</textarea>
<button class="btn btn-primary mt-2">🐦 Tweet 🐦</button>
<% end %>
</div>
</td>
</tr>
<% end %>
</tbody>
</table>

View file

@ -5,8 +5,7 @@
<a class="crayons-link crayons-link--block <%= "crayons-link--current" if deduced_controller(request) == group[:children][0][:controller] %>"
href="/admin/<%= group[:children][0][:controller] %>"
aria-page="<%= "page" if deduced_controller(request) == group[:children][0][:controller] %>"
data-action="click->sidebar#expandDropdown"
>
data-action="click->sidebar#expandDropdown">
<%= inline_svg_tag(group[:svg], aria: true, class: "dropdown-icon crayons-icon") %>
<%= display_name(group_name) %>
</a>
@ -19,22 +18,19 @@
data-target-href="/admin/<%= group_name %>/<%= group[:children][0][:controller] %>"
aria-expanded="<%= (deduced_scope(request) == group_name.to_s).to_s %>"
aria-controls="<%= group_name %>"
data-action="click->sidebar#expandDropdown"
>
data-action="click->sidebar#expandDropdown">
<%= inline_svg_tag(group[:svg], aria: true, class: "dropdown-icon crayons-icon") %>
<%= display_name(group_name) %>
</button>
<ul id="<%= group_name %>"
data-sidebar-target="submenu"
class="<%= deduced_scope(request) == group_name.to_s ? "expand show" : "collapse hide" %>"
>
class="<%= deduced_scope(request) == group_name.to_s ? "expand show" : "collapse hide" %>">
<% group[:children].each do |item| %>
<% if item[:visible] %>
<li>
<a class="crayons-link crayons-link--block ml-7 <%= "fw-bold" if deduced_controller(request) == item[:controller].to_s %>"
href="/admin/<%= group_name %>/<%= item[:controller] %>"
aria-page="<%= "page" if deduced_controller(request) == item[:controller].to_s %>"
>
aria-page="<%= "page" if deduced_controller(request) == item[:controller].to_s %>">
<%= item[:name].to_s.titleize %>
</a>
</li>

View file

@ -9,7 +9,7 @@
<li>
<a
href="/admin/<%= deduced_scope(request) %>/<%= item[:controller] %>"
class="crayons-tabs__item <%= "crayons-tabs__item--current" if deduced_controller(request)&.match?(item[:controller]) %>" <>
class="crayons-tabs__item <%= "crayons-tabs__item--current" if deduced_controller(request)&.match?(item[:controller]) %>">
<%= item[:name].to_s.titleize %>
</a>
</li>

View file

@ -30,21 +30,6 @@
<div class="dashboard-container crayons-layout">
<%= render "dashboards/dashboard_article", article: @article, organization: @article.organization, org_admin: @user.org_admin?(@article.organization), manage_view: true %>
<% if @buffer_updates.any? %>
<div class="single-article thanks-for-suggesting-a-tweet">
Tweet Suggestion Sent 🙏
</div>
<% else %>
<div class="single-article single-article-manage-form-wrapper">
<%= form_for(BufferUpdate.new) do |f| %>
<h2>Suggest a Tweet</h2>
<%= f.hidden_field :article_id, value: @article.id %>
<%= f.text_area :body_text, minlength: 10, maxlength: 220 %>
<%= f.submit "Share Tweet Suggestion" %>
<p>Suggestion can be a quote, summary, or bullet points from the post.</p>
<% end %>
</div>
<% end %>
<div class="single-article single-article-manage-form-wrapper">
<%= form_for(RatingVote.new) do |f| %>
<h2>Experience Level of Post</h2>

View file

@ -92,7 +92,6 @@
<% end %>
<% end %>
<%= yield %>
<% if @help_url %>
<a class="admin-help-button crayons-btn crayons-btn--icon-rounded crayons-btn--s" href="<%= @help_url %>" target="_blank" rel="noopener noreferer">

View file

@ -204,15 +204,5 @@
Who <em>might</em> find this post most valuable, based on overall experience level?
</p>
</div>
<% if @moderatable.last_buffered.blank? %>
<div class="tag-mod-form">
<%= form_for(BufferUpdate.new) do |f| %>
<h2>Suggest a Tweet for @<%= SiteConfig.social_media_handles["twitter"] %></h2>
<%= f.hidden_field :article_id, value: @moderatable.id %>
<%= f.text_area :body_text, maxlength: 220, placeholder: "Can be a TLDR of the post, an interesting quote from the post, or bullet points from topics covered in the post, etc." %>
<%= f.submit "Share Tweet Suggestion" %>
<% end %>
</div>
<% end %>
<% end %>
</div>

View file

@ -48,7 +48,6 @@ Rails.application.routes.draw do
remote_token http_origin session_hijacking] } })
mount flipper_ui, at: "feature_flags"
end
resources :buffer_updates, only: %i[create update]
resources :feedback_messages, only: %i[index show]
resources :invitations, only: %i[index new create destroy]
resources :organization_memberships, only: %i[update destroy create]
@ -383,7 +382,6 @@ Rails.application.routes.draw do
resources :credits, only: %i[index new create] do
get "purchase", on: :collection, to: "credits#new"
end
resources :buffer_updates, only: [:create]
resources :reading_list_items, only: [:update]
resources :poll_votes, only: %i[show create]
resources :poll_skips, only: [:create]

View file

@ -1,13 +0,0 @@
module DataUpdateScripts
class RemoveOrphanedBufferUpdatesByArticle
def run
# Delete all BufferUpdates belonging to Articles that don't exist anymore
ActiveRecord::Base.connection.execute(
<<~SQL.squish,
DELETE FROM buffer_updates
WHERE article_id NOT IN (SELECT id FROM articles);
SQL
)
end
end
end

View file

@ -66,7 +66,6 @@ module DataUpdateScripts
# Poll is ignored because it's related to the liquid tag inside the article, also user's can't use polls
# TagAdjustment is ignored as there's likely no reason for article to have an adjustment moved over
models_with_a_direct_relation = [
BufferUpdate,
HtmlVariantSuccess,
HtmlVariantSuccess,
HtmlVariantTrial,

View file

@ -1,15 +0,0 @@
module DataUpdateScripts
class NullifyOrphanRowsFromBufferUpdatesByComposerUserId
def run
# Nullify all BufferUpdates composer_user_id belonging to Users that don't exist anymore
ActiveRecord::Base.connection.execute(
<<~SQL.squish,
UPDATE buffer_updates
SET composer_user_id = NULL
WHERE composer_user_id IS NOT NULL
AND composer_user_id NOT IN (SELECT id FROM users);
SQL
)
end
end
end

View file

@ -1,6 +0,0 @@
FactoryBot.define do
factory :buffer_update do
article
tag
end
end

View file

@ -18,7 +18,6 @@ RSpec.describe Article, type: :model do
it { is_expected.to belong_to(:organization).optional }
it { is_expected.to belong_to(:user) }
it { is_expected.to have_many(:buffer_updates).dependent(:destroy) }
it { is_expected.to have_many(:comments).dependent(:nullify) }
it { is_expected.to have_many(:html_variant_successes).dependent(:nullify) }
it { is_expected.to have_many(:html_variant_trials).dependent(:nullify) }

View file

@ -1,66 +0,0 @@
require "rails_helper"
RSpec.describe BufferUpdate, type: :model do
let(:article) { create(:article) }
let(:tag1) { create(:tag) }
let(:tag2) { create(:tag) }
describe "validations" do
describe "builtin validations" do
subject { described_class.buff!(article.id, "twitter_buffer_text") }
it { is_expected.to belong_to(:approver_user).optional }
it { is_expected.to belong_to(:composer_user).optional }
it { is_expected.to belong_to(:tag).optional }
end
end
it "creates update" do
described_class.buff!(article.id, "twitter_buffer_text")
expect(described_class.all.size).to eq(1)
end
it "does not allow duplicate updates" do
described_class.buff!(article.id, "twitter_buffer_text")
described_class.buff!(article.id, "twitter_buffer_text")
expect(described_class.all.size).to eq(1)
end
it "does not allow duplicate updates if the first one was a little while ago" do
b1 = described_class.buff!(article.id, "twitter_buffer_text")
b1.update_column(:created_at, 5.minutes.ago)
described_class.buff!(article.id, "twitter_buffer_text")
expect(described_class.all.size).to eq(2)
described_class.buff!(article.id, "twitter_buffer_text")
expect(described_class.all.size).to eq(2)
described_class.buff!(article.id, "twitter_buffer_text yoyo")
expect(described_class.all.size).to eq(3)
end
it "allows same text across different social platforms" do
described_class.buff!(article.id, "twitter_buffer_text", social_service_name: "facebook")
described_class.buff!(article.id, "twitter_buffer_text")
expect(described_class.all.size).to eq(2)
end
it "allows same text across different tags" do
described_class.buff!(article.id, "twitter_buffer_text", tag_id: tag1.id)
described_class.buff!(article.id, "twitter_buffer_text", tag_id: tag2.id)
expect(described_class.all.size).to eq(2)
end
it "allows same text across different articles with the same tag" do
described_class.buff!(article.id, "twitter_buffer_text", tag_id: tag1.id)
described_class.buff!(create(:article).id, "twitter_buffer_text", tag_id: tag1.id)
expect(described_class.all.size).to eq(2)
end
it "does not allow more than 3 suggestions" do
Array.new(3) do |i|
described_class.buff!(article.id, "twitter_buffer_text_#{i}")
end
invalid_buffer = described_class.buff!(article.id, "twitter_buffer_text_4")
expect(described_class.all.size).to eq(3)
expect(invalid_buffer.errors.full_messages.first).to include("already has multiple suggestions")
end
end

View file

@ -8,7 +8,6 @@ RSpec.describe Tag, type: :model do
subject { tag }
it { is_expected.to belong_to(:badge).optional }
it { is_expected.to have_many(:buffer_updates).dependent(:nullify) }
it { is_expected.to have_one(:sponsorship).inverse_of(:sponsorable).dependent(:destroy) }
it { is_expected.to validate_length_of(:name).is_at_most(30) }

View file

@ -145,22 +145,6 @@ RSpec.describe User, type: :model do
.dependent(:delete_all)
end
it do
expect(subject).to have_many(:buffer_updates_approved)
.class_name("BufferUpdate")
.with_foreign_key("approver_user_id")
.inverse_of(:approver_user)
.dependent(:nullify)
end
it do
expect(subject).to have_many(:buffer_updates_composed)
.class_name("BufferUpdate")
.with_foreign_key("composer_user_id")
.inverse_of(:composer_user)
.dependent(:nullify)
end
it do
expect(subject).to have_many(:created_podcasts)
.class_name("Podcast")

View file

@ -1,13 +0,0 @@
require "rails_helper"
RSpec.describe BufferUpdatePolicy, type: :policy do
subject { described_class.new(user, article) }
let(:article) { build_stubbed(:article) }
context "when user is trusted" do
let(:user) { build(:user, :trusted) }
it { is_expected.to permit_actions(%i[create]) }
end
end

View file

@ -163,9 +163,6 @@ RSpec.configure do |config|
stub_request(:any, /localhost:9090/)
.to_return(status: 200, body: "OK".to_json, headers: {})
stub_request(:post, /api.bufferapp.com/)
.to_return(status: 200, body: { fake_text: "so fake" }.to_json, headers: {})
# for twitter image cdn
stub_request(:get, /twimg.com/)
.to_return(status: 200, body: "", headers: {})

View file

@ -1,84 +0,0 @@
require "rails_helper"
require "requests/shared_examples/internal_policy_dependant_request"
RSpec.describe "/admin/buffer_updates", type: :request do
let(:user) { create(:user) }
let(:article) { create(:article, user_id: user.id) }
let(:comment) { build_stubbed(:comment, user_id: user.id, commentable: article) }
it_behaves_like "an InternalPolicy dependant request", BufferUpdate do
let(:request) { post "/admin/buffer_updates" }
end
describe "POST /admin/buffer_updates" do
before do
user.add_role(:super_admin)
sign_in user
end
it "creates buffer update for tweet if tweet params are passed" do
post "/admin/buffer_updates",
params:
{ social_channel: "main_twitter", article_id: article.id, tweet: "Hello this is a test" }
expect(BufferUpdate.all.size).to eq(1)
post "/admin/buffer_updates",
params: { social_channel: "main_twitter", article_id: article.id, tweet: "Hello this is a test!" }
expect(BufferUpdate.all.size).to eq(2)
expect(BufferUpdate.last.article_id).to eq(article.id)
end
it "updates last buffered at" do
post "/admin/buffer_updates",
params:
{ social_channel: "main_twitter", article_id: article.id, tweet: "Hello this is a test" }
expect(article.reload.last_buffered).not_to eq(nil)
end
it "marks article as featured" do
post "/admin/buffer_updates",
params:
{ social_channel: "main_twitter", article_id: article.id, tweet: "Hello this is a test" }
expect(article.reload.featured).to be true
end
it "updates last buffered at with satellite buffer" do
post "/admin/buffer_updates",
params:
{ social_channel: "satellite_twitter", article_id: article.id, tweet: "Hello this is a test" }
expect(article.reload.last_buffered).not_to eq(nil)
end
it "updates last facebook buffered at" do
post "/admin/buffer_updates",
params:
{ social_channel: "facebook", article_id: article.id, fb_post: "Hello this is a test" }
expect(article.reload.facebook_last_buffered).not_to eq(nil)
end
end
describe "PUT /admin/buffer_updates" do
let(:tag) { create(:tag) }
let(:buffer_update) do
BufferUpdate.create(article_id: article.id,
composer_user_id: user.id,
body_text: "This is text - #{rand(100)}",
social_service_name: "twitter",
tag_id: tag.id,
status: "pending")
end
before do
sign_in user
user.add_role(:super_admin)
end
it "sends to buffer" do
put "/admin/buffer_updates/#{buffer_update.id}", params: {
status: "confirmed", body_text: "test"
}
expect(buffer_update.reload.buffer_response).not_to eq(nil)
expect(buffer_update.reload.status).to eq("confirmed")
expect(buffer_update.reload.approver_user_id).to eq(user.id)
end
end
end

View file

@ -1,74 +0,0 @@
require "rails_helper"
RSpec.describe "BufferUpdates", type: :request do
let(:user) { create(:user) }
let(:mod_user) { create(:user) }
let(:article) { create(:article, user_id: user.id) }
let(:mod_article) { create(:article, user_id: mod_user.id) }
let(:comment) { create(:comment, user_id: user.id, commentable: article) }
context "when trusted user is logged in" do
before do
sign_in mod_user
mod_user.add_role(:trusted)
end
it "creates buffer update for tweet if tweet params are passed" do
post "/buffer_updates",
params:
{ buffer_update: { body_text: "This is the text!!!!", tag_id: "javascript", article_id: article.id } }
expect(BufferUpdate.all.size).to eq(2)
expect(BufferUpdate.last.body_text).to start_with("This is the text!!!!")
expect(BufferUpdate.last.status).to eq("pending")
end
it "creates buffer update with link" do
post "/buffer_updates",
params:
{ buffer_update: { body_text: "This is the text!!!!", tag_id: "javascript", article_id: article.id } }
expect(BufferUpdate.first.body_text).to include(article.path)
end
it "creates buffer hashtag" do
allow(SiteConfig).to receive(:twitter_hashtag).and_return("#DEVCommunity")
post "/buffer_updates",
params:
{ buffer_update: { body_text: "This is the text!!!!", tag_id: "javascript", article_id: article.id } }
expect(BufferUpdate.first.body_text).to include(SiteConfig.twitter_hashtag.to_s)
end
it "creates satellite and Facebook buffer" do
article.update_column(:cached_tag_list, "ruby, rails, meta")
create(:tag, name: "rails")
tag = create(:tag, buffer_profile_id_code: "placeholder", name: "ruby")
post "/buffer_updates",
params:
{ buffer_update: { body_text: "This is the text!!!!", tag_id: "javascript", article_id: article.id } }
expect(BufferUpdate.all.size).to eq(3)
expect(BufferUpdate.second.tag_id).to eq(tag.id)
expect(BufferUpdate.last.social_service_name).to eq("facebook")
end
end
context "when non-trusted user is logged in" do
before do
sign_in user
mod_user.add_role(:trusted)
end
it "rejects buffer update for non-trusted user" do
expect do
post "/buffer_updates",
params:
{ buffer_update: { body_text: "This is the text!!!!", tag_id: "javascript", article_id: mod_article.id } }
end.to raise_error(Pundit::NotAuthorizedError)
end
it "accepts buffer update from author of article" do
post "/buffer_updates",
params:
{ buffer_update: { body_text: "This is the text!!!!", tag_id: "javascript", article_id: article.id } }
expect(BufferUpdate.first.body_text).to include(article.path)
end
end
end

View file

@ -1,42 +0,0 @@
require "rails_helper"
RSpec.describe Bufferizer::FacebookPost, type: :service do
describe "#call" do
let(:user) { create(:user) }
let(:tag) { create(:tag, buffer_profile_id_code: "test") }
let(:article) { create(:article, user_id: user.id, tags: tag.name) }
context "when article is nil" do
it "doesn't raise an error" do
post = "test post"
expect { described_class.call(nil, post, user.id) }.not_to raise_error
end
end
context "when post is nil" do
it "doesn't raise an error" do
expect { described_class.call(article, nil, user.id) }.not_to raise_error
end
end
context "when admin_id is nil" do
it "doesn't raise an error" do
post = "test post"
expect { described_class.call(article, post, nil) }.not_to raise_error
end
end
it "sends to buffer facebook" do
post = "test facebook post"
described_class.call(article, post, user.id)
expect(article.facebook_last_buffered.utc.to_i).to be > 2.minutes.ago.to_i
end
it "adds linkedin social tags" do
post = "test facebook post"
described_class.call(article, post, user.id)
expect(BufferUpdate.last.body_text).to include(" #programming")
expect(BufferUpdate.last.body_text).to include(" ##{article.tag_list.first}")
end
end
end

View file

@ -1,27 +0,0 @@
require "rails_helper"
RSpec.describe Bufferizer::ListingsTweet, type: :service do
describe "#call" do
let(:user) { create(:user) }
let(:listing) { create(:listing, user_id: user.id) }
context "when listing is nil" do
it "doesn't raise an error" do
tweet = "test tweet"
expect { described_class.call(nil, tweet) }.not_to raise_error
end
end
context "when tweet is nil" do
it "doesn't raise an error" do
expect { described_class.call(listing, nil) }.not_to raise_error
end
end
it "sends to buffer listings" do
text = "test listing"
described_class.call(listing, text)
expect(listing.last_buffered).not_to be(nil)
end
end
end

View file

@ -1,40 +0,0 @@
require "rails_helper"
RSpec.describe Bufferizer::MainTweet, type: :service do
describe "#call" do
let(:user) { create(:user) }
let(:article) { create(:article, user_id: user.id) }
context "when article is nil" do
it "doesn't raise an error" do
tweet = "test tweet"
expect { described_class.call(nil, tweet, user.id) }.not_to raise_error
end
end
context "when tweet is nil" do
it "doesn't raise an error" do
expect { described_class.call(article, nil, user.id) }.not_to raise_error
end
end
context "when admin_id is nil" do
it "doesn't raise an error" do
tweet = "test tweet"
expect { described_class.call(article, tweet, nil) }.not_to raise_error
end
end
it "sends to buffer twitter" do
tweet = "test tweet"
described_class.call(article, tweet, user.id)
expect(article.last_buffered.utc.to_i).to be > 2.minutes.ago.to_i
end
it "includes admin approver" do
tweet = "test tweet"
described_class.call(article, tweet, user.id)
expect(BufferUpdate.last.approver_user_id).to be user.id
end
end
end

View file

@ -1,37 +0,0 @@
require "rails_helper"
RSpec.describe Bufferizer::SatelliteTweet, type: :service do
describe "#call" do
let(:user) { create(:user) }
let(:tag) { create(:tag, buffer_profile_id_code: "test") }
let(:article) { create(:article, user_id: user.id, tags: tag.name) }
context "when article is nil" do
it "doesn't raise an error" do
tweet = "test tweet"
expect { described_class.call(nil, tweet, user.id) }.not_to raise_error
end
end
context "when tweet is nil" do
it "doesn't raise an error" do
expect { described_class.call(article, nil, user.id) }.not_to raise_error
end
end
context "when admin_id is nil" do
it "doesn't raise an error" do
tweet = "test tweet"
expect { described_class.call(article, tweet, nil) }.not_to raise_error
end
end
it "sends to buffer sattelite twitter" do
allow(SiteConfig).to receive(:twitter_hashtag).and_return("#DEVCommunity")
tweet = "test tweet #{SiteConfig.twitter_hashtag}"
described_class.call(article, tweet, user.id)
expect(article.last_buffered.utc.to_i).to be > 2.minutes.ago.to_i
expect(BufferUpdate.last.body_text).to include(" #{SiteConfig.twitter_hashtag} ##{tag.name} http")
end
end
end

View file

@ -36,14 +36,6 @@ RSpec.describe Users::DeleteArticles, type: :service do
expect(Comment.where(commentable_id: article.id, commentable_type: "Article").any?).to be false
end
it "deletes articles' buffer updates" do
BufferUpdate.buff!(article.id, "twitter_buffer_text")
described_class.call(user)
expect(BufferUpdate.where(article_id: article.id).any?).to be false
end
it "busts cache" do
described_class.call(user)
expect(EdgeCache::BustComment).to have_received(:call).with(article).twice

View file

@ -95,8 +95,6 @@ RSpec.describe Users::Delete, type: :service do
affected_feedback_messages
audit_logs
banished_users
buffer_updates_approved
buffer_updates_composed
created_podcasts
offender_feedback_messages
page_views

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.