Add functionality for buffering to different accounts (#752)
* Create initial buffer updates logic * Add UI functionality and test for sattelite tweets * Add additional /mod functionality and re-use script partial in /internal
This commit is contained in:
parent
90c6731184
commit
2517bb555b
19 changed files with 337 additions and 232 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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!
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
41
app/models/buffer_update.rb
Normal file
41
app/models/buffer_update.rb
Normal file
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -52,6 +52,7 @@
|
|||
<meta name="twitter:title" content="<%=@article.title %>">
|
||||
<meta name="twitter:description" content="<%=@article.description || "An article from the community" %>">
|
||||
<meta name="twitter:card" content="summary_large_image">
|
||||
<meta name="twitter:widgets:new-embed-design" content="on">
|
||||
<% if @article.published %>
|
||||
<meta property="og:image" content="<%= cloud_social_image(@article) %>" />
|
||||
<meta name="twitter:image:src" content="<%= cloud_social_image(@article) %>">
|
||||
|
|
|
|||
89
app/views/internal/articles/_article_script.html.erb
Normal file
89
app/views/internal/articles/_article_script.html.erb
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
<script>
|
||||
function timeNow(objectID){
|
||||
var seconds = new Date().getTime() / 1000;
|
||||
document.getElementById("featured_number_"+objectID).value = Math.round(seconds);
|
||||
}
|
||||
function sink(objectID){
|
||||
var seconds = new Date().getTime() / 1080;
|
||||
document.getElementById("featured_number_"+objectID).value = Math.round(seconds);
|
||||
}
|
||||
|
||||
$('.row').on("submit", "form", function() {
|
||||
var form = $(this);
|
||||
var valuesToSubmit = $(this).serialize();
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: $(this).attr('action'), //sumbits it to the given url of the form
|
||||
data: valuesToSubmit,
|
||||
// dataType: "JSON" // you want a difference between normal and ajax-calls, and json is standard
|
||||
}).success(function(json){
|
||||
console.log("success")
|
||||
form.parents(".row").addClass("highlighted-bg")
|
||||
form.parents(".row").addClass("highlighted-border")
|
||||
setTimeout(function(){
|
||||
form.parents(".row").removeClass("highlighted-bg")
|
||||
},350)
|
||||
});
|
||||
return false; // prevents normal behaviour
|
||||
});
|
||||
|
||||
document.getElementById('image-upload-button').onclick = function (e) {
|
||||
e.preventDefault();
|
||||
document.getElementById('image-upload').click();
|
||||
}
|
||||
|
||||
document.getElementById('image-upload').onchange = function (e) {
|
||||
var image = document.getElementById('image-upload').files;
|
||||
if (image.length > 0) {
|
||||
document.getElementById('image-upload-file-label').style = 'color:#888888';
|
||||
document.getElementById('image-upload-file-label').innerHTML = "Uploading...";
|
||||
document.getElementById('uploaded-image').style = 'display:none';
|
||||
document.getElementById('image-upload-submit').value = "uploading";
|
||||
setTimeout(function(){
|
||||
document.getElementById('image-upload-submit').click(function(){
|
||||
});
|
||||
},50)
|
||||
}
|
||||
}
|
||||
|
||||
document.getElementById('image-upload-submit').onclick = function (e) {
|
||||
e.preventDefault();
|
||||
var image = document.getElementById('image-upload').files;
|
||||
if (image.length > 0) {
|
||||
var ajaxReq = createAjaxReq();
|
||||
ajaxReq.onreadystatechange = uploadImageCb.bind(this, ajaxReq);
|
||||
ajaxReq.open('POST', '/image_uploads', true);
|
||||
ajaxReq.send(generateUploadFormdata(image));
|
||||
}
|
||||
}
|
||||
|
||||
function generateUploadFormdata(image) {
|
||||
var token = document.getElementsByName('authenticity_token')[0].value;
|
||||
var formData = new FormData();
|
||||
formData.append('authenticity_token', token);
|
||||
formData.append('image', image[0]);
|
||||
return formData;
|
||||
}
|
||||
|
||||
function uploadImageCb(ajaxReq) {
|
||||
if (ajaxReq.status === 200 && ajaxReq.readyState === XMLHttpRequest.DONE) {
|
||||
var address = document.getElementById('uploaded-image');
|
||||
address.value = JSON.parse(ajaxReq.response).link;
|
||||
address.style.display = "inline-block";
|
||||
address.style.width = "90%";
|
||||
address.select();
|
||||
var uploadedMessage = '';
|
||||
document.getElementById('image-upload-file-label').innerHTML = uploadedMessage;
|
||||
document.getElementById('image-upload-file-label').style.color = '#00c673';
|
||||
document.getElementById('image-upload-submit').style.display = 'none';
|
||||
}
|
||||
}
|
||||
|
||||
function createAjaxReq() {
|
||||
if (window.XMLHttpRequest) {
|
||||
return new XMLHttpRequest();
|
||||
} else {
|
||||
return new ActiveXObject("Microsoft.XMLHTTP");
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
@ -23,7 +23,7 @@
|
|||
</div>
|
||||
<% end %>
|
||||
<b><a href="<%= article.path %>" target="_blank"><%= article.title %></a></b> <a href="<%= article.path %>/edit" target="_blank" style="background:#00da8b;color:white;padding:1px 6px">EDIT</a>
|
||||
<% article.tag_list.each do |tag| %>
|
||||
<% article.decorate.cached_tag_list_array.each do |tag| %>
|
||||
<a href='/t/<%= tag %>'>#<%= tag %></a>
|
||||
<% end %>
|
||||
<a href="<%= article.user&.path %>">@<%= article.user&.username %></a> ❤️ <%= article.positive_reactions_count %> | 💬 <%= article.comments_count %> | ID: <a href="/internal/articles/<%= article.id %>"><%= article.id %></a>
|
||||
|
|
@ -51,6 +51,13 @@
|
|||
|
||||
    <button class="btn btn-primary">SUBMIT</button>
|
||||
</form>
|
||||
<div>
|
||||
<% article.buffer_updates.order("created_at ASC").each do |buffer_update| %>
|
||||
<div class="row bg-warning">
|
||||
<b><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> </b> <%= buffer_update.body_text %> <br/><em style="font-size:0.8em"><%= time_ago_in_words(buffer_update.created_at) %> ago</em>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<% if article.boosted_dev_digest_email %>
|
||||
<br/><br/>
|
||||
|
|
@ -67,27 +74,30 @@
|
|||
|
||||
<% unless params[:state]&.include?("classic") %>
|
||||
<div class="inner-row" style="padding:10px;margin-top:20px;font-weight:800;">
|
||||
<div>
|
||||
<%= form_tag "/internal/buffer_updates" do %>
|
||||
<input type="hidden" name="social_channel" value="twitter" />
|
||||
<input type="hidden" name="social_channel" value="main_twitter" />
|
||||
<input type="hidden" name="article_id" value="<%= article.id %>" />
|
||||
<p> Twitter </p>
|
||||
<p> Twitter MAIN</p>
|
||||
<textarea cols="37" rows="6" wrap="hard" name="tweet" maxlength="242" /><%= article.title %></textarea>
|
||||
<% if article.last_buffered %>
|
||||
<button class="btn btn-danger" style="font-size:1em;">🙈 TWEETED <%= time_ago_in_words(article.last_buffered) %> ago</button>
|
||||
<% else %>
|
||||
<button class="btn btn-info" style="font-size:1em;">😎 TWEET 🚀🚀🚀🚀🚀🚀</button>
|
||||
<button class="btn btn-info" style="font-size:1em;">🦅 Tweet to @ThePracticalDev</button>
|
||||
<% end %>
|
||||
<% if (article.decorate.cached_tag_list_array & Tag.bufferized_tags).any? %>
|
||||
<%= form_tag "/internal/buffer_updates" do %>
|
||||
<input type="hidden" name="social_channel" value="satellite_twitter" />
|
||||
<input type="hidden" name="article_id" value="<%= article.id %>" />
|
||||
<p> Twitter Satellite</p>
|
||||
<textarea cols="37" rows="6" wrap="hard" name="tweet" maxlength="242" /><%= article.title %></textarea>
|
||||
<button class="btn btn-info" style="font-size:1em;">🐦 Tweet to satellites</button>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</div>
|
||||
<%= form_tag "/internal/buffer_updates" do %>
|
||||
<input type="hidden" name="social_channel" value="facebook" />
|
||||
<input type="hidden" name="article_id" value="<%= article.id %>" />
|
||||
<p> Facebook & LinkedIn </p>
|
||||
<textarea cols="37" rows="6" wrap="hard" name="fb_post" required/></textarea>
|
||||
<% if article.facebook_last_buffered %>
|
||||
<button class="btn btn-danger" style="font-size:1em;">🙈 POSTED <%= time_ago_in_words(article.facebook_last_buffered) %> ago</button>
|
||||
<% else %>
|
||||
<button class="btn btn-info" style="font-size:1em;">😎 POST 🚀🚀🚀🚀🚀🚀</button>
|
||||
<% end %>
|
||||
<button class="btn btn-info" style="font-size:1em;">📘 Post to Facebook</button>
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
|
|
|||
|
|
@ -60,92 +60,4 @@
|
|||
<%= paginate @articles %>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function timeNow(objectID){
|
||||
var seconds = new Date().getTime() / 1000;
|
||||
document.getElementById("featured_number_"+objectID).value = Math.round(seconds);
|
||||
}
|
||||
function sink(objectID){
|
||||
var seconds = new Date().getTime() / 1080;
|
||||
document.getElementById("featured_number_"+objectID).value = Math.round(seconds);
|
||||
}
|
||||
|
||||
$('.row').on("submit", "form", function() {
|
||||
var form = $(this);
|
||||
var valuesToSubmit = $(this).serialize();
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: $(this).attr('action'), //sumbits it to the given url of the form
|
||||
data: valuesToSubmit,
|
||||
// dataType: "JSON" // you want a difference between normal and ajax-calls, and json is standard
|
||||
}).success(function(json){
|
||||
console.log("success")
|
||||
form.parents(".row").addClass("highlighted-bg")
|
||||
form.parents(".row").addClass("highlighted-border")
|
||||
setTimeout(function(){
|
||||
form.parents(".row").removeClass("highlighted-bg")
|
||||
},350)
|
||||
});
|
||||
return false; // prevents normal behaviour
|
||||
});
|
||||
|
||||
document.getElementById('image-upload-button').onclick = function (e) {
|
||||
e.preventDefault();
|
||||
document.getElementById('image-upload').click();
|
||||
}
|
||||
|
||||
document.getElementById('image-upload').onchange = function (e) {
|
||||
var image = document.getElementById('image-upload').files;
|
||||
if (image.length > 0) {
|
||||
document.getElementById('image-upload-file-label').style = 'color:#888888';
|
||||
document.getElementById('image-upload-file-label').innerHTML = "Uploading...";
|
||||
document.getElementById('uploaded-image').style = 'display:none';
|
||||
document.getElementById('image-upload-submit').value = "uploading";
|
||||
setTimeout(function(){
|
||||
document.getElementById('image-upload-submit').click(function(){
|
||||
});
|
||||
},50)
|
||||
}
|
||||
}
|
||||
|
||||
document.getElementById('image-upload-submit').onclick = function (e) {
|
||||
e.preventDefault();
|
||||
var image = document.getElementById('image-upload').files;
|
||||
if (image.length > 0) {
|
||||
var ajaxReq = createAjaxReq();
|
||||
ajaxReq.onreadystatechange = uploadImageCb.bind(this, ajaxReq);
|
||||
ajaxReq.open('POST', '/image_uploads', true);
|
||||
ajaxReq.send(generateUploadFormdata(image));
|
||||
}
|
||||
}
|
||||
|
||||
function generateUploadFormdata(image) {
|
||||
var token = document.getElementsByName('authenticity_token')[0].value;
|
||||
var formData = new FormData();
|
||||
formData.append('authenticity_token', token);
|
||||
formData.append('image', image[0]);
|
||||
return formData;
|
||||
}
|
||||
|
||||
function uploadImageCb(ajaxReq) {
|
||||
if (ajaxReq.status === 200 && ajaxReq.readyState === XMLHttpRequest.DONE) {
|
||||
var address = document.getElementById('uploaded-image');
|
||||
address.value = JSON.parse(ajaxReq.response).link;
|
||||
address.style.display = "inline-block";
|
||||
address.style.width = "90%";
|
||||
address.select();
|
||||
var uploadedMessage = '';
|
||||
document.getElementById('image-upload-file-label').innerHTML = uploadedMessage;
|
||||
document.getElementById('image-upload-file-label').style.color = '#00c673';
|
||||
document.getElementById('image-upload-submit').style.display = 'none';
|
||||
}
|
||||
}
|
||||
|
||||
function createAjaxReq() {
|
||||
if (window.XMLHttpRequest) {
|
||||
return new XMLHttpRequest();
|
||||
} else {
|
||||
return new ActiveXObject("Microsoft.XMLHTTP");
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<%= render "article_script" %>
|
||||
|
|
|
|||
|
|
@ -1,92 +1,2 @@
|
|||
<%= render "individual_article", article: @article %>
|
||||
|
||||
|
||||
<script>
|
||||
function timeNow(objectID){
|
||||
var seconds = new Date().getTime() / 1000;
|
||||
document.getElementById("featured_number_"+objectID).value = Math.round(seconds);
|
||||
}
|
||||
function sink(objectID){
|
||||
var seconds = new Date().getTime() / 1080;
|
||||
document.getElementById("featured_number_"+objectID).value = Math.round(seconds);
|
||||
}
|
||||
|
||||
$('.row').on("submit", "form", function() {
|
||||
var form = $(this);
|
||||
var valuesToSubmit = $(this).serialize();
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: $(this).attr('action'), //sumbits it to the given url of the form
|
||||
data: valuesToSubmit,
|
||||
// dataType: "JSON" // you want a difference between normal and ajax-calls, and json is standard
|
||||
}).success(function(json){
|
||||
console.log("success")
|
||||
form.parents(".row").addClass("highlighted-bg")
|
||||
form.parents(".row").addClass("highlighted-border")
|
||||
setTimeout(function(){
|
||||
form.parents(".row").removeClass("highlighted-bg")
|
||||
},350)
|
||||
});
|
||||
return false; // prevents normal behaviour
|
||||
});
|
||||
|
||||
document.getElementById('image-upload-button').onclick = function (e) {
|
||||
e.preventDefault();
|
||||
document.getElementById('image-upload').click();
|
||||
}
|
||||
|
||||
document.getElementById('image-upload').onchange = function (e) {
|
||||
var image = document.getElementById('image-upload').files;
|
||||
if (image.length > 0) {
|
||||
document.getElementById('image-upload-file-label').style = 'color:#888888';
|
||||
document.getElementById('image-upload-file-label').innerHTML = "Uploading...";
|
||||
document.getElementById('uploaded-image').style = 'display:none';
|
||||
document.getElementById('image-upload-submit').value = "uploading";
|
||||
setTimeout(function(){
|
||||
document.getElementById('image-upload-submit').click(function(){
|
||||
});
|
||||
},50)
|
||||
}
|
||||
}
|
||||
|
||||
document.getElementById('image-upload-submit').onclick = function (e) {
|
||||
e.preventDefault();
|
||||
var image = document.getElementById('image-upload').files;
|
||||
if (image.length > 0) {
|
||||
var ajaxReq = createAjaxReq();
|
||||
ajaxReq.onreadystatechange = uploadImageCb.bind(this, ajaxReq);
|
||||
ajaxReq.open('POST', '/image_uploads', true);
|
||||
ajaxReq.send(generateUploadFormdata(image));
|
||||
}
|
||||
}
|
||||
|
||||
function generateUploadFormdata(image) {
|
||||
var token = document.getElementsByName('authenticity_token')[0].value;
|
||||
var formData = new FormData();
|
||||
formData.append('authenticity_token', token);
|
||||
formData.append('image', image[0]);
|
||||
return formData;
|
||||
}
|
||||
|
||||
function uploadImageCb(ajaxReq) {
|
||||
if (ajaxReq.status === 200 && ajaxReq.readyState === XMLHttpRequest.DONE) {
|
||||
var address = document.getElementById('uploaded-image');
|
||||
address.value = JSON.parse(ajaxReq.response).link;
|
||||
address.style.display = "inline-block";
|
||||
address.style.width = "90%";
|
||||
address.select();
|
||||
var uploadedMessage = '';
|
||||
document.getElementById('image-upload-file-label').innerHTML = uploadedMessage;
|
||||
document.getElementById('image-upload-file-label').style.color = '#00c673';
|
||||
document.getElementById('image-upload-submit').style.display = 'none';
|
||||
}
|
||||
}
|
||||
|
||||
function createAjaxReq() {
|
||||
if (window.XMLHttpRequest) {
|
||||
return new XMLHttpRequest();
|
||||
} else {
|
||||
return new ActiveXObject("Microsoft.XMLHTTP");
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<%= render "article_script" %>
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@
|
|||
</style>
|
||||
|
||||
<div class="container" style="text-align: center">
|
||||
<h2>MODERATE: <a href="<%= @moderatable.path %>" rel="nofollow"><%= @moderatable.title %>></a></h2>
|
||||
<h2>MODERATE: <a href="<%= @moderatable.path %>" rel="nofollow"><%= @moderatable.title %></a></h2>
|
||||
|
||||
<button class="reaction-button <%= Reaction.cached_any_reactions_for?(@moderatable, current_user, "thumbsdown") ? "reacted" : "" %>" data-reactable-id="<%= @moderatable.id %>" data-category="thumbsdown" data-reactable-type="<%= @moderatable.class.name %>">
|
||||
<%= image_tag "emoji/emoji-one-thumbs-down-gray.png" %>
|
||||
|
|
@ -33,12 +33,23 @@
|
|||
<%= image_tag "emoji/emoji-one-nausea-face-gray.png" %>
|
||||
<img class="reacted-emoji" src="<%= asset_path("emoji/emoji-one-nausea-face.png") %>"/>
|
||||
</button>
|
||||
<p style="width: 90%;margin:50px auto;text-align:left">
|
||||
<b style="font-size:1.3em">All negative reactions are 100% private.</b>
|
||||
<br><br>Use the <b>thumbsdown(👎)</b> to move something "down" for any reason (quality, usefulness, code of conduct grey area).
|
||||
<br><br>The <b>vomit(🤢)</b> is for code of conduct violations (harassment, being an asshole, spam, etc.).
|
||||
<br><br>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.
|
||||
</p>
|
||||
|
||||
<% if current_user.has_role?(:super_admin) && @moderatable.class.name == "Article" %>
|
||||
<h1> Admin Functionality!</h1>
|
||||
<script
|
||||
src="https://code.jquery.com/jquery-2.2.4.min.js"
|
||||
integrity="sha256-BbhdlvQf/xTY9gja0Dq3HiwQF8LaCRTXxZKRutelT44="
|
||||
crossorigin="anonymous"></script>
|
||||
<%= render "internal/articles/individual_article", article: @moderatable %>
|
||||
<%= render "internal/articles/article_script" %>
|
||||
<% else %>
|
||||
<p style="width: 90%;margin:50px auto;text-align:left">
|
||||
<b style="font-size:1.3em">All negative reactions are 100% private.</b>
|
||||
<br><br>Use the <b>thumbsdown(👎)</b> to move something "down" for any reason (quality, usefulness, code of conduct grey area).
|
||||
<br><br>The <b>vomit(🤢)</b> is for code of conduct violations (harassment, being an asshole, spam, etc.).
|
||||
<br><br>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.
|
||||
</p>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<script defer>
|
||||
|
|
|
|||
14
db/migrate/20180924201325_create_buffer_updates.rb
Normal file
14
db/migrate/20180924201325_create_buffer_updates.rb
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
class CreateBufferUpdates < ActiveRecord::Migration[5.1]
|
||||
def change
|
||||
create_table :buffer_updates do |t|
|
||||
t.integer :article_id, null: false
|
||||
t.integer :tag_id
|
||||
t.text :body_text
|
||||
t.string :buffer_profile_id_code
|
||||
t.string :buffer_id_code
|
||||
t.string :social_service_name
|
||||
t.text :buffer_response, default: {}.to_yaml
|
||||
t.timestamps
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
class AddBufferProfileIdCodeToTags < ActiveRecord::Migration[5.1]
|
||||
def change
|
||||
add_column :tags, :buffer_profile_id_code, :string
|
||||
end
|
||||
end
|
||||
19
db/schema.rb
19
db/schema.rb
|
|
@ -10,7 +10,7 @@
|
|||
#
|
||||
# It's strongly recommended that you check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema.define(version: 20180826174411) do
|
||||
ActiveRecord::Schema.define(version: 20180924204406) do
|
||||
# These are extensions that must be enabled in order to support this database
|
||||
enable_extension "plpgsql"
|
||||
|
||||
|
|
@ -163,6 +163,18 @@ ActiveRecord::Schema.define(version: 20180826174411) do
|
|||
t.string "type_of"
|
||||
end
|
||||
|
||||
create_table "buffer_updates", force: :cascade do |t|
|
||||
t.integer "article_id", null: false
|
||||
t.text "body_text"
|
||||
t.string "buffer_id_code"
|
||||
t.string "buffer_profile_id_code"
|
||||
t.text "buffer_response", default: "--- {}\n"
|
||||
t.datetime "created_at", null: false
|
||||
t.string "social_service_name"
|
||||
t.integer "tag_id"
|
||||
t.datetime "updated_at", null: false
|
||||
end
|
||||
|
||||
create_table "chat_channel_memberships", force: :cascade do |t|
|
||||
t.bigint "chat_channel_id", null: false
|
||||
t.datetime "created_at", null: false
|
||||
|
|
@ -388,6 +400,10 @@ ActiveRecord::Schema.define(version: 20180826174411) do
|
|||
create_table "messages", force: :cascade do |t|
|
||||
t.bigint "chat_channel_id", null: false
|
||||
t.datetime "created_at", null: false
|
||||
t.text "encrypted_message_html"
|
||||
t.text "encrypted_message_html_iv"
|
||||
t.text "encrypted_message_markdown"
|
||||
t.text "encrypted_message_markdown_iv"
|
||||
t.string "message_html", null: false
|
||||
t.string "message_markdown", null: false
|
||||
t.datetime "updated_at", null: false
|
||||
|
|
@ -567,6 +583,7 @@ ActiveRecord::Schema.define(version: 20180826174411) do
|
|||
create_table "tags", id: :serial, force: :cascade do |t|
|
||||
t.string "alias_for"
|
||||
t.string "bg_color_hex"
|
||||
t.string "buffer_profile_id_code"
|
||||
t.integer "hotness_score", default: 0
|
||||
t.string "keywords_for_search"
|
||||
t.string "name"
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ RSpec.describe Bufferizer do
|
|||
|
||||
it "sends to buffer twitter" do
|
||||
tweet = "test tweet"
|
||||
described_class.new(article, tweet).twitter_post!
|
||||
described_class.new(article, tweet).main_teet!
|
||||
expect(article.last_buffered.utc.to_i).to be > 2.minutes.ago.to_i
|
||||
end
|
||||
|
||||
|
|
|
|||
46
spec/models/buffer_update_spec.rb
Normal file
46
spec/models/buffer_update_spec.rb
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
require 'rails_helper'
|
||||
|
||||
RSpec.describe BufferUpdate, type: :model do
|
||||
let(:user) { create(:user) }
|
||||
let(:article) { create(:article, user_id: user.id) }
|
||||
|
||||
it "creates update" do
|
||||
BufferUpdate.buff!(article.id, "twitter_buffer_text", "CODE", "twitter")
|
||||
expect(BufferUpdate.all.size).to eq(1)
|
||||
end
|
||||
|
||||
it "does not allow duplicate updates" do
|
||||
BufferUpdate.buff!(article.id, "twitter_buffer_text", "CODE", "twitter")
|
||||
BufferUpdate.buff!(article.id, "twitter_buffer_text", "CODE", "twitter")
|
||||
expect(BufferUpdate.all.size).to eq(1)
|
||||
end
|
||||
|
||||
it "does not allow duplicate updates if the first one was a little while ago" do
|
||||
b1 = BufferUpdate.buff!(article.id, "twitter_buffer_text", "CODE", "twitter")
|
||||
b1.update_column(:created_at, 5.minutes.ago)
|
||||
BufferUpdate.buff!(article.id, "twitter_buffer_text", "CODE", "twitter")
|
||||
expect(BufferUpdate.all.size).to eq(2)
|
||||
BufferUpdate.buff!(article.id, "twitter_buffer_text", "CODE", "twitter")
|
||||
expect(BufferUpdate.all.size).to eq(2)
|
||||
BufferUpdate.buff!(article.id, "twitter_buffer_text yoyo", "CODE", "twitter")
|
||||
expect(BufferUpdate.all.size).to eq(3)
|
||||
end
|
||||
|
||||
it "allows same text across different social platforms" do
|
||||
BufferUpdate.buff!(article.id, "twitter_buffer_text", "CODE", "facebook")
|
||||
BufferUpdate.buff!(article.id, "twitter_buffer_text", "CODE", "twitter")
|
||||
expect(BufferUpdate.all.size).to eq(2)
|
||||
end
|
||||
|
||||
it "allows same text across different tags" do
|
||||
BufferUpdate.buff!(article.id, "twitter_buffer_text", "CODE", "twitter", 1)
|
||||
BufferUpdate.buff!(article.id, "twitter_buffer_text", "CODE", "twitter", 2)
|
||||
expect(BufferUpdate.all.size).to eq(2)
|
||||
end
|
||||
|
||||
it "allows same text across different tags" do
|
||||
BufferUpdate.buff!(article.id, "twitter_buffer_text", "CODE", "twitter", 1)
|
||||
BufferUpdate.buff!(create(:article).id, "twitter_buffer_text", "CODE", "twitter", 1)
|
||||
expect(BufferUpdate.all.size).to eq(2)
|
||||
end
|
||||
end
|
||||
44
spec/requests/internal_buffer_updates_spec.rb
Normal file
44
spec/requests/internal_buffer_updates_spec.rb
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
require "rails_helper"
|
||||
|
||||
RSpec.describe "InternalBufferUpdates", type: :request do
|
||||
let(:user) { create(:user) }
|
||||
let(:article) { create(:article, user_id: user.id) }
|
||||
let(:comment) { create(:comment, user_id: user.id, commentable_id: article.id) }
|
||||
|
||||
before do
|
||||
sign_in user
|
||||
user.add_role(:super_admin)
|
||||
end
|
||||
|
||||
it "creates buffer update for tweet if tweet params are passed" do
|
||||
post "/internal/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 "/internal/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 "/internal/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 "updates last buffered at with satellite buffer" do
|
||||
post "/internal/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 "/internal/buffer_updates",
|
||||
params:
|
||||
{ social_channel: "facebook", article_id: article.id, tweet: "Hello this is a test" }
|
||||
expect(article.reload.facebook_last_buffered).not_to eq(nil)
|
||||
end
|
||||
end
|
||||
Loading…
Add table
Reference in a new issue