allow users with admin:metrics to read app metrics
Some checks are pending
ci/woodpecker/push/woodpecker Pipeline is pending
Some checks are pending
ci/woodpecker/push/woodpecker Pipeline is pending
This commit is contained in:
parent
b8be8192fb
commit
c2054f82ab
14 changed files with 283 additions and 44 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -76,3 +76,4 @@ docs/site
|
||||||
|
|
||||||
# docker stuff
|
# docker stuff
|
||||||
docker-db
|
docker-db
|
||||||
|
*.iml
|
||||||
|
|
|
@ -3,9 +3,13 @@ defmodule Pleroma.Web.AkkomaAPI.MetricsController do
|
||||||
|
|
||||||
alias Pleroma.Web.Plugs.OAuthScopesPlug
|
alias Pleroma.Web.Plugs.OAuthScopesPlug
|
||||||
|
|
||||||
@unauthenticated_access %{fallback: :proceed_unauthenticated, scopes: []}
|
plug(
|
||||||
plug(:skip_auth)
|
OAuthScopesPlug,
|
||||||
|
%{scopes: ["admin:metrics"]}
|
||||||
|
when action in [
|
||||||
|
:show
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
def show(conn, _params) do
|
def show(conn, _params) do
|
||||||
stats = TelemetryMetricsPrometheus.Core.scrape()
|
stats = TelemetryMetricsPrometheus.Core.scrape()
|
||||||
|
|
|
@ -197,7 +197,11 @@ defp incorporate_conn_info(action_settings, %{params: params} = conn) do
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
defp ip(%{remote_ip: remote_ip}) do
|
defp ip(%{remote_ip: remote_ip}) when is_binary(remote_ip) do
|
||||||
|
remote_ip
|
||||||
|
end
|
||||||
|
|
||||||
|
defp ip(%{remote_ip: remote_ip}) when is_tuple(remote_ip) do
|
||||||
remote_ip
|
remote_ip
|
||||||
|> Tuple.to_list()
|
|> Tuple.to_list()
|
||||||
|> Enum.join(".")
|
|> Enum.join(".")
|
||||||
|
|
|
@ -868,7 +868,11 @@ defmodule Pleroma.Web.Router do
|
||||||
|
|
||||||
scope "/" do
|
scope "/" do
|
||||||
pipe_through([:pleroma_html, :authenticate, :require_admin])
|
pipe_through([:pleroma_html, :authenticate, :require_admin])
|
||||||
live_dashboard("/phoenix/live_dashboard", metrics: {Pleroma.Web.Telemetry, :live_dashboard_metrics}, csp_nonce_assign_key: :csp_nonce)
|
|
||||||
|
live_dashboard("/phoenix/live_dashboard",
|
||||||
|
metrics: {Pleroma.Web.Telemetry, :live_dashboard_metrics},
|
||||||
|
csp_nonce_assign_key: :csp_nonce
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Test-only routes needed to test action dispatching and plug chain execution
|
# Test-only routes needed to test action dispatching and plug chain execution
|
||||||
|
@ -907,6 +911,7 @@ defmodule Pleroma.Web.Router do
|
||||||
scope "/", Pleroma.Web.Fallback do
|
scope "/", Pleroma.Web.Fallback do
|
||||||
get("/registration/:token", RedirectController, :registration_page)
|
get("/registration/:token", RedirectController, :registration_page)
|
||||||
get("/:maybe_nickname_or_id", RedirectController, :redirector_with_meta)
|
get("/:maybe_nickname_or_id", RedirectController, :redirector_with_meta)
|
||||||
|
get("/api/*path", RedirectController, :api_not_implemented)
|
||||||
get("/*path", RedirectController, :redirector_with_preload)
|
get("/*path", RedirectController, :redirector_with_preload)
|
||||||
|
|
||||||
options("/*path", RedirectController, :empty)
|
options("/*path", RedirectController, :empty)
|
||||||
|
|
|
@ -11,16 +11,13 @@ def start_link(arg) do
|
||||||
def init(_arg) do
|
def init(_arg) do
|
||||||
children = [
|
children = [
|
||||||
{:telemetry_poller, measurements: periodic_measurements(), period: 10_000},
|
{:telemetry_poller, measurements: periodic_measurements(), period: 10_000},
|
||||||
{TelemetryMetricsPrometheus, metrics: prometheus_metrics(), plug_cowboy_opts: [ip: {127, 0, 0, 1}]}
|
{TelemetryMetricsPrometheus.Core, metrics: prometheus_metrics()}
|
||||||
]
|
]
|
||||||
|
|
||||||
Supervisor.init(children, strategy: :one_for_one)
|
Supervisor.init(children, strategy: :one_for_one)
|
||||||
end
|
end
|
||||||
|
|
||||||
@doc """
|
# A seperate set of metrics for distributions because phoenix dashboard does NOT handle them well
|
||||||
A seperate set of metrics for distributions because phoenix dashboard does NOT handle
|
|
||||||
them well
|
|
||||||
"""
|
|
||||||
defp distribution_metrics do
|
defp distribution_metrics do
|
||||||
[
|
[
|
||||||
distribution(
|
distribution(
|
||||||
|
@ -110,8 +107,6 @@ defp summary_metrics do
|
||||||
summary("vm.total_run_queue_lengths.total"),
|
summary("vm.total_run_queue_lengths.total"),
|
||||||
summary("vm.total_run_queue_lengths.cpu"),
|
summary("vm.total_run_queue_lengths.cpu"),
|
||||||
summary("vm.total_run_queue_lengths.io"),
|
summary("vm.total_run_queue_lengths.io"),
|
||||||
|
|
||||||
|
|
||||||
last_value("pleroma.local_users.total"),
|
last_value("pleroma.local_users.total"),
|
||||||
last_value("pleroma.domains.total"),
|
last_value("pleroma.domains.total"),
|
||||||
last_value("pleroma.local_statuses.total")
|
last_value("pleroma.local_statuses.total")
|
||||||
|
|
|
@ -4,17 +4,33 @@
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width,initial-scale=1,minimal-ui">
|
<meta name="viewport" content="width=device-width,initial-scale=1,minimal-ui">
|
||||||
<title><%= Pleroma.Config.get([:instance, :name]) %></title>
|
<title><%= Pleroma.Config.get([:instance, :name]) %></title>
|
||||||
<link rel="stylesheet" href="/instance/static.css">
|
<link rel="stylesheet" href="/static-fe/static-fe.css">
|
||||||
|
<link rel="stylesheet" href="/static-fe/forms.css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div class="instance-header">
|
|
||||||
<a class="instance-header__content" href="/">
|
<div class="background-image"></div>
|
||||||
<img class="instance-header__thumbnail" src="<%= Pleroma.Config.get([:instance, :instance_thumbnail]) %>">
|
<nav>
|
||||||
<h1 class="instance-header__title"><%= Pleroma.Config.get([:instance, :name]) %></h1>
|
<div class="inner-nav">
|
||||||
</a>
|
<a class="site-brand" href="/">
|
||||||
</div>
|
<img class="favicon" src="/favicon.png" />
|
||||||
|
<span><%= Pleroma.Config.get([:instance, :name]) %></span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<%= @inner_content %>
|
<div class="underlay"></div>
|
||||||
|
<div class="column main flex">
|
||||||
|
<div class="panel oauth">
|
||||||
|
<%= @inner_content %>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
:root {
|
||||||
|
--background-image: url("<%= Pleroma.Config.get([:instance, :background_image]) %>");
|
||||||
|
}
|
||||||
|
</style>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -20,8 +20,8 @@
|
||||||
</nav>
|
</nav>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="underlay"></div>
|
<div class="underlay"></div>
|
||||||
<div class="column main">
|
<div class="column main">
|
||||||
<%= @inner_content %>
|
<%= @inner_content %>
|
||||||
</div>
|
</div>
|
||||||
<div class="column sidebar">
|
<div class="column sidebar">
|
||||||
<div class="about panel">
|
<div class="about panel">
|
||||||
|
|
|
@ -1,2 +1,8 @@
|
||||||
<h1><%= Gettext.dpgettext("static_pages", "oauth authorized page title", "Successfully authorized") %></h1>
|
<div>
|
||||||
<h2><%= raw Gettext.dpgettext("static_pages", "oauth token code message", "Token code is <br>%{token}", token: safe_to_string(html_escape(@auth.token))) %></h2>
|
<div class="panel-heading">
|
||||||
|
<%= Gettext.dpgettext("static_pages", "oauth authorized page title", "Successfully authorized") %>
|
||||||
|
</div>
|
||||||
|
<div class="panel-content">
|
||||||
|
<%= raw Gettext.dpgettext("static_pages", "oauth token code message", "Token code is <br>%{token}", token: safe_to_string(html_escape(@auth.token))) %>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
|
@ -20,7 +20,9 @@
|
||||||
|
|
||||||
<div class="container__content">
|
<div class="container__content">
|
||||||
<%= if @app do %>
|
<%= if @app do %>
|
||||||
<p><%= raw Gettext.dpgettext("static_pages", "oauth authorize message", "Application <strong>%{client_name}</strong> is requesting access to your account.", client_name: safe_to_string(html_escape(@app.client_name))) %></p>
|
<div class="panel-heading">
|
||||||
|
<p><%= raw Gettext.dpgettext("static_pages", "oauth authorize message", "Application <strong>%{client_name}</strong> is requesting access to your account.", client_name: safe_to_string(html_escape(@app.client_name))) %></p>
|
||||||
|
</div>
|
||||||
<%= render @view_module, "_scopes.html", Map.merge(assigns, %{form: f}) %>
|
<%= render @view_module, "_scopes.html", Map.merge(assigns, %{form: f}) %>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
||||||
|
|
2
mix.exs
2
mix.exs
|
@ -163,7 +163,7 @@ defp deps do
|
||||||
{:telemetry, "~> 0.3"},
|
{:telemetry, "~> 0.3"},
|
||||||
{:telemetry_poller, "~> 0.4"},
|
{:telemetry_poller, "~> 0.4"},
|
||||||
{:telemetry_metrics, "~> 0.4"},
|
{:telemetry_metrics, "~> 0.4"},
|
||||||
{:telemetry_metrics_prometheus, "~> 1.1.0"},
|
{:telemetry_metrics_prometheus_core, "~> 1.1.0"},
|
||||||
{:poolboy, "~> 1.5"},
|
{:poolboy, "~> 1.5"},
|
||||||
{:recon, "~> 2.5"},
|
{:recon, "~> 2.5"},
|
||||||
{:joken, "~> 2.0"},
|
{:joken, "~> 2.0"},
|
||||||
|
|
114
priv/static/static-fe/forms.css
Normal file
114
priv/static/static-fe/forms.css
Normal file
|
@ -0,0 +1,114 @@
|
||||||
|
form {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input {
|
||||||
|
color: var(--muted-text-color);
|
||||||
|
display: flex;
|
||||||
|
margin-left: 1em;
|
||||||
|
margin-right: 1em;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
input {
|
||||||
|
padding: 10px;
|
||||||
|
margin-top: 5px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
background-color: var(--background-color);
|
||||||
|
color: var(--primary-text-color);
|
||||||
|
border: 0;
|
||||||
|
transition-property: border-bottom;
|
||||||
|
transition-duration: 0.35s;
|
||||||
|
border-bottom: 2px solid #2a384a;
|
||||||
|
font-size: 14px;
|
||||||
|
width: inherit;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scopes-input {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
margin: 1em 0;
|
||||||
|
color: var(--muted-text-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.scopes-input label:first-child {
|
||||||
|
height: 2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scopes {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
color: var(--primary-text-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.scope {
|
||||||
|
display: flex;
|
||||||
|
flex-basis: 100%;
|
||||||
|
height: 2em;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scope:before {
|
||||||
|
color: var(--primary-text-color);
|
||||||
|
content: "✔\fe0e";
|
||||||
|
margin-left: 1em;
|
||||||
|
margin-right: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
[type="checkbox"]+label {
|
||||||
|
display: none;
|
||||||
|
cursor: pointer;
|
||||||
|
margin: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
[type="checkbox"] {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
[type="checkbox"]+label:before {
|
||||||
|
cursor: pointer;
|
||||||
|
display: inline-block;
|
||||||
|
color: white;
|
||||||
|
background-color: var(--background-color);
|
||||||
|
border: 4px solid var(--background-color);
|
||||||
|
box-shadow: 0px 0px 1px 0 var(--brand-color);
|
||||||
|
width: 1.2em;
|
||||||
|
height: 1.2em;
|
||||||
|
margin-right: 1.0em;
|
||||||
|
content: "";
|
||||||
|
transition-property: background-color;
|
||||||
|
transition-duration: 0.35s;
|
||||||
|
color: var(--background-color);
|
||||||
|
margin-bottom: -0.2em;
|
||||||
|
border-radius: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
[type="checkbox"]:checked+label:before {
|
||||||
|
background-color: var(--brand-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
a.button,
|
||||||
|
button {
|
||||||
|
width: 100%;
|
||||||
|
background-color: #1c2a3a;
|
||||||
|
color: var(--primary-text-color);
|
||||||
|
border-radius: 4px;
|
||||||
|
border: none;
|
||||||
|
padding: 10px 16px;
|
||||||
|
margin-top: 20px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
text-transform: uppercase;
|
||||||
|
font-size: 16px;
|
||||||
|
box-shadow: 0px 0px 2px 0px black,
|
||||||
|
0px 1px 0px 0px rgba(255, 255, 255, 0.2) inset,
|
||||||
|
0px -1px 0px 0px rgba(0, 0, 0, 0.2) inset;
|
||||||
|
}
|
||||||
|
|
||||||
|
a.button:hover,
|
||||||
|
button:hover {
|
||||||
|
cursor: pointer;
|
||||||
|
box-shadow: 0px 0px 0px 1px var(--brand-color),
|
||||||
|
0px 1px 0px 0px rgba(255, 255, 255, 0.2) inset,
|
||||||
|
0px -1px 0px 0px rgba(0, 0, 0, 0.2) inset;
|
||||||
|
}
|
|
@ -11,14 +11,14 @@ :root {
|
||||||
--profileTint: rgba(15, 22, 30, 0.5);
|
--profileTint: rgba(15, 22, 30, 0.5);
|
||||||
--btnText: rgba(185, 185, 186, 1);
|
--btnText: rgba(185, 185, 186, 1);
|
||||||
--btn: rgba(21, 30, 43, 1);
|
--btn: rgba(21, 30, 43, 1);
|
||||||
--btnShadow: 0px 0px 2px 0px rgba(0, 0, 0, 1) , 0px 1px 0px 0px rgba(255, 255, 255, 0.2) inset, 0px -1px 0px 0px rgba(0, 0, 0, 0.2) inset;
|
--btnShadow: 0px 0px 2px 0px rgba(0, 0, 0, 1), 0px 1px 0px 0px rgba(255, 255, 255, 0.2) inset, 0px -1px 0px 0px rgba(0, 0, 0, 0.2) inset;
|
||||||
--btnHoverShadow: 0px 0px 1px 2px rgba(185, 185, 186, 0.4) inset, 0px 1px 0px 0px rgba(255, 255, 255, 0.2) inset, 0px -1px 0px 0px rgba(0, 0, 0, 0.2) inset;
|
--btnHoverShadow: 0px 0px 1px 2px rgba(185, 185, 186, 0.4) inset, 0px 1px 0px 0px rgba(255, 255, 255, 0.2) inset, 0px -1px 0px 0px rgba(0, 0, 0, 0.2) inset;
|
||||||
--lightText: rgba(236, 236, 236, 1);
|
--lightText: rgba(236, 236, 236, 1);
|
||||||
--panelShadow: 0px 0px 3px 0px rgba(0, 0, 0, 0.5) , 0px 4px 6px 3px rgba(0, 0, 0, 0.3);
|
--panelShadow: 0px 0px 3px 0px rgba(0, 0, 0, 0.5), 0px 4px 6px 3px rgba(0, 0, 0, 0.3);
|
||||||
--panelHeaderShadow: 0px 1px 3px 0px rgba(0, 0, 0, 0.4) , 0px 1px 0px 0px rgba(255, 255, 255, 0.2) inset;
|
--panelHeaderShadow: 0px 1px 3px 0px rgba(0, 0, 0, 0.4), 0px 1px 0px 0px rgba(255, 255, 255, 0.2) inset;
|
||||||
--topBar: rgba(21, 30, 43, 1);
|
--topBar: rgba(21, 30, 43, 1);
|
||||||
--topBarText: rgba(159, 159, 161, 1);
|
--topBarText: rgba(159, 159, 161, 1);
|
||||||
--topBarShadow: 0px 1px 4px 0px rgba(0, 0, 0, 0.4) , 0px 2px 7px 0px rgba(0, 0, 0, 0.3);
|
--topBarShadow: 0px 1px 4px 0px rgba(0, 0, 0, 0.4), 0px 2px 7px 0px rgba(0, 0, 0, 0.3);
|
||||||
--underlay: rgba(9, 14, 20, 0.6);
|
--underlay: rgba(9, 14, 20, 0.6);
|
||||||
--background: rgba(15, 22, 30, 1);
|
--background: rgba(15, 22, 30, 1);
|
||||||
--faint: rgba(185, 185, 186, 0.5);
|
--faint: rgba(185, 185, 186, 0.5);
|
||||||
|
@ -28,9 +28,11 @@ :root {
|
||||||
--border: rgba(26, 37, 53, 1);
|
--border: rgba(26, 37, 53, 1);
|
||||||
--poll: rgba(99, 84, 72, 1);
|
--poll: rgba(99, 84, 72, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (prefers-color-scheme: light) {
|
@media (prefers-color-scheme: light) {
|
||||||
:root {
|
:root {
|
||||||
--icon-filter: invert(67%) sepia(7%) saturate(525%) hue-rotate(173deg) brightness(90%) contrast(92%);;
|
--icon-filter: invert(67%) sepia(7%) saturate(525%) hue-rotate(173deg) brightness(90%) contrast(92%);
|
||||||
|
;
|
||||||
--wallpaper: rgba(248, 250, 252, 1);
|
--wallpaper: rgba(248, 250, 252, 1);
|
||||||
--alertNeutral: rgba(48, 64, 85, 0.5);
|
--alertNeutral: rgba(48, 64, 85, 0.5);
|
||||||
--alertNeutralText: rgba(0, 0, 0, 1);
|
--alertNeutralText: rgba(0, 0, 0, 1);
|
||||||
|
@ -41,10 +43,10 @@ @media (prefers-color-scheme: light) {
|
||||||
--profileTint: rgba(242, 246, 249, 0.5);
|
--profileTint: rgba(242, 246, 249, 0.5);
|
||||||
--btnText: rgba(48, 64, 85, 1);
|
--btnText: rgba(48, 64, 85, 1);
|
||||||
--btn: rgba(214, 223, 237, 1);
|
--btn: rgba(214, 223, 237, 1);
|
||||||
--btnShadow: 0px 0px 2px 0px rgba(0, 0, 0, 0.2) , 0px 1px 0px 0px rgba(255, 255, 255, 0.5) inset, 0px -1px 0px 0px rgba(0, 0, 0, 0.2) inset;
|
--btnShadow: 0px 0px 2px 0px rgba(0, 0, 0, 0.2), 0px 1px 0px 0px rgba(255, 255, 255, 0.5) inset, 0px -1px 0px 0px rgba(0, 0, 0, 0.2) inset;
|
||||||
--btnHoverShadow: 0px 0px 2px 0px rgba(0, 0, 0, 0.2) , 0px 0px 1px 2px rgba(255, 195, 159, 1) inset, 0px -1px 0px 0px rgba(0, 0, 0, 0.2) inset;
|
--btnHoverShadow: 0px 0px 2px 0px rgba(0, 0, 0, 0.2), 0px 0px 1px 2px rgba(255, 195, 159, 1) inset, 0px -1px 0px 0px rgba(0, 0, 0, 0.2) inset;
|
||||||
--lightText: rgba(11, 14, 19, 1);
|
--lightText: rgba(11, 14, 19, 1);
|
||||||
--panelShadow: 0px 1px 3px 0px rgba(0, 0, 0, 0.5) , 0px 3px 6px 1px rgba(0, 0, 0, 0.2);
|
--panelShadow: 0px 1px 3px 0px rgba(0, 0, 0, 0.5), 0px 3px 6px 1px rgba(0, 0, 0, 0.2);
|
||||||
--panelHeaderShadow: 0px 1px 0px 0px rgba(255, 255, 255, 0.5) inset, 0px 1px 3px 0px rgba(0, 0, 0, 0.3);
|
--panelHeaderShadow: 0px 1px 0px 0px rgba(255, 255, 255, 0.5) inset, 0px 1px 3px 0px rgba(0, 0, 0, 0.3);
|
||||||
--topBar: rgba(214, 223, 237, 1);
|
--topBar: rgba(214, 223, 237, 1);
|
||||||
--topBarText: rgba(48, 64, 85, 1);
|
--topBarText: rgba(48, 64, 85, 1);
|
||||||
|
@ -119,7 +121,7 @@ .inner-nav img {
|
||||||
padding-right: 5px
|
padding-right: 5px
|
||||||
}
|
}
|
||||||
|
|
||||||
body > .container {
|
body>.container {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: minmax(25em, 45em) 25em;
|
grid-template-columns: minmax(25em, 45em) 25em;
|
||||||
grid-template-areas: "content sidebar";
|
grid-template-areas: "content sidebar";
|
||||||
|
@ -155,6 +157,10 @@ .panel-heading {
|
||||||
box-shadow: var(--panelHeaderShadow);
|
box-shadow: var(--panelHeaderShadow);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.panel-content {
|
||||||
|
padding: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
.about-content {
|
.about-content {
|
||||||
padding: 0.6em;
|
padding: 0.6em;
|
||||||
}
|
}
|
||||||
|
@ -169,6 +175,18 @@ .sidebar {
|
||||||
padding-left: 0.5em;
|
padding-left: 0.5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.column.flex {
|
||||||
|
grid-column-end: sidebar-end;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scopes-input {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
margin: 1em 0;
|
||||||
|
color: var(--muted-text-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
.status-container,
|
.status-container,
|
||||||
.repeat-header,
|
.repeat-header,
|
||||||
.user-card {
|
.user-card {
|
||||||
|
@ -193,6 +211,7 @@ .repeat-header {
|
||||||
.repeat-header .right-side {
|
.repeat-header .right-side {
|
||||||
color: var(--faint);
|
color: var(--faint);
|
||||||
}
|
}
|
||||||
|
|
||||||
.repeat-header .u-photo {
|
.repeat-header .u-photo {
|
||||||
height: 20px;
|
height: 20px;
|
||||||
width: 20px;
|
width: 20px;
|
||||||
|
@ -255,6 +274,7 @@ .heading-reply-row {
|
||||||
.reply-to-link {
|
.reply-to-link {
|
||||||
color: var(--faint);
|
color: var(--faint);
|
||||||
}
|
}
|
||||||
|
|
||||||
.reply-to-link:hover {
|
.reply-to-link:hover {
|
||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
}
|
}
|
||||||
|
@ -280,11 +300,13 @@ .h-card {
|
||||||
margin-bottom: 8px;
|
margin-bottom: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
header a, .h-card a {
|
header a,
|
||||||
|
.h-card a {
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
header a:hover, .h-card a:hover {
|
header a:hover,
|
||||||
|
.h-card a:hover {
|
||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -307,7 +329,7 @@ .attachment {
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.attachment > * {
|
.attachment>* {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
object-fit: contain;
|
object-fit: contain;
|
||||||
}
|
}
|
||||||
|
@ -322,6 +344,7 @@ .nsfw-banner {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.nsfw-banner div {
|
.nsfw-banner div {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
@ -330,6 +353,7 @@ .nsfw-banner div {
|
||||||
.nsfw-banner:not(:hover) {
|
.nsfw-banner:not(:hover) {
|
||||||
background-color: var(--background);
|
background-color: var(--background);
|
||||||
}
|
}
|
||||||
|
|
||||||
.nsfw-banner:hover div {
|
.nsfw-banner:hover div {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
@ -342,10 +366,12 @@ .poll-option {
|
||||||
word-break: break-word;
|
word-break: break-word;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.poll-option .percentage {
|
.poll-option .percentage {
|
||||||
width: 3.5em;
|
width: 3.5em;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.poll-option .fill {
|
.poll-option .fill {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
@ -362,7 +388,8 @@ .status-actions {
|
||||||
display: flex;
|
display: flex;
|
||||||
margin-top: 0.75em;
|
margin-top: 0.75em;
|
||||||
}
|
}
|
||||||
.status-actions > * {
|
|
||||||
|
.status-actions>* {
|
||||||
max-width: 4em;
|
max-width: 4em;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
@ -458,11 +485,11 @@ .user-banner {
|
||||||
right: 0;
|
right: 0;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
background-image: linear-gradient(to bottom, var(--profileTint), var(--profileTint)),
|
background-image: linear-gradient(to bottom, var(--profileTint), var(--profileTint)),
|
||||||
var(--user-banner);
|
var(--user-banner);
|
||||||
background-size: cover;
|
background-size: cover;
|
||||||
background-color: var(--profileBg);
|
background-color: var(--profileBg);
|
||||||
-webkit-mask: linear-gradient(to top, white, transparent) bottom no-repeat,
|
-webkit-mask: linear-gradient(to top, white, transparent) bottom no-repeat,
|
||||||
linear-gradient(to top, white, white);
|
linear-gradient(to top, white, white);
|
||||||
-webkit-mask-composite: xor;
|
-webkit-mask-composite: xor;
|
||||||
-webkit-mask-size: 100% 60%;
|
-webkit-mask-size: 100% 60%;
|
||||||
z-index: -2;
|
z-index: -2;
|
||||||
|
@ -600,7 +627,7 @@ .reply-to-link .fa-icon {
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 800px) {
|
@media (max-width: 800px) {
|
||||||
body > .container {
|
body>.container {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
65
scripts/create_metrics_app.sh
Executable file
65
scripts/create_metrics_app.sh
Executable file
|
@ -0,0 +1,65 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
read -p "Instance URL (e.g https://example.com): " INSTANCE_URL
|
||||||
|
|
||||||
|
echo "Creating oauth app..."
|
||||||
|
|
||||||
|
RESP=$(curl \
|
||||||
|
-XPOST \
|
||||||
|
$INSTANCE_URL/api/v1/apps \
|
||||||
|
--silent \
|
||||||
|
--data-urlencode 'client_name=fedibash' \
|
||||||
|
--data-urlencode 'redirect_uris=urn:ietf:wg:oauth:2.0:oob' \
|
||||||
|
--data-urlencode 'scopes=admin:metrics' \
|
||||||
|
--header "Content-Type: application/x-www-form-urlencoded"
|
||||||
|
)
|
||||||
|
|
||||||
|
client_id=$(echo $RESP | jq -r .client_id)
|
||||||
|
client_secret=$(echo $RESP | jq -r .client_secret)
|
||||||
|
|
||||||
|
if [ -z "$client_id"]; then
|
||||||
|
echo "Could not create an app"
|
||||||
|
echo "$RESP"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Please visit the following URL and input the code provided"
|
||||||
|
AUTH_URL="$INSTANCE_URL/oauth/authorize?client_id=$client_id&redirect_uri=urn:ietf:wg:oauth:2.0:oob&scope=admin:metrics&response_type=code"
|
||||||
|
if [ ! -z "$BROWSER" ]; then
|
||||||
|
$BROWSER $AUTH_URL
|
||||||
|
fi;
|
||||||
|
|
||||||
|
echo $AUTH_URL
|
||||||
|
|
||||||
|
read -p "Code: " CODE
|
||||||
|
|
||||||
|
echo "Requesting code..."
|
||||||
|
|
||||||
|
RESP=$(curl \
|
||||||
|
-XPOST \
|
||||||
|
$INSTANCE_URL/oauth/token \
|
||||||
|
--silent \
|
||||||
|
--header "Content-Type: application/x-www-form-urlencoded" \
|
||||||
|
--data-urlencode "client_id=$client_id" \
|
||||||
|
--data-urlencode "client_secret=$client_secret" \
|
||||||
|
--data-urlencode "code=$CODE" \
|
||||||
|
--data-urlencode "grant_type=authorization_code" \
|
||||||
|
--data-urlencode 'redirect_uri=urn:ietf:wg:oauth:2.0:oob' \
|
||||||
|
--data-urlencode "scope=admin:metrics"
|
||||||
|
)
|
||||||
|
|
||||||
|
ACCESS_TOKEN="$(echo $RESP | jq -r .access_token)"
|
||||||
|
|
||||||
|
echo "Token is $ACCESS_TOKEN"
|
||||||
|
DOMAIN=$(echo $INSTANCE_URL | sed -e 's/^https:\/\///')
|
||||||
|
|
||||||
|
echo "Use the following config in your prometheus.yml:
|
||||||
|
- job_name: akkoma
|
||||||
|
scheme: https
|
||||||
|
authorization:
|
||||||
|
credentials: $ACCESS_TOKEN
|
||||||
|
metrics_path: /api/v1/akkoma/metrics
|
||||||
|
static_configs:
|
||||||
|
- targets:
|
||||||
|
- $DOMAIN
|
||||||
|
"
|
|
@ -554,7 +554,7 @@ def oauth_app_factory do
|
||||||
%Pleroma.Web.OAuth.App{
|
%Pleroma.Web.OAuth.App{
|
||||||
client_name: sequence(:client_name, &"Some client #{&1}"),
|
client_name: sequence(:client_name, &"Some client #{&1}"),
|
||||||
redirect_uris: "https://example.com/callback",
|
redirect_uris: "https://example.com/callback",
|
||||||
scopes: ["read", "write", "follow", "push", "admin"],
|
scopes: ["read", "write", "follow", "push"],
|
||||||
website: "https://example.com",
|
website: "https://example.com",
|
||||||
client_id: Ecto.UUID.generate(),
|
client_id: Ecto.UUID.generate(),
|
||||||
client_secret: "aaa;/&bbb"
|
client_secret: "aaa;/&bbb"
|
||||||
|
|
Loading…
Reference in a new issue