DEV: move to an ember component

This commit is contained in:
Joffrey JAFFEUX 2024-12-13 17:00:17 +01:00
parent df21bc6e73
commit 66ec74bf2b
24 changed files with 101 additions and 150 deletions

View File

@ -4,9 +4,4 @@ Display stats on your last year of Discourse usage.
## Usage
- add `http://127.0.0.1:4200/rewinds?` in `SiteSetting.allowed_iframes`
- example embed of a rewind in a post:
```
<iframe src="http://127.0.0.1:4200/rewinds?year=2024&username=j.jaffeux" width="320" height="500" frameborder="0" style="border:0;" allowfullscreen="" aria-hidden="false" tabindex="0" />
```
Navigate to `/my/activity/rewind`

View File

@ -1,32 +0,0 @@
# frozen_string_literal: true
module ::DiscourseRewind
class RewindsAssetsController < ::ApplicationController
requires_plugin PLUGIN_NAME
skip_before_action :preload_json, :check_xhr, only: %i[show]
skip_before_action :verify_authenticity_token, only: %i[show]
def show
no_cookies
name = params[:name]
path, content_type =
if name == "rewind"
%w[rewind.css text/css]
else
raise Discourse::NotFound
end
content = File.read(DiscourseRewind.public_asset_path("css/#{path}"))
# note, path contains a ":version" which automatically busts the cache
# based on file content, so this is safe
response.headers["Last-Modified"] = 10.years.ago.httpdate
response.headers["Content-Length"] = content.bytesize.to_s
immutable_for 1.year
render plain: content, disposition: :nil, content_type: content_type
end
end
end

View File

@ -4,16 +4,11 @@ module ::DiscourseRewind
class RewindsController < ::ApplicationController
requires_plugin PLUGIN_NAME
skip_before_action :preload_json, :check_xhr, :redirect_to_login_if_required, only: %i[show]
def show
# expires_in 1.minute, public: false
response.headers["X-Robots-Tag"] = "noindex"
DiscourseRewind::Rewind::Fetch.call(service_params) do
on_success do |reports:|
@reports = reports
render "show", layout: false
render json: MultiJson.dump(reports), status: 200
end
end
end

View File

@ -1,25 +0,0 @@
# frozen_string_literal: true
module DiscourseRewind
module RewindsHelper
# keeping it here for caching
def self.rewind_asset_url(asset_name)
if !%w[rewind.css].include?(asset_name)
raise StandardError, "unknown asset type #{asset_name}"
end
@urls ||= {}
url = @urls[asset_name]
return url if url
content = File.read(DiscourseRewind.public_asset_path("css/#{asset_name}"))
sha1 = Digest::SHA1.hexdigest(content)
url = "/rewinds/assets/#{sha1}/#{asset_name}"
@urls[asset_name] = GlobalPath.cdn_path(url)
end
def rewind_asset_url(asset_name)
DiscourseRewind::RewindsHelper.rewind_asset_url(asset_name)
end
end
end

View File

@ -1,7 +1,7 @@
# frozen_string_literal: true
module DiscourseRewind
class Rewind::Action::Base < Service::ActionBase
class Rewind::Action::BaseReport < Service::ActionBase
option :user
option :date
@ -9,7 +9,7 @@ module DiscourseRewind
raise NotImplementedError
end
def enabled?
def self.enabled?
true
end
end

View File

@ -3,7 +3,7 @@
# Forum Best Friend Forever ranking
# Score is informative only, do not show in UI
module DiscourseRewind
class Rewind::Action::Fbff < Action::Base
class Rewind::Action::Fbff < Rewind::Action::BaseReport
MAX_SUMMARY_RESULTS = 50
LIKE_SCORE = 1
REPLY_SCORE = 10

View File

@ -3,7 +3,7 @@
# For a GitHub like calendar
# https://docs.github.com/assets/cb-35216/mw-1440/images/help/profile/contributions-graph.webp
module DiscourseRewind
class Rewind::Action::PostingCalendar < Action::Base
class Rewind::Action::PostingCalendar < Rewind::Action::BaseReport
def call
calendar =
Post

