diff --git a/apps/api/app/controllers/api/rss_controller.rb b/apps/api/app/controllers/api/rss_controller.rb index f48b444..ddd2dfa 100644 --- a/apps/api/app/controllers/api/rss_controller.rb +++ b/apps/api/app/controllers/api/rss_controller.rb @@ -7,21 +7,21 @@ class Api::RssController < ApiController api :GET, "/api/rss/blog", "Blog RSS feed" returns code: 200, desc: "RSS XML feed of blog posts" def blog - xml = RssService.new.blog_feed + xml = Rss::BlogFeed.new.xml render xml: xml, content_type: "application/rss+xml" end api :GET, "/api/rss/releases", "Software releases RSS feed" returns code: 200, desc: "RSS XML feed of software releases" def releases - xml = RssService.new.releases_feed + xml = Rss::ReleasesFeed.new.xml render xml: xml, content_type: "application/rss+xml" end api :GET, "/api/rss/howtos", "HowTos RSS feed" returns code: 200, desc: "RSS XML feed of tech howtos" def howtos - xml = RssService.new.howtos_feed + xml = Rss::HowtosFeed.new.xml render xml: xml, content_type: "application/rss+xml" end end diff --git a/apps/api/app/controllers/api/wiki_controller.rb b/apps/api/app/controllers/api/wiki_controller.rb index 3789263..fe362ef 100644 --- a/apps/api/app/controllers/api/wiki_controller.rb +++ b/apps/api/app/controllers/api/wiki_controller.rb @@ -28,7 +28,7 @@ class Api::WikiController < ApiController end def index - render json: WikiService.new.index( + render json: Wiki::Pages.new.fetch( tag: params[:tag], limit: params[:limit], body: params[:body] diff --git a/apps/api/app/controllers/application_controller.rb b/apps/api/app/controllers/application_controller.rb index 1c07694..8dba3f4 100644 --- a/apps/api/app/controllers/application_controller.rb +++ b/apps/api/app/controllers/application_controller.rb @@ -1,3 +1,5 @@ class ApplicationController < ActionController::Base + include SyncsAdminCookie + protect_from_forgery with: :exception end diff --git a/apps/api/app/controllers/concerns/syncs_admin_cookie.rb b/apps/api/app/controllers/concerns/syncs_admin_cookie.rb new file mode 100644 index 0000000..388d580 --- /dev/null +++ b/apps/api/app/controllers/concerns/syncs_admin_cookie.rb @@ -0,0 +1,17 @@ +module SyncsAdminCookie + extend ActiveSupport::Concern + + included do + after_action :sync_admin_cookie + end + + private + + def sync_admin_cookie + if current_admin_user + cookies[:is_admin] = { value: "1", httponly: false, same_site: :lax, path: "/" } + elsif cookies[:is_admin] + cookies.delete(:is_admin, path: "/") + end + end +end diff --git a/apps/api/app/services/rss/blog_feed.rb b/apps/api/app/services/rss/blog_feed.rb new file mode 100644 index 0000000..e283db5 --- /dev/null +++ b/apps/api/app/services/rss/blog_feed.rb @@ -0,0 +1,20 @@ +module Rss + class BlogFeed < Feed + private + + def title = "Teletype Games Blog" + def link = "#{site_url}/blog" + def description = "Latest blog posts from Teletype Games" + + def items + Wiki::Pages.new.all(tag: "blog", limit: 30).map do |page| + { + title: page["title"], + link: "#{site_url}/blog/#{page['route']}", + description: page["description"], + published_at: parse_time(page["createdAt"]) + } + end + end + end +end diff --git a/apps/api/app/services/rss/feed.rb b/apps/api/app/services/rss/feed.rb new file mode 100644 index 0000000..c8c2b11 --- /dev/null +++ b/apps/api/app/services/rss/feed.rb @@ -0,0 +1,35 @@ +require "rss" + +module Rss + class Feed + def xml + RSS::Maker.make("2.0") do |maker| + maker.channel.title = title + maker.channel.link = link + maker.channel.description = description + maker.channel.language = "hu" + + items.each do |item| + maker.items.new_item do |rss_item| + rss_item.title = item[:title] + rss_item.link = item[:link] + rss_item.description = item[:description].to_s + rss_item.pubDate = item[:published_at] + end + end + end.to_s + end + + private + + def site_url = Rails.configuration.x.site_url + + def wiki_url = Rails.configuration.x.wiki_url + + def parse_time(value) + Time.parse(value.to_s) + rescue ArgumentError, TypeError + Time.current + end + end +end diff --git a/apps/api/app/services/rss/howtos_feed.rb b/apps/api/app/services/rss/howtos_feed.rb new file mode 100644 index 0000000..d6a9b93 --- /dev/null +++ b/apps/api/app/services/rss/howtos_feed.rb @@ -0,0 +1,20 @@ +module Rss + class HowtosFeed < Feed + private + + def title = "Teletype Games HowTos" + def link = "#{site_url}/howtos" + def description = "Latest tech howtos from Teletype Games" + + def items + Wiki::Pages.new.all(tag: "howto", limit: 30).map do |page| + { + title: page["title"], + link: "#{wiki_url}/#{page['path']}", + description: page["description"], + published_at: parse_time(page["createdAt"]) + } + end + end + end +end diff --git a/apps/api/app/services/rss/releases_feed.rb b/apps/api/app/services/rss/releases_feed.rb new file mode 100644 index 0000000..e845268 --- /dev/null +++ b/apps/api/app/services/rss/releases_feed.rb @@ -0,0 +1,23 @@ +module Rss + class ReleasesFeed < Feed + private + + def title = "Teletype Games Releases" + def link = "#{site_url}/catalog" + def description = "Latest game releases from Teletype Games" + + def items + WarpEngine::Release.includes(:software).order(created_at: :desc).limit(50).filter_map do |release| + software = release.software + next if software.nil? + + { + title: "#{software.title} v#{release.version}", + link: "#{site_url}/catalog/#{software.name}", + description: "#{software.title} #{release.version} released – #{software.desc}", + published_at: release.created_at.to_time + } + end + end + end +end diff --git a/apps/api/app/services/rss_service.rb b/apps/api/app/services/rss_service.rb deleted file mode 100644 index 9bbe087..0000000 --- a/apps/api/app/services/rss_service.rb +++ /dev/null @@ -1,73 +0,0 @@ -require "rss" - -class RssService - SITE_URL = ENV.fetch("SITE_URL", "https://teletypegames.org").freeze - WIKI_URL = ENV.fetch("WIKI_URL", "https://wiki.teletypegames.org").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 = WarpEngine::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.to_time - end - end - end.to_s - end - - def howtos_feed - pages = WikiService.new.pages(tag: "howto", limit: 30) - items = pages.fetch("pages", []) - - RSS::Maker.make("2.0") do |maker| - maker.channel.title = "Teletype Games HowTos" - maker.channel.link = "#{SITE_URL}/howtos" - maker.channel.description = "Latest tech howtos from Teletype Games" - maker.channel.language = "hu" - - items.each do |page| - maker.items.new_item do |item| - item.title = page["title"] - item.link = "#{WIKI_URL}/#{page["path"]}" - item.description = page["description"].to_s - item.pubDate = Time.parse(page["createdAt"]) rescue Time.current - end - end - end.to_s - end -end diff --git a/apps/api/app/services/wiki/pages.rb b/apps/api/app/services/wiki/pages.rb new file mode 100644 index 0000000..53f04d1 --- /dev/null +++ b/apps/api/app/services/wiki/pages.rb @@ -0,0 +1,37 @@ +require "net/http" +require "json" + +module Wiki + class Pages + def fetch(tag:, limit: nil, body: nil) + query = { tag: tag } + query[:limit] = limit if limit.present? + query[:body] = body if body.present? + + uri = URI.parse("#{Rails.configuration.x.wiki_url}/custom/pages.json") + uri.query = URI.encode_www_form(query) + + response = Net::HTTP.start( + uri.host, uri.port, + use_ssl: uri.scheme == "https", + open_timeout: 5, read_timeout: 10 + ) { |http| http.get(uri.request_uri) } + + return empty(tag, "grav responded #{response.code}") unless response.is_a?(Net::HTTPSuccess) + + JSON.parse(response.body) + rescue StandardError => e + empty(tag, e.message) + end + + def all(tag:, limit: nil) + fetch(tag: tag, limit: limit).fetch("pages", []) + end + + private + + def empty(tag, error) + { "tag" => tag, "count" => 0, "pages" => [], "error" => error } + end + end +end diff --git a/apps/api/app/services/wiki_service.rb b/apps/api/app/services/wiki_service.rb deleted file mode 100644 index d9a9ddc..0000000 --- a/apps/api/app/services/wiki_service.rb +++ /dev/null @@ -1,31 +0,0 @@ -require "net/http" -require "json" - -class WikiService - GRAV_URL = ENV.fetch("WIKI_GRAV_URL", "http://localhost:8080").freeze - - def index(tag:, limit: nil, body: nil) - query = { tag: tag } - query[:limit] = limit if limit.present? - query[:body] = body if body.present? - - uri = URI.parse("#{GRAV_URL}/custom/pages.json") - uri.query = URI.encode_www_form(query) - - response = Net::HTTP.start( - uri.host, uri.port, - use_ssl: uri.scheme == "https", - open_timeout: 5, read_timeout: 10 - ) { |http| http.get(uri.request_uri) } - - unless response.is_a?(Net::HTTPSuccess) - return { "tag" => tag, "count" => 0, "pages" => [], "error" => "grav responded #{response.code}" } - end - - JSON.parse(response.body) - rescue StandardError => e - { "tag" => tag, "count" => 0, "pages" => [], "error" => e.message } - end - - alias_method :pages, :index -end diff --git a/apps/api/config/application.rb b/apps/api/config/application.rb index 01834f8..3b0cd57 100644 --- a/apps/api/config/application.rb +++ b/apps/api/config/application.rb @@ -25,5 +25,9 @@ module Api config.action_controller.forgery_protection_origin_check = false config.autoload_lib(ignore: %w[assets tasks]) + + config.x.site_url = ENV.fetch("SITE_URL", "https://teletypegames.org") + config.x.wiki_url = ENV.fetch("WIKI_GRAV_URL", "https://wiki.teletypegames.org") + config.x.images.container_path = ENV.fetch("IMAGE_CONTAINER_PATH", "/images") end end diff --git a/apps/api/config/initializers/admin_cookie.rb b/apps/api/config/initializers/admin_cookie.rb deleted file mode 100644 index 89d3a48..0000000 --- a/apps/api/config/initializers/admin_cookie.rb +++ /dev/null @@ -1,15 +0,0 @@ -Rails.application.config.to_prepare do - ApplicationController.class_eval do - after_action :sync_admin_cookie - - private - - def sync_admin_cookie - if current_admin_user - cookies[:is_admin] = { value: "1", httponly: false, same_site: :lax, path: "/" } - elsif cookies[:is_admin] - cookies.delete(:is_admin, path: "/") - end - end - end -end diff --git a/apps/api/config/initializers/warp_engine.rb b/apps/api/config/initializers/warp_engine.rb index fac7e14..17d45a8 100644 --- a/apps/api/config/initializers/warp_engine.rb +++ b/apps/api/config/initializers/warp_engine.rb @@ -6,6 +6,8 @@ Rails.application.config.to_prepare do c.image_class_name = "Image" + c.site_url = Rails.configuration.x.site_url + c.ci_adapter = WarpEngine::CI::Woodpecker::Adapter.new( url: ENV["WOODPECKER_URL"], api_token: ENV["WOODPECKER_API_TOKEN"], diff --git a/libs/ruby/warp_engine/lib/warp_engine/configuration.rb b/libs/ruby/warp_engine/lib/warp_engine/configuration.rb index 91d41f6..63c2bae 100644 --- a/libs/ruby/warp_engine/lib/warp_engine/configuration.rb +++ b/libs/ruby/warp_engine/lib/warp_engine/configuration.rb @@ -1,7 +1,8 @@ module WarpEngine class Configuration - attr_accessor :file_container_path, + attr_accessor :site_url, + :file_container_path, :update_secret, :application_token_source, :application_token_owner_class, @@ -19,6 +20,7 @@ module WarpEngine :device_code_interval def initialize + @site_url = nil @file_container_path = ENV.fetch("FILE_CONTAINER_PATH", "/softwares") @update_secret = ENV["UPDATE_SECRET"] @application_token_source = :env