rss feed and download stats
This commit is contained in:
@@ -0,0 +1,11 @@
|
||||
class Api::RssController < ApiController
|
||||
def blog
|
||||
xml = RssService.new.blog_feed
|
||||
render xml: xml, content_type: "application/rss+xml"
|
||||
end
|
||||
|
||||
def releases
|
||||
xml = RssService.new.releases_feed
|
||||
render xml: xml, content_type: "application/rss+xml"
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,23 @@
|
||||
class DownloadsController < ApplicationController
|
||||
skip_forgery_protection
|
||||
|
||||
def show
|
||||
path = params[:path]
|
||||
return head :bad_request if path.blank?
|
||||
|
||||
full_path = DownloadService.new.call(
|
||||
path: path,
|
||||
ip: request.remote_ip,
|
||||
user_agent: request.user_agent,
|
||||
referer: request.referer
|
||||
)
|
||||
|
||||
if full_path
|
||||
ext = File.extname(full_path.to_s).delete_prefix(".")
|
||||
mime = Mime::Type.lookup_by_extension(ext) || "application/octet-stream"
|
||||
send_file full_path, disposition: "attachment", type: mime
|
||||
else
|
||||
head :not_found
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,5 @@
|
||||
class Download < ApplicationRecord
|
||||
belongs_to :release, optional: true
|
||||
|
||||
validates :file_path, presence: true
|
||||
end
|
||||
@@ -2,6 +2,7 @@ class Release < ApplicationRecord
|
||||
self.table_name = "releases"
|
||||
|
||||
belongs_to :software
|
||||
has_many :downloads
|
||||
|
||||
default_scope { where(deleted_at: nil) }
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ class Software < ApplicationRecord
|
||||
has_many :software_images, foreign_key: :software_id, dependent: :destroy
|
||||
has_many :images, through: :software_images
|
||||
has_many :releases, foreign_key: :software_id
|
||||
has_many :downloads, through: :releases
|
||||
has_many :external_links, foreign_key: :software_id
|
||||
|
||||
accepts_nested_attributes_for :software_images, allow_destroy: true
|
||||
|
||||
@@ -14,4 +14,5 @@ class ReleaseSerializer < Blueprinter::Base
|
||||
field(:sourcePath) { |r| r.source_path.blank? ? "" : r.source_path.gsub(FILE_PATH_FROM, FILE_PATH_TO) }
|
||||
field(:htmlFolderPath) { |r| r.html_folder_path.blank? ? "" : r.html_folder_path.gsub(FILE_PATH_FROM, FILE_PATH_TO) }
|
||||
field(:docsFolderPath) { |r| r.docs_folder_path.blank? ? "" : r.docs_folder_path.gsub(FILE_PATH_FROM, FILE_PATH_TO) }
|
||||
field(:downloadCount) { |r| r.downloads.size }
|
||||
end
|
||||
|
||||
@@ -3,4 +3,5 @@ class SoftwareDetailSerializer < Blueprinter::Base
|
||||
field(:releases) { |_, opts| ReleaseSerializer.render_as_hash(opts[:releases]) }
|
||||
field(:latestRelease) { |_, opts| opts[:latest] ? ReleaseSerializer.render_as_hash(opts[:latest]) : nil }
|
||||
field(:webPlayableRelease) { |_, opts| opts[:web_playable] ? ReleaseSerializer.render_as_hash(opts[:web_playable]) : nil }
|
||||
field(:totalDownloads) { |sw, _| Download.where(release: sw.releases).count }
|
||||
end
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
class DownloadService
|
||||
BASE_PATH = Pathname.new(ENV.fetch("FILE_CONTAINER_PATH", "/softwares")).realpath
|
||||
|
||||
def call(path:, ip:, user_agent:, referer:)
|
||||
full_path = BASE_PATH.join(path.to_s)
|
||||
return nil unless File.file?(full_path)
|
||||
|
||||
release = Release.find_by("cartridge_path LIKE ? OR source_path LIKE ?",
|
||||
"%#{path}%", "%#{path}%")
|
||||
|
||||
Download.create!(
|
||||
file_path: path,
|
||||
release: release,
|
||||
ip_address: ip,
|
||||
user_agent: user_agent&.truncate(500),
|
||||
referer: referer&.truncate(500)
|
||||
)
|
||||
|
||||
full_path
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,51 @@
|
||||
require "rss"
|
||||
|
||||
class RssService
|
||||
SITE_URL = ENV.fetch("SITE_URL", "https://teletypegames.hu").freeze
|
||||
|
||||
def blog_feed
|
||||
pages = WikiService.new.pages(tag: "blog", limit: 30)
|
||||
items = pages.fetch("pages", [])
|
||||
|
||||
RSS::Maker.make("2.0") do |maker|
|
||||
maker.channel.title = "Teletype Games Blog"
|
||||
maker.channel.link = "#{SITE_URL}/blog"
|
||||
maker.channel.description = "Latest blog posts from Teletype Games"
|
||||
maker.channel.language = "hu"
|
||||
|
||||
items.each do |page|
|
||||
maker.items.new_item do |item|
|
||||
item.title = page["title"]
|
||||
item.link = "#{SITE_URL}/blog/#{page["route"]}"
|
||||
item.description = page["description"].to_s
|
||||
item.pubDate = Time.parse(page["createdAt"]) rescue Time.current
|
||||
end
|
||||
end
|
||||
end.to_s
|
||||
end
|
||||
|
||||
def releases_feed
|
||||
releases = Release.includes(:software)
|
||||
.order(created_at: :desc)
|
||||
.limit(50)
|
||||
|
||||
RSS::Maker.make("2.0") do |maker|
|
||||
maker.channel.title = "Teletype Games Releases"
|
||||
maker.channel.link = "#{SITE_URL}/catalog"
|
||||
maker.channel.description = "Latest game releases from Teletype Games"
|
||||
maker.channel.language = "hu"
|
||||
|
||||
releases.each do |release|
|
||||
sw = release.software
|
||||
next unless sw
|
||||
|
||||
maker.items.new_item do |item|
|
||||
item.title = "#{sw.title} v#{release.version}"
|
||||
item.link = "#{SITE_URL}/catalog/#{sw.name}"
|
||||
item.description = "#{sw.title} #{release.version} released – #{sw.desc}"
|
||||
item.pubDate = release.created_at
|
||||
end
|
||||
end
|
||||
end.to_s
|
||||
end
|
||||
end
|
||||
@@ -8,7 +8,7 @@ class SoftwareHighlightedService
|
||||
.first
|
||||
return nil unless software
|
||||
|
||||
releases = Release.where(software_id: software.id).to_a
|
||||
releases = Release.includes(:downloads).where(software_id: software.id).to_a
|
||||
build_response(software, releases)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -2,7 +2,7 @@ class SoftwareService
|
||||
include SoftwareResponseBuilder
|
||||
|
||||
def index
|
||||
softwares = Software.includes(:releases, :external_links, :software_images).all
|
||||
softwares = Software.includes(releases: :downloads).includes(:external_links, :software_images).all
|
||||
{ softwares: softwares.map { |sw| build_response(sw, sw.releases.to_a) } }
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user