View File

@ -2,7 +2,7 @@
# For a most user / received reactions cards
module DiscourseRewind
class Rewind::Action::Reactions < Action::Base
class Rewind::Action::Reactions < Rewind::Action::BaseReport
def call
post_used_reactions = {}
post_received_reactions = {}

View File

@ -3,9 +3,9 @@
# For showcasing the reading time of a user
# Should we show book covers or just the names?
module DiscourseRewind
class Rewind::Action::ReadingTime < Action::Base
class Rewind::Action::ReadingTime < Rewind::Action::BaseReport
def call
reading_time = UserVisit.where(user: user).where(visited_at: date).sum(:time_read)
reading_time = UserVisit.where(user_id: user.id).where(visited_at: date).sum(:time_read)
{
data: {
@ -38,7 +38,7 @@ module DiscourseRewind
"And Then There Were None" => 16_200,
"The Alchemist" => 10_800,
"The Hitchhiker's Guide to the Galaxy" => 12_600,
}
}.symbolize_keys
end
def best_book_fit(reading_time)

View File

@ -5,11 +5,7 @@ module DiscourseRewind
#
# @example
# ::DiscourseRewind::Rewind::Fetch.call(
# guardian: guardian,
# params: {
# username: "falco",
# year: 2024,
# }
# guardian: guardian
# )
#
class Rewind::Fetch
@ -22,18 +18,9 @@ module DiscourseRewind
# @option params [Integer] :username of the rewind
# @return [Service::Base::Context]
# Do we need a custom order?
available_reports = DiscourseRewind::Rewind::Action::Base.descendants
CACHE_DURATION = 5.minutes
params do
attribute :year, :integer
attribute :username, :string
validates :year, presence: true
validates :username, presence: true
end
YEAR = 2024
model :user
model :date
@ -41,23 +28,24 @@ module DiscourseRewind
private
def fetch_user(params:)
User.find_by_username(params.username)
def fetch_user(guardian:)
User.find_by_username(guardian.user.username)
end
def fetch_date(params:)
Date.new(params.year).all_year
Date.new(YEAR).all_year
end
def fetch_reports(params:, date:, user:, guardian:)
key = "rewind:#{params.username}:#{params.year}"
def fetch_reports(date:, user:, guardian:)
key = "rewind:#{guardian.user.username}:#{YEAR}"
reports = Discourse.redis.get(key)
if Rails.env.development? || !reports
reports =
available_reports
::DiscourseRewind::Rewind::Action::BaseReport
.descendants
.filter { _1.enabled? }
.map { |report| report.call(params:, date:, user:, guardian:) }
.map { |report| report.call(date:, user:, guardian:) }
Discourse.redis.setex(key, CACHE_DURATION, MultiJson.dump(reports))
else
reports = MultiJson.load(reports, symbolize_keys: true)

View File

@ -1,31 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<title><%= I18n.t("discourse_rewind.title", title: "RETRO TITLE", site_name: SiteSetting.title) %></title>
<meta property="og:title" content="<%= I18n.t("discourse_rewind.title", title: "RETRO TITLE", site_name: SiteSetting.title) %>">
<meta property="og:description" content="DESC">
<meta property="og:type" content="website">
<meta property="og:url" content="<%= request.original_url %>">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="<%= I18n.t("discourse_rewind.title", title: "RETRO TITLE", site_name: SiteSetting.title) %>">
<meta name="twitter:description" content="DESC">
<meta name="viewport" content="width=device-width">
<link rel="stylesheet" href="<%= rewind_asset_url("rewind.css") %>">
</head>
<body>
<div class="rewind__wrapper">
<div class="rewind">
<%- @reports.each do |report| %>
<div class="rewind__report">
<div class="rewind__report__header">
<%= report[:identifier] %>
</div>
<div class="rewind__report__body">
<%= report[:data][:count] %>
</div>
</div>
<%- end %>
</div>
</div>
</body>
</html>

View File

@ -0,0 +1,27 @@
import Component from "@glimmer/component";
import { tracked } from "@glimmer/tracking";
import { action } from "@ember/object";
import didInsert from "@ember/render-modifiers/modifiers/did-insert";
import { ajax } from "discourse/lib/ajax";
import { popupAjaxError } from "discourse/lib/ajax-error";
export default class Rewind extends Component {
@tracked rewind = [];
@action
async loadRewind() {
try {
this.rewind = await ajax("/rewinds");
} catch (e) {
popupAjaxError(e);
}
}
<template>
<div class="rewind" {{didInsert this.loadRewind}}>
{{#each this.rewind as |report|}}
<p>{{report.identifier}}</p>
{{/each}}
</div>
</template>
}

View File

@ -0,0 +1,17 @@
import Component from "@glimmer/component";
import DNavigationItem from "discourse/components/d-navigation-item";
import icon from "discourse-common/helpers/d-icon";
import { i18n } from "discourse-i18n";
export default class RewindTab extends Component {
<template>
<DNavigationItem
@route="userActivity.rewind"
@ariaCurrentContext="subNav"
class="user-nav__activity-rewind"
>
{{icon "repeat"}}
<span>{{i18n "rewind.title"}}</span>
</DNavigationItem>
</template>
}

View File

@ -0,0 +1,11 @@
export default function () {
this.route(
"user",
{ path: "/u/:username", resetNamespace: true },
function () {
this.route("userActivity", function () {
this.route("rewind");
});
}
);
}

View File

@ -0,0 +1,5 @@
import DiscourseRoute from "discourse/routes/discourse";
export default class UserActivityRewind extends DiscourseRoute {
templateName = "user/rewind";
}

View File

@ -0,0 +1 @@
<Rewind />

View File

@ -0,0 +1 @@
@import "rewind";

View File

@ -0,0 +1,6 @@
.rewind {
width: 280px;
height: 400px;
background-color: var(--secondary-high);
border-radius: var(--d-border-radius);
}

View File

View File

View File

@ -1,8 +1,5 @@
# frozen_string_literal: true
DiscourseRewind::Engine.routes.draw do
get "/rewinds" => "rewinds#show"
get "/rewinds/assets/:version/:name" => "rewinds_assets#show"
end
DiscourseRewind::Engine.routes.draw { get "/rewinds" => "rewinds#show" }
Discourse::Application.routes.draw { mount ::DiscourseRewind::Engine, at: "/" }

View File

@ -9,5 +9,11 @@ module ::DiscourseRewind
config.to_prepare do
Rails.autoloaders.main.eager_load_dir(scheduled_job_dir) if Dir.exist?(scheduled_job_dir)
end
Rails.application.reloader.to_prepare do
Dir[
"#{Rails.root}/plugins/discourse-rewind/app/services/discourse_rewind/rewind/action/*.rb"
].each { |file| require_dependency file }
end
end
end

View File

@ -10,6 +10,12 @@
enabled_site_setting :discourse_rewind_enabled
register_svg_icon "repeat"
register_asset "stylesheets/common/index.scss"
register_asset "stylesheets/desktop/index.scss", :desktop
register_asset "stylesheets/mobile/index.scss", :mobile
module ::DiscourseRewind
PLUGIN_NAME = "discourse-rewind"

View File

@ -1,16 +0,0 @@
/* RESET CSS */
*, *::before, *::after { box-sizing: border-box; }
* { margin: 0; padding: 0; }
ul[role='list'], ol[role='list'] { list-style: none; }
html:focus-within { scroll-behavior: smooth; }
a:not([class]) { text-decoration-skip-ink: auto; }
input, button, textarea, select { font: inherit; }
body, html { height: 100%; scroll-behavior: smooth; }
/* END RESET CSS */
.rewind {
display: flex;
height: 100vh;
background-color: #f5f5f5;
border-radius: 5px;
}