docbrown/app/views/admin/articles/_individual_article.html.erb
rhymes 99ddd31058
Pin posts to feed (#13807)
* Add SiteConfig.feed_pinned_article and validation

* Display pinned article at the top of feed

* Add (basic) functionality to pin/unpin post

* Admins can pin other users posts as well

* Hide the button if looking at the non pinned post

* Add pinned/unpinned snackbar message

* Rename SiteConfig usage to Settings::General

* Add pinned article to the Admin articles index

* Show the pin post button when there's no pinned article

* Move pinning to a separate controller

* Fix SiteConfig reference

* Hide PinController actions to unauthorized users

* PinnedArticlesController#show action and refactor some of the code

* Add Modal interaction

* Fix modal-pinned checkbox interaction

* Fixed pin/unpin post

* Add ArticleDecorator#pinned? specs

* Add PinnedArticlePolicy and PinnedArticlesController specs

* Add ability to actually pin an article from the admin after submit

* Add partial Cypress pin/unpin spec

* Fix pinned article and add basic Cypress interaction tests

* Add Crayons styling to modal

* Only render the pinned article on the default Feed page

* Use persisted?

* Add some comments

* Update app/javascript/articles/Article.jsx

Co-authored-by: Suzanne Aitchison <suzanne@forem.com>

* Update app/javascript/packs/homePageFeed.jsx

Co-authored-by: Suzanne Aitchison <suzanne@forem.com>

* Fix Cypress tests

* Update app/javascript/admin/controllers/article_controller.js

Co-authored-by: Ridhwana <Ridhwana.Khan16@gmail.com>

* Fix pinning in article show page

* Used PinnedArticle domain model

* Fix spec

* Update cypress/integration/adminFlows/articles/pinArticle.spec.js

Co-authored-by: Suzanne Aitchison <suzanne@forem.com>

* Update cypress/integration/adminFlows/articles/pinArticle.spec.js

Co-authored-by: Suzanne Aitchison <suzanne@forem.com>

* Update cypress/integration/adminFlows/articles/pinArticle.spec.js

Co-authored-by: Suzanne Aitchison <suzanne@forem.com>

* Update cypress/integration/adminFlows/articles/pinArticle.spec.js

Co-authored-by: Suzanne Aitchison <suzanne@forem.com>

* Update cypress/integration/adminFlows/articles/pinArticle.spec.js

Co-authored-by: Suzanne Aitchison <suzanne@forem.com>

* Update cypress/integration/articleFlows/pinArticle.spec.js

Co-authored-by: Suzanne Aitchison <suzanne@forem.com>

* Update cypress/integration/articleFlows/pinArticle.spec.js

Co-authored-by: Suzanne Aitchison <suzanne@forem.com>

* Update app/views/admin/articles/index.html.erb

Co-authored-by: Suzanne Aitchison <suzanne@forem.com>

* Fix merge woes

* Add missing article pin post flows

* Add missing admin article flows

* Add Unpin to Admin as well

* Add Audit::Log entries for pin/unpin actions

* Update app/controllers/stories/feeds_controller.rb

Co-authored-by: Michael Kohl <citizen428@dev.to>

* Do not rate limit in E2E tests

* Use .find instead of .filter

* Rename ArticleIdValidator to ExistingArticleIdValidator

* Treat draft and deleted articles the same

* Make sure posts can be pinned after the pinned article is unpublished or deleted

* Use .get directly

* Fix spec and fix PinnedArticlesController#show

* Strengthen pinArticle Cypress tests

* Add Cypress test heading guard

* Add another Cypress test heading guard

* Remove duplicate validator

* Try using the Tools: header instead of the article title

Co-authored-by: Suzanne Aitchison <suzanne@forem.com>
Co-authored-by: Ridhwana <Ridhwana.Khan16@gmail.com>
Co-authored-by: Michael Kohl <citizen428@dev.to>
2021-06-04 10:54:53 +02:00

182 lines
7.5 KiB
Text

<style>
.article-body-html img {
max-width: 100%;
}
</style>
<% decorated_article = article.decorate %>
<div class="card my-3"
data-controller="article"
data-article-id-value="<%= article.id %>"
data-article-pin-path-value="<%= stories_feed_pinned_article_path %>"
data-article-bg-highlighted-class="bg-highlighted"
data-article-border-highlighted-class="border-highlighted"
data-action="ajax:success@document->article#ajaxSuccess">
<div class="card-header">
<h2>
<a href="<%= article.path %>" target="_blank" rel="noopener">
<%= article.title %>
</a>
</h2>
<div>
<a href="<%= article.path %>/edit" target="_blank" rel="noopener"><span class="btn btn-sm btn-primary">Edit</span></a>
<button class="btn btn-sm btn-success" data-action="article#increaseFeaturedNumber">Boost</button>
<a class="btn btn-sm btn-secondary" href="<%= admin_user_path(article.user_id) %>" target="_blank" rel="noopener">Manage User</a>
<% if decorated_article.pinned? %>
<%= link_to(
"Unpin Post",
unpin_admin_article_path(decorated_article.id),
method: :delete,
remote: true,
class: "btn btn-sm btn-secondary",
data: { "article-target": "unpinButton" },
) %>
<% end %>
<a href="<%= admin_user_path(article.user_id) %>" class="badge badge-light">@<%= article.user&.username %></a>
<span class="badge badge-light">❤️ <%= article.public_reactions_count %> 💬 <%= article.comments_count %></span>
<span class="badge badge-light">
<% if article.published_from_feed? && !article.published? %>
RSS Import <%= article.created_at.strftime("%b %d, %Y") %>
Originally Published <%= article.published_at&.strftime("%b %d, %Y") %>
<% elsif article.crossposted_at? %>
Crossposted <%= article.crossposted_at.strftime("%b %d, %Y") %> & Published
<%= article.published_at&.strftime("%b %d, %Y") %>
<% else %>
<%= article.published_at&.strftime("%b %d, %Y") %>
<% end %>
</span>
<% decorated_article.cached_tag_list_array.each do |tag| %>
<a class="badge badge-secondary" href='<%= tag_path(tag) %>'>#<%= tag %></a>
<% end %>
</div>
</div>
<% featured = article.featured ? "bg-featured" : "" %>
<% approved = article.approved ? "bg-approved" : featured %>
<% pinned = decorated_article.pinned? ? "bg-pinned" : approved %>
<% background_color = pinned %>
<div
data-article-target="cardBody"
class="card-body <%= background_color %> <%= "bg-danger" if !article.published? && article.published_from_feed? %>">
<% if article.video %>
<h2>Contains Video</h2>
<% end %>
<% cache "admin-user-info-#{article.user_id}-#{article.user&.updated_at}", expires_in: 4.hours do %>
<% if article.user&.warned %>
<h2><span class="badge badge-warning">USER WARNED</span></h2>
<% end %>
<% if article.user&.notes&.any? %>
<h2>User Notes (<%= article.user&.notes&.size %> total)</h2>
<% article.user&.notes&.last(3)&.each do |note| %>
<p>
<em><%= note.created_at.strftime("%d %B %Y %H:%M UTC") %> by
<%= note.author_id ? User.find(note.author_id).username : "No Author" %></em> - <%= note.content %>
</p>
<% end %>
<p><a href="<%= admin_user_path(article.user_id) %>">View All</a></p>
<% end %>
<% end %>
<% if article.main_image.present? %>
<div style="max-height:450px;overflow:hidden;">
<img src="<%= cloud_cover_url(article.main_image) %>" style="width:100%;max-width:380px;border-radius:8px;background:<%= article.main_image_background_hex_color %>;" alt="cover image" loading="lazy" />
<br />
</div>
<% end %>
<%= form_with url: admin_article_path(article.id), model: article, local: true 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" />
</div>
<div class="row">
<div class="form-group col">
<label for="featured_number_<%= article.id %>">Featured Number:</label>
<input id="featured_number_<%= article.id %>"
class="form-control"
name="article[featured_number]"
value="<%= article.featured_number %>"
data-article-target="featuredNumber">
</div>
<div class="form-group col">
<label for="author_id_<%= article.id %>">Author ID:</label>
<input id="author_id_<%= article.id %>" class="form-control" size="6" name="article[user_id]"
value="<%= article.user_id %>">
</div>
<div class="form-group col">
<label for="co_author_ids_list_<%= article.id %>">Co-Author IDs (comma separated):</label>
<input id="co_author_ids_list_<%= article.id %>" class="form-control" size="6" name="article[co_author_ids_list]"
value="<%= article.co_author_ids&.join(", ") %>">
</div>
</div>
<% if article.published? %>
<div class="row">
<div class="form-group col">
<label for="published_at_<%= article.id %>">Published at:</label>
<%= f.datetime_select :published_at, required: true, include_blank: true, include_seconds: true, class: "form-control" %> UTC
</div>
</div>
<% end %>
<div class="row">
<div class="form-check col">
<%= f.check_box :featured, id: "featured-#{article.id}" %>
<label for="featured-<%= article.id %>">Featured</label>
</div>
<div class="form-check col">
<%= f.check_box :approved, id: "approved-#{article.id}" %>
<label for="approved-<%= article.id %>">Approved</label>
</div>
<div class="form-check col">
<%= f.check_box :boosted_additional_articles, id: "boosted_additional_articles-#{article.id}" %>
<label for="boosted_additional_articles-<%= article.id %>">Boosted</label>
</div>
<div class="form-check col">
<%= check_box_tag :pinned, "1", decorated_article.pinned?,
name: "article[pinned]",
id: "pinned-#{article.id}",
data: {
"article-target": "pinnedCheckbox",
"article-pinned-modal-target": "pinnedCheckbox",
action: "click->article#togglePin"
} %>
<label for="pinned-<%= article.id %>">Pinned</label>
</div>
<div class="col">
<button class="btn btn-primary float-right">Submit</button>
</div>
</div>
<% end %>
<% if article.boosted_dev_digest_email %>
<br /><br />
<% phrase = "#{article.path}?booster_org=#{article.organization&.slug || 'generic'}" %>
<b>BOOSTED IN <%= EmailMessage.where("subject LIKE ?", "%#{phrase}%").where.not(opened_at: nil).size %> EMAILS</b>
<br />
<b>BOOSTED IN
<%= EmailMessage.where("subject LIKE ?", "%#{phrase}%").where.not(opened_at: nil).where("sent_at > ?", 1.week.ago).size %>
EMAILS IN THE PAST WEEK</b>
<br /><br />
<b>BOOSTED IN
<%= EmailMessage.where("subject LIKE ?", "%#{phrase}%").where.not(opened_at: nil).where.not(opened_at: nil).size %>
OPENED EMAILS</b>
<br />
<b>BOOSTED IN
<%= 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>
</div>