Buffer Listings (#2956)
* add share to buffer button * wip * wip * adds listings to buffer via form * create migration for buffered timestamp and update seed file * display when listing was last buffered * remove annoying spacing * refactor article script for listings * social preview wip * add custom social card for indivdual listings * add styling * fix css * tweak styling * final css tweaks * fix branch * add buffer listings id * update envfile * add social previews spec
This commit is contained in:
parent
d33cc055dd
commit
10674aed72
20 changed files with 310 additions and 107 deletions
1
Envfile
1
Envfile
|
|
@ -79,6 +79,7 @@ variable :BUFFER_FACEBOOK_ID, :String, default: "Optional"
|
|||
variable :BUFFER_LINKEDIN_ID, :String, default: "Optional"
|
||||
variable :BUFFER_PROFILE_ID, :Integer, default: 0
|
||||
variable :BUFFER_TWITTER_ID, :String, default: "Optional"
|
||||
variable :BUFFER_LISTINGS_PROFILE, :String, default: "Optional"
|
||||
|
||||
# Cloudinary for image resizing and cache??
|
||||
variable :CLOUDINARY_API_KEY, :String, default: "Optional"
|
||||
|
|
|
|||
|
|
@ -1,16 +1,23 @@
|
|||
class Internal::BufferUpdatesController < Internal::ApplicationController
|
||||
def create
|
||||
article = Article.find(params[:article_id])
|
||||
article_id = params[:article_id]
|
||||
article = Article.find(article_id) if article_id.present?
|
||||
fb_post = params[:fb_post]
|
||||
tweet = params[:tweet]
|
||||
if params[:social_channel] == "main_twitter"
|
||||
Bufferizer.new(article, tweet).main_teet!
|
||||
listing_id = params[:listing_id]
|
||||
listing = ClassifiedListing.find(params[:listing_id]) if listing_id.present?
|
||||
case params[:social_channel]
|
||||
when "main_twitter"
|
||||
Bufferizer.new("article", article, tweet).main_tweet!
|
||||
render body: nil
|
||||
elsif params[:social_channel] == "satellite_twitter"
|
||||
Bufferizer.new(article, tweet).satellite_tweet!
|
||||
when "satellite_twitter"
|
||||
Bufferizer.new("article", article, tweet).satellite_tweet!
|
||||
render body: nil
|
||||
elsif params[:social_channel] == "facebook"
|
||||
Bufferizer.new(article, fb_post).facebook_post!
|
||||
when "facebook"
|
||||
Bufferizer.new("article", article, fb_post).facebook_post!
|
||||
render body: nil
|
||||
when "listings_twitter"
|
||||
Bufferizer.new("listing", listing, tweet).listings_tweet!
|
||||
render body: nil
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -23,14 +23,27 @@ class SocialPreviewsController < ApplicationController
|
|||
|
||||
def user
|
||||
@user = User.find(params[:id]) || not_found
|
||||
|
||||
respond_to do |format|
|
||||
format.html do
|
||||
render layout: false
|
||||
end
|
||||
format.png do
|
||||
html = render_to_string(formats: :html, layout: false)
|
||||
redirect_to HtmlCssToImage.fetch_url(html: html, css: PNG_CSS, google_fonts: "Roboto"), status: :found
|
||||
redirect_to HtmlCssToImage.fetch_url(html: html, css: PNG_CSS, google_fonts: "Roboto|Roboto+Condensed"), status: :found
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def listing
|
||||
@listing = ClassifiedListing.find(params[:id]) || not_found
|
||||
define_categories
|
||||
respond_to do |format|
|
||||
format.html do
|
||||
render layout: false
|
||||
end
|
||||
format.png do
|
||||
html = render_to_string(formats: :html, layout: false)
|
||||
redirect_to HtmlCssToImage.fetch_url(html: html, css: PNG_CSS, google_fonts: "Roboto|Roboto+Condensed"), status: :found
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -62,4 +75,24 @@ class SocialPreviewsController < ApplicationController
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def define_categories
|
||||
cat_info = {
|
||||
"collabs": ["Collaborators Wanted", "#5AE8D9"],
|
||||
"cfp": ["Call For Proposal", "#f58f8d"],
|
||||
"forhire": ["Available For Hire", "#b78cf4"],
|
||||
"education": ["Education", "#5AABE8"],
|
||||
"jobs": ["Now Hiring", "#53c3ad"],
|
||||
"mentors": ["Offering Mentorship", "#A69EE8"],
|
||||
"mentees": ["Looking For Mentorship", "#88aedb"],
|
||||
"forsale": ["Stuff For Sale", "#d0adfb"],
|
||||
"events": ["Upcoming Event", "#f8b3d0"],
|
||||
"misc": ["Miscellaneous", "#6393FF"],
|
||||
"products": ["Products & Tools", "#5AE8D9"]
|
||||
}
|
||||
@category = cat_info[@listing.category.to_sym][0]
|
||||
@cat_color = cat_info[@listing.category.to_sym][1]
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -13,6 +13,10 @@ module SocialImageHelper
|
|||
end
|
||||
end
|
||||
|
||||
def listing_social_image_url(listing)
|
||||
listing_social_preview_url(listing, format: :png)
|
||||
end
|
||||
|
||||
def article_social_image_url(article)
|
||||
image = user_defined_image(article)
|
||||
if image.present?
|
||||
|
|
|
|||
|
|
@ -1,35 +1,49 @@
|
|||
class Bufferizer
|
||||
attr_accessor :article, :text
|
||||
def initialize(article, text)
|
||||
@article = article
|
||||
attr_accessor :post_type, :post, :text
|
||||
def initialize(post_type, post, text)
|
||||
if post_type == "article"
|
||||
@article = post
|
||||
else
|
||||
@listing = post
|
||||
end
|
||||
@text = text
|
||||
end
|
||||
|
||||
def satellite_tweet!
|
||||
article.tags.find_each do |tag|
|
||||
BufferUpdate.buff!(article.id, twitter_buffer_text, tag.buffer_profile_id_code, "twitter", tag.id) if tag.buffer_profile_id_code.present?
|
||||
@article.tags.find_each do |tag|
|
||||
BufferUpdate.buff!(@article.id, twitter_buffer_text, tag.buffer_profile_id_code, "twitter", tag.id) if tag.buffer_profile_id_code.present?
|
||||
end
|
||||
article.update(last_buffered: Time.current)
|
||||
@article.update(last_buffered: Time.current)
|
||||
end
|
||||
|
||||
def main_teet!
|
||||
BufferUpdate.buff!(article.id, twitter_buffer_text, ApplicationConfig["BUFFER_TWITTER_ID"], "twitter", nil)
|
||||
article.update(last_buffered: Time.current)
|
||||
def main_tweet!
|
||||
BufferUpdate.buff!(@article.id, twitter_buffer_text, ApplicationConfig["BUFFER_TWITTER_ID"], "twitter", nil)
|
||||
@article.update(last_buffered: Time.current)
|
||||
end
|
||||
|
||||
def facebook_post!
|
||||
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.current)
|
||||
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.current)
|
||||
end
|
||||
|
||||
def listings_tweet!
|
||||
buffer_listings_id = ApplicationConfig["BUFFER_LISTINGS_PROFILE"]
|
||||
BufferUpdate.send_to_buffer(listings_twitter_text, buffer_listings_id)
|
||||
@listing.update(last_buffered: Time.current)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def twitter_buffer_text
|
||||
"#{text} https://dev.to#{article.path}" if text.size <= 255
|
||||
"#{text} https://dev.to#{@article.path}" if text.size <= 255
|
||||
end
|
||||
|
||||
def fb_buffer_text
|
||||
"#{text} https://dev.to#{article.path}"
|
||||
"#{text} https://dev.to#{@article.path}"
|
||||
end
|
||||
|
||||
def listings_twitter_text
|
||||
"#{text} https://dev.to#{@listing.path}" if text.size <= 255
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
class BufferUpdate < ApplicationRecord
|
||||
belongs_to :article
|
||||
|
||||
validate :validate_body_text_recent_uniqueness
|
||||
validates :status, inclusion: { in: %w[pending sent_direct confirmed dismissed] }
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ class ClassifiedListing < ApplicationRecord
|
|||
|
||||
belongs_to :user, optional: true
|
||||
belongs_to :organization, optional: true
|
||||
|
||||
before_save :evaluate_markdown
|
||||
before_create :create_slug
|
||||
before_validation :modify_inputs
|
||||
|
|
|
|||
|
|
@ -4,37 +4,44 @@
|
|||
<link rel="canonical" href="https://dev.to<%= request.path %>" />
|
||||
<meta name="description" content="Where programmers share ideas and help each other grow.">
|
||||
<meta name="keywords" content="software development,engineering,rails,javascript,ruby">
|
||||
|
||||
<meta property="og:type" content="website" />
|
||||
<meta property="og:url" content="https://dev.to<%= request.path %>" />
|
||||
<meta property="og:title" content="Listings" />
|
||||
<meta property="og:image" content="https://thepracticaldev.s3.amazonaws.com/i/sa3xjflbtvt9zw0xpan5.png">
|
||||
<meta property="og:description" content="Where programmers share ideas and help each other grow." />
|
||||
<meta property="og:site_name" content="<%= community_qualified_name %>" />
|
||||
|
||||
<% if @displayed_classified_listing %>
|
||||
<meta property="og:title" content="<%= truncate @displayed_classified_listing.title, length: 54 %>" />
|
||||
<meta property="og:description" content="DEV Listing" />
|
||||
<meta property="og:image" content="<%= listing_social_image_url @displayed_classified_listing %>">
|
||||
<meta name="twitter:title" content="<%= truncate @displayed_classified_listing.title, length: 54 %>">
|
||||
<meta name="twitter:description" content="DEV Listing">
|
||||
<meta name="twitter:image:src" content="<%= listing_social_image_url @displayed_classified_listing %>">
|
||||
<% else %>
|
||||
<meta property="og:title" content="Listings" />
|
||||
<meta property="og:description" content="Where programmers share ideas and help each other grow." />
|
||||
<meta property="og:image" content="https://thepracticaldev.s3.amazonaws.com/i/sa3xjflbtvt9zw0xpan5.png">
|
||||
<meta name="twitter:title" content="Listings">
|
||||
<meta name="twitter:description" content="Where programmers share ideas, experiences, and help each other grow.">
|
||||
<meta name="twitter:image:src" content="https://thepracticaldev.s3.amazonaws.com/i/sa3xjflbtvt9zw0xpan5.png">
|
||||
<% end %>
|
||||
<meta name="twitter:site" content="@ThePracticalDev">
|
||||
<meta name="twitter:title" content="Listings">
|
||||
<meta name="twitter:description" content="Where programmers share ideas, experiences, and help each other grow.">
|
||||
<meta name="twitter:image:src" content="https://thepracticaldev.s3.amazonaws.com/i/sa3xjflbtvt9zw0xpan5.png">
|
||||
<meta name="twitter:card" content="summary_large_image">
|
||||
<% end %>
|
||||
|
||||
<div class="home">
|
||||
<div class="classifieds-container" id="classifieds-index-container"
|
||||
data-category="<%= params[:category] %>" data-listings="<%= @classified_listings.to_json(
|
||||
only: %i[title processed_html tag_list category id user_id slug contact_via_connect],
|
||||
include: {
|
||||
author: { only: %i[username name], methods: %i[username profile_image_90] },
|
||||
},
|
||||
) %>"
|
||||
only: %i[title processed_html tag_list category id user_id slug contact_via_connect],
|
||||
include: {
|
||||
author: { only: %i[username name], methods: %i[username profile_image_90] }
|
||||
},
|
||||
) %>"
|
||||
data-allcategories="<%= ClassifiedListing.categories_for_display.to_json %>"
|
||||
<% if @displayed_classified_listing %>
|
||||
data-displayedlisting="<%= @displayed_classified_listing.to_json(
|
||||
only: %i[title processed_html tag_list category id user_id slug contact_via_connect],
|
||||
include: {
|
||||
author: { only: %i[username name], methods: %i[username profile_image_90] },
|
||||
},
|
||||
) %> "
|
||||
only: %i[title processed_html tag_list category id user_id slug contact_via_connect],
|
||||
include: {
|
||||
author: { only: %i[username name], methods: %i[username profile_image_90] }
|
||||
},
|
||||
) %> "
|
||||
<% end %>
|
||||
>
|
||||
<div class="classified-filters">
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
<script>
|
||||
console.log('its rendering!')
|
||||
function timeNow(objectID) {
|
||||
var seconds = new Date().getTime() / 1000;
|
||||
document.getElementById("featured_number_" + objectID).value = Math.round(seconds);
|
||||
|
|
@ -9,7 +10,7 @@
|
|||
document.getElementById("featured_number_" + objectID).value = Math.round(seconds);
|
||||
}
|
||||
|
||||
$('.row').on("submit", "form", function () {
|
||||
function submitForms() {
|
||||
var form = $(this);
|
||||
var valuesToSubmit = $(this).serialize();
|
||||
$.ajax({
|
||||
|
|
@ -19,47 +20,54 @@
|
|||
// 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")
|
||||
form.parents(".row, .single-internal-listing").addClass("highlighted-bg")
|
||||
form.parents(".row, .single-internal-listing").addClass("highlighted-border")
|
||||
setTimeout(function () {
|
||||
form.parents(".row").removeClass("highlighted-bg")
|
||||
form.parents(".row, .single-internal-listing").removeClass("highlighted-bg")
|
||||
}, 350)
|
||||
});
|
||||
return false; // prevents normal behaviour
|
||||
});
|
||||
}
|
||||
|
||||
$('.row').on("submit", "form", submitForms)
|
||||
$('.buffering-area-for-single-listing').on("submit", "form", submitForms)
|
||||
|
||||
$(".toggle-buffering-butt").click(function (e) {
|
||||
e.preventDefault()
|
||||
console.log($(this).closest(".single-internal-article").find(".buffering-area-for-single-article").toggle());
|
||||
console.log($(this).closest(".single-internal-article, .buffer-area").find(".buffering-area-for-single-article, .buffering-area-for-single-listing").toggle());
|
||||
})
|
||||
|
||||
document.getElementById('image-upload-button').onclick = function (e) {
|
||||
e.preventDefault();
|
||||
document.getElementById('image-upload').click();
|
||||
}
|
||||
imageUploadButt = document.getElementById('image-upload-button')
|
||||
imageUpload = document.getElementById('image-upload')
|
||||
imageUploadSubmit = document.getElementById('image-upload-submit')
|
||||
|
||||
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)
|
||||
if (imageUploadButt && imageUpload && imageUploadSubmit) {
|
||||
imageUploadButt.onclick = function (e) {
|
||||
e.preventDefault();
|
||||
document.getElementById('image-upload').click();
|
||||
}
|
||||
}
|
||||
|
||||
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));
|
||||
imageUpload.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)
|
||||
}
|
||||
}
|
||||
imageUploadSubmit.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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -132,8 +132,7 @@
|
|||
<% if !article.user.twitter_username.blank? %>
|
||||
|
||||
{ author: @<%= article.user.twitter_username %> } #DEVCommunity
|
||||
<% end %>
|
||||
</textarea>
|
||||
<% end %></textarea>
|
||||
<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? %>
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
<%= submit_tag("Search") %>
|
||||
<% end %>
|
||||
<%= paginate @classified_listings %>
|
||||
<div class="wrapper">
|
||||
<div class="wrapper" style="border-bottom: 1px solid black">
|
||||
<div class="grid-item">Title Link</div>
|
||||
<div class="grid-item">User/Org</div>
|
||||
<div class="grid-item">Category</div>
|
||||
|
|
@ -17,23 +17,41 @@
|
|||
<div class="grid-item">Last Bumped</div>
|
||||
</div>
|
||||
<% @classified_listings.each do |listing| %>
|
||||
<div class="wrapper">
|
||||
<div class="grid-item">
|
||||
<a href="/internal/listings/<%= listing.id %>/edit" target="_blank">
|
||||
<%= listing.title %>
|
||||
</a>
|
||||
<div class="single-internal-listing">
|
||||
<div class="wrapper">
|
||||
<div class="grid-item">
|
||||
<a href="/internal/listings/<%= listing.id %>/edit" target="_blank">
|
||||
<%= listing.title %>
|
||||
</a>
|
||||
</div>
|
||||
<div class="grid-item"><a href="/internal/users/<%= listing.user_id %>"><%= User.find(listing.user_id).username %></a><%= " / " + Organization.find(listing.organization_id).name if listing.organization_id.present? %></div>
|
||||
<div class="grid-item"><%= listing.category %></div>
|
||||
<div class="grid-item"><%= listing.cached_tag_list %></div>
|
||||
<div class="grid-item"><%= listing.published ? "Yes" : "No" %></div>
|
||||
<div class="grid-item"><%= time_ago_in_words(listing.bumped_at) %> ago</div>
|
||||
</div>
|
||||
<div class="buffer-area" style="text-align: left">
|
||||
<br>
|
||||
<button class="btn toggle-buffering-butt" style="border: 1px solid grey; margin-top: 2px">Share to Buffer</button><% if listing.last_buffered.present? %> <em> Last shared: <%= listing.last_buffered.strftime("%d %B %Y") %></em><% end %>
|
||||
<br>
|
||||
<br>
|
||||
<div class="buffering-area-for-single-listing" style="display: none;">
|
||||
<div class="grid-item">
|
||||
<p class="listing-title"><strong><%= listing.title %></strong></p>
|
||||
<p class="listing-body"><%= listing.processed_html&.html_safe %></p>
|
||||
</div>
|
||||
<div class="grid-item">
|
||||
<%= form_tag "/internal/buffer_updates" do %>
|
||||
<input type="hidden" name="social_channel" value="listings_twitter" />
|
||||
<input type="hidden" name="listing_id" value="<%= listing.id %>" />
|
||||
<textarea cols="37" rows="5" wrap="hard" name="tweet" maxlength="255"><%= listing.title %><% if User.find(listing.user_id).twitter_username.present? %>

Listed by @<%= User.find(listing.user_id).twitter_username %> 😎
<% end %>
#DEVCommunity</textarea>
|
||||
<br>
|
||||
<button class="btn-info tweet-listing">🐦 Tweet 🐦</button>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="grid-item"><a href="/internal/users/<%= listing.user_id %>"><%= User.find(listing.user_id).username %></a><%= " / " + Organization.find(listing.organization_id).name if listing.organization_id.present? %></div>
|
||||
<div class="grid-item"><%= listing.category %></div>
|
||||
<div class="grid-item"><%= listing.cached_tag_list %></div>
|
||||
<div class="grid-item"><%= listing.published ? "Yes" : "No" %></div>
|
||||
<div class="grid-item"><%= time_ago_in_words(listing.bumped_at) %> ago</div>
|
||||
</div>
|
||||
<% end %>
|
||||
<%= paginate @classified_listings %>
|
||||
<style>
|
||||
.wrapper {
|
||||
border-bottom: 1px solid grey;
|
||||
padding: 10px;
|
||||
}
|
||||
</style>
|
||||
<%= render "internal/articles/article_script" %>
|
||||
|
|
|
|||
|
|
@ -59,6 +59,17 @@
|
|||
min-width: 100px;
|
||||
}
|
||||
|
||||
.single-internal-listing {
|
||||
border-bottom: 1px solid grey;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.buffering-area-for-single-listing {
|
||||
display: grid;
|
||||
grid-template-columns: 50% 50%;
|
||||
padding: 2px;
|
||||
}
|
||||
|
||||
.tab {
|
||||
padding-top: 10px;
|
||||
padding-bottom: 10px;
|
||||
|
|
|
|||
|
|
@ -1,13 +1,86 @@
|
|||
<div clas="listing-content">
|
||||
<h3><%= @listing.title %></h3>
|
||||
<div class="single-classified-listing-body">
|
||||
<%= @listing.processed_html.html_safe %>
|
||||
</div>
|
||||
<div class="single-classified-listing-tags">
|
||||
<% if @listing.tags.present? %>
|
||||
<%= @listing.tags.each do |tag| %>
|
||||
<%= tag.name %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
<style>
|
||||
body {
|
||||
background: white;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.preview-div-wrapper {
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.preview-div {
|
||||
border: 0.25vw solid <%= @cat_color %>;
|
||||
box-shadow: 0.75vw .75vw 0px <%= @cat_color %>;
|
||||
width: 88vw;
|
||||
height: 42vw;
|
||||
margin: 2.5vw auto 5vw;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
background-image: linear-gradient(to bottom, transparent 40%, <%= @cat_color %>);
|
||||
}
|
||||
|
||||
.preview-info-header {
|
||||
color: black;
|
||||
margin: 2vw auto 0vw;
|
||||
font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier, "Roboto", monospace;
|
||||
font-size: 3.5vw;
|
||||
width: 92%;
|
||||
}
|
||||
|
||||
.preview-title{
|
||||
padding: 0 2vw;
|
||||
}
|
||||
|
||||
h1 {
|
||||
color: <%= @cat_color %>;
|
||||
width: 92%;
|
||||
margin: 0;
|
||||
padding: 1vw;
|
||||
font-family: "Helvetica Neue", Helvetica, Arial, "Lucida Grande", "Roboto", sans-serif;
|
||||
}
|
||||
|
||||
.preview-body {
|
||||
font-size: 2vw;
|
||||
padding: 0 4vw;
|
||||
font-family: "Helvetica Neue", Helvetica, Arial, "Lucida Grande", "Roboto", sans-serif;
|
||||
color: <%= @cat_color %>;
|
||||
}
|
||||
|
||||
.preview-category {
|
||||
font-size: 3.5vw;
|
||||
position: absolute;
|
||||
background: white;
|
||||
left: -2vw;
|
||||
bottom: 0vw;
|
||||
padding: 1vw 4vw;
|
||||
font-weight: 500;
|
||||
width: 100%;
|
||||
color: <%= @cat_color %>;
|
||||
}
|
||||
|
||||
.preview-dev-logo {
|
||||
position: absolute;
|
||||
bottom: -2.25vw;
|
||||
right: -3vw;
|
||||
text-align: right;
|
||||
}
|
||||
</style>
|
||||
<div class="preview-div-wrapper">
|
||||
<div class="preview-div">
|
||||
<div class="preview-title">
|
||||
<% font_size = @listing.title.length > 65 ? 3 : 4 %>
|
||||
<h1 style="font-size:<%= font_size %>vw;"><%= @listing.title %></h1>
|
||||
</div>
|
||||
<div class="preview-body">
|
||||
<%= @listing.processed_html.html_safe %>
|
||||
</div>
|
||||
<div class="preview-category">
|
||||
<%= @category %>
|
||||
</div>
|
||||
<div class="preview-dev-logo">
|
||||
<%= inline_svg("devlistings-horizontal.svg", class: "logo", size: "30vw*10vw", aria: true, title: "DEV logo") %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ Rails.application.config.assets.precompile += %w[s3_direct_upload.css]
|
|||
Rails.application.config.assets.precompile += %w[base.js]
|
||||
Rails.application.config.assets.precompile += %w[hello-dev.js]
|
||||
Rails.application.config.assets.precompile += %w[s3_direct_upload.js]
|
||||
|
||||
Rails.application.config.assets.precompile += %w[classified_listings.css]
|
||||
Rails.application.config.assets.precompile += %w[lib/xss.js]
|
||||
Rails.application.config.assets.precompile += %w[lib/pulltorefresh.js]
|
||||
Rails.application.config.assets.precompile += %w[internal.js]
|
||||
|
|
|
|||
|
|
@ -166,6 +166,7 @@ Rails.application.routes.draw do
|
|||
get "/social_previews/user/:id" => "social_previews#user", as: :user_social_preview
|
||||
get "/social_previews/organization/:id" => "social_previews#organization", as: :organization_social_preview
|
||||
get "/social_previews/tag/:id" => "social_previews#tag", as: :tag_social_preview
|
||||
get "/social_previews/listing/:id" => "social_previews#listing", as: :listing_social_preview
|
||||
|
||||
get "/async_info/base_data", controller: "async_info#base_data", defaults: { format: :json }
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,5 @@
|
|||
class AddLastBufferedToClassifiedListings < ActiveRecord::Migration[5.2]
|
||||
def change
|
||||
add_column :classified_listings, :last_buffered, :datetime
|
||||
end
|
||||
end
|
||||
|
|
@ -14,6 +14,7 @@
|
|||
|
||||
ActiveRecord::Schema.define(version: 2019_06_14_093041) do
|
||||
# These are extensions that must be enabled in order to support this database
|
||||
enable_extension "pg_stat_statements"
|
||||
enable_extension "plpgsql"
|
||||
|
||||
create_table "ahoy_messages", id: :serial, force: :cascade do |t|
|
||||
|
|
@ -244,6 +245,7 @@ ActiveRecord::Schema.define(version: 2019_06_14_093041) do
|
|||
t.string "category"
|
||||
t.boolean "contact_via_connect", default: false
|
||||
t.datetime "created_at", null: false
|
||||
t.datetime "last_buffered"
|
||||
t.bigint "organization_id"
|
||||
t.text "processed_html"
|
||||
t.boolean "published"
|
||||
|
|
|
|||
|
|
@ -253,6 +253,8 @@ listings_categories.each_with_index do |category, index|
|
|||
body_markdown: Faker::Markdown.random,
|
||||
category: category,
|
||||
contact_via_connect: true,
|
||||
published: true,
|
||||
bumped_at: Time.current,
|
||||
)
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -2,17 +2,24 @@ require "rails_helper"
|
|||
|
||||
RSpec.describe Bufferizer do
|
||||
let(:user) { create(:user) }
|
||||
let(:listing) { create(:classified_listing, user_id: user.id) }
|
||||
let(:article) { create(:article, user_id: user.id) }
|
||||
|
||||
it "sends to buffer twitter" do
|
||||
tweet = "test tweet"
|
||||
described_class.new(article, tweet).main_teet!
|
||||
described_class.new("article", article, tweet).main_tweet!
|
||||
expect(article.last_buffered.utc.to_i).to be > 2.minutes.ago.to_i
|
||||
end
|
||||
|
||||
it "sends to buffer facebook" do
|
||||
post = "test facebook post"
|
||||
described_class.new(article, post).facebook_post!
|
||||
described_class.new("article", article, post).facebook_post!
|
||||
expect(article.facebook_last_buffered.utc.to_i).to be > 2.minutes.ago.to_i
|
||||
end
|
||||
|
||||
it "sends to buffer listings" do
|
||||
text = "test listing"
|
||||
described_class.new("listing", listing, text).listings_tweet!
|
||||
expect(listing.last_buffered).not_to be(nil)
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ RSpec.describe "SocialPreviews", type: :request do
|
|||
let(:organization) { create(:organization) }
|
||||
let(:article) { create(:article, user_id: user.id) }
|
||||
let(:image_url) { "https://hcti.io/v1/image/6c52de9d-4d37-4008-80f8-67155589e1a1" }
|
||||
let(:listing) { create(:classified_listing, user_id: user.id, category: "cfp") }
|
||||
|
||||
before do
|
||||
stub_request(:post, /hcti.io/).
|
||||
|
|
@ -73,4 +74,16 @@ RSpec.describe "SocialPreviews", type: :request do
|
|||
expect(response).to redirect_to(image_url)
|
||||
end
|
||||
end
|
||||
|
||||
describe "GET /social_previews/listing/:id" do
|
||||
it "renders pretty category name" do
|
||||
get "/social_previews/listing/#{listing.id}"
|
||||
expect(response.body).to include CGI.escapeHTML("Call For Proposal")
|
||||
end
|
||||
|
||||
it "renders and image when requested and redirects to iamge url" do
|
||||
get "/social_previews/listing/#{listing.id}.png"
|
||||
expect(response).to redirect_to(image_url)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue