From a996f3bd05fc480247fd112f23fa3e67f7d5d7b5 Mon Sep 17 00:00:00 2001 From: Star Rauchenberger Date: Sat, 7 Dec 2024 15:54:39 -0500 Subject: Added support for liking blog posts via webmention --- app/controllers/blogs_controller.rb | 34 +++++++++++++++++++++++++++++++++ app/models/concerns/votable.rb | 8 ++++++++ app/models/vote.rb | 1 - app/views/blogs/_blog.html.haml | 2 +- app/views/blogs/show.html.haml | 1 + app/views/layouts/application.html.haml | 2 ++ 6 files changed, 46 insertions(+), 2 deletions(-) (limited to 'app') diff --git a/app/controllers/blogs_controller.rb b/app/controllers/blogs_controller.rb index 033d6bb..4bbbc28 100644 --- a/app/controllers/blogs_controller.rb +++ b/app/controllers/blogs_controller.rb @@ -1,6 +1,9 @@ +require 'microformats' require 'redcarpet/render_strip' +require 'webmention' class BlogsController < ApplicationController + skip_before_action :verify_authenticity_token, only: [:webmention] def summary @blogs = Blog.where(published: true).order(published_at: :desc).paginate(page: params[:page], per_page: 10) @@ -89,4 +92,35 @@ class BlogsController < ApplicationController end end + def webmention + @blog = Blog.find_by_slug(params[:slug]) + + raise ActiveRecord::RecordNotFound unless @blog + raise ActiveRecord::RecordNotFound unless @blog.published + + permalink = url_for(@blog) + + target = params[:target] + unless target == permalink + render json: { error: "Incorrect target for webmention endpoint (#{target} != #{permalink})." } + return + end + + source = params[:source] + verification = Webmention.verify_webmention(source, target) + unless verification.verified? + render json: { error: "Webmention could not be verified." } + return + end + + response = Webmention::Request.get(source) + parsed = Microformats.parse(response.body.to_s) + + if parsed.entry.properties.to_hash.include?("like-of") and parsed.entry.like_of(:all).map(&:to_s).include? permalink + @blog.like!(parsed.entry.author.url, parsed.entry.author.name) + end + + head :ok + end + end diff --git a/app/models/concerns/votable.rb b/app/models/concerns/votable.rb index ba6e6d5..40b3a2a 100644 --- a/app/models/concerns/votable.rb +++ b/app/models/concerns/votable.rb @@ -39,5 +39,13 @@ module Votable save! end end + + def like!(url, name) + return false unless votes.where(liker_url: url).empty? + + votes.create(liker_url: url, liker_name: name, upvote: 1).save + self.upvotes += 1 + save! + end end end diff --git a/app/models/vote.rb b/app/models/vote.rb index e2d8386..fced5bd 100644 --- a/app/models/vote.rb +++ b/app/models/vote.rb @@ -2,5 +2,4 @@ class Vote < ApplicationRecord belongs_to :votable, polymorphic: true validates :upvote, presence: true, inclusion: { in: [0, 1] } - validates :ip, presence: true end diff --git a/app/views/blogs/_blog.html.haml b/app/views/blogs/_blog.html.haml index d0b81d1..878b1a2 100644 --- a/app/views/blogs/_blog.html.haml +++ b/app/views/blogs/_blog.html.haml @@ -19,7 +19,7 @@ %cite.bubble.blog-cite %span.p-author.h-card %strong.p-name= blog.user.login.capitalize - %data.u-url{ value: "/" } + %data.u-url{ value: root_url } on %time.dt-published{ datetime: blog.visible_date.strftime("%Y-%m-%dT%H:%M:%SZ%z") }= blog.visible_date.strftime("%B #{blog.visible_date.day.ordinalize}, %Y at %-I:%M:%S%P") .post-vote{ id: "blog-vote-section-#{blog.id}" } diff --git a/app/views/blogs/show.html.haml b/app/views/blogs/show.html.haml index 7558257..c849143 100644 --- a/app/views/blogs/show.html.haml +++ b/app/views/blogs/show.html.haml @@ -1,4 +1,5 @@ - title @blog.title +- content_for :webmention_endpoint, webmention_blog_url(@blog) - unless @prev.nil? .back-post= link_to "← #{@prev.title}", @prev - unless @next.nil? diff --git a/app/views/layouts/application.html.haml b/app/views/layouts/application.html.haml index 69cd6ba..ec37f73 100644 --- a/app/views/layouts/application.html.haml +++ b/app/views/layouts/application.html.haml @@ -6,6 +6,8 @@ = stylesheet_link_tag 'main', media: 'all', 'data-turbolinks-track': 'reload' = javascript_include_tag 'application', 'data-turbolinks-track': 'reload' = display_meta_tags og: { site_name: "Four Island" } + - if content_for?(:webmention_endpoint) + %link{rel: "webmention", href: yield(:webmention_endpoint)} %body#main-body - if flash[:alert] %div#flash.flash-alert= flash[:alert] -- cgit 1.4.1