Merge branch 'develop' into config/benchmark
This commit is contained in:
commit
50638525db
|
@ -28,6 +28,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
|||
- **Breaking:** Admin API: Return link alongside with token on password reset
|
||||
- **Breaking:** Admin API: `PUT /api/pleroma/admin/reports/:id` is now `PATCH /api/pleroma/admin/reports`, see admin_api.md for details
|
||||
- **Breaking:** `/api/pleroma/admin/users/invite_token` now uses `POST`, changed accepted params and returns full invite in json instead of only token string.
|
||||
- **Breaking** replying to reports is now "report notes", enpoint changed from `POST /api/pleroma/admin/reports/:id/respond` to `POST /api/pleroma/admin/reports/:id/notes`
|
||||
- Admin API: Return `total` when querying for reports
|
||||
- Mastodon API: Return `pleroma.direct_conversation_id` when creating a direct message (`POST /api/v1/statuses`)
|
||||
- Admin API: Return link alongside with token on password reset
|
||||
|
@ -83,6 +84,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
|||
- ActivityPub: Configurable `type` field of the actors.
|
||||
- Mastodon API: `/api/v1/accounts/:id` has `source/pleroma/actor_type` field.
|
||||
- Mastodon API: `/api/v1/update_credentials` accepts `actor_type` field.
|
||||
- Captcha: Support native provider
|
||||
- Captcha: Enable by default
|
||||
</details>
|
||||
|
||||
### Fixed
|
||||
|
@ -91,6 +94,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
|||
- MRF: `Delete` activities being exempt from MRF policies
|
||||
- OTP releases: Not being able to configure OAuth expired token cleanup interval
|
||||
- OTP releases: Not being able to configure HTML sanitization policy
|
||||
- Favorites timeline now ordered by favorite date instead of post date
|
||||
<details>
|
||||
<summary>API Changes</summary>
|
||||
|
||||
|
|
|
@ -66,9 +66,11 @@
|
|||
jobs: scheduled_jobs
|
||||
|
||||
config :pleroma, Pleroma.Captcha,
|
||||
enabled: false,
|
||||
enabled: true,
|
||||
seconds_valid: 60,
|
||||
method: Pleroma.Captcha.Kocaptcha
|
||||
method: Pleroma.Captcha.Native
|
||||
|
||||
config :pleroma, Pleroma.Captcha.Kocaptcha, endpoint: "https://captcha.kotobank.ch"
|
||||
|
||||
config :pleroma, :hackney_pools,
|
||||
federation: [
|
||||
|
@ -84,8 +86,6 @@
|
|||
timeout: 300_000
|
||||
]
|
||||
|
||||
config :pleroma, Pleroma.Captcha.Kocaptcha, endpoint: "https://captcha.kotobank.ch"
|
||||
|
||||
# Upload configuration
|
||||
config :pleroma, Pleroma.Upload,
|
||||
uploader: Pleroma.Uploaders.Local,
|
||||
|
|
|
@ -68,7 +68,9 @@
|
|||
queues: false,
|
||||
prune: :disabled
|
||||
|
||||
config :pleroma, Pleroma.Scheduler, jobs: []
|
||||
config :pleroma, Pleroma.Scheduler,
|
||||
jobs: [],
|
||||
global: false
|
||||
|
||||
config :pleroma, Pleroma.ScheduledActivity,
|
||||
daily_user_limit: 2,
|
||||
|
|
|
@ -614,78 +614,29 @@ Note: Available `:permission_group` is currently moderator and admin. 404 is ret
|
|||
|
||||
- On success: `204`, empty response
|
||||
|
||||
## `POST /api/pleroma/admin/reports/:id/respond`
|
||||
## `POST /api/pleroma/admin/reports/:id/notes`
|
||||
|
||||
### Respond to a report
|
||||
### Create report note
|
||||
|
||||
- Params:
|
||||
- `id`
|
||||
- `status`: required, the message
|
||||
- `id`: required, report id
|
||||
- `content`: required, the message
|
||||
- Response:
|
||||
- On failure:
|
||||
- 400 Bad Request `"Invalid parameters"` when `status` is missing
|
||||
- 403 Forbidden `{"error": "error_msg"}`
|
||||
- 404 Not Found `"Not found"`
|
||||
- On success: JSON, created Mastodon Status entity
|
||||
- On success: `204`, empty response
|
||||
|
||||
```json
|
||||
{
|
||||
"account": { ... },
|
||||
"application": {
|
||||
"name": "Web",
|
||||
"website": null
|
||||
},
|
||||
"bookmarked": false,
|
||||
"card": null,
|
||||
"content": "Your claim is going to be closed",
|
||||
"created_at": "2019-05-11T17:13:03.000Z",
|
||||
"emojis": [],
|
||||
"favourited": false,
|
||||
"favourites_count": 0,
|
||||
"id": "9ihuiSL1405I65TmEq",
|
||||
"in_reply_to_account_id": null,
|
||||
"in_reply_to_id": null,
|
||||
"language": null,
|
||||
"media_attachments": [],
|
||||
"mentions": [
|
||||
{
|
||||
"acct": "user",
|
||||
"id": "9i6dAJqSGSKMzLG2Lo",
|
||||
"url": "https://pleroma.example.org/users/user",
|
||||
"username": "user"
|
||||
},
|
||||
{
|
||||
"acct": "admin",
|
||||
"id": "9hEkA5JsvAdlSrocam",
|
||||
"url": "https://pleroma.example.org/users/admin",
|
||||
"username": "admin"
|
||||
}
|
||||
],
|
||||
"muted": false,
|
||||
"pinned": false,
|
||||
"pleroma": {
|
||||
"content": {
|
||||
"text/plain": "Your claim is going to be closed"
|
||||
},
|
||||
"conversation_id": 35,
|
||||
"in_reply_to_account_acct": null,
|
||||
"local": true,
|
||||
"spoiler_text": {
|
||||
"text/plain": ""
|
||||
}
|
||||
},
|
||||
"reblog": null,
|
||||
"reblogged": false,
|
||||
"reblogs_count": 0,
|
||||
"replies_count": 0,
|
||||
"sensitive": false,
|
||||
"spoiler_text": "",
|
||||
"tags": [],
|
||||
"uri": "https://pleroma.example.org/objects/cab0836d-9814-46cd-a0ea-529da9db5fcb",
|
||||
"url": "https://pleroma.example.org/notice/9ihuiSL1405I65TmEq",
|
||||
"visibility": "direct"
|
||||
}
|
||||
```
|
||||
## `POST /api/pleroma/admin/reports/:report_id/notes/:id`
|
||||
|
||||
### Delete report note
|
||||
|
||||
- Params:
|
||||
- `report_id`: required, report id
|
||||
- `id`: required, note id
|
||||
- Response:
|
||||
- On failure:
|
||||
- 400 Bad Request `"Invalid parameters"` when `status` is missing
|
||||
- On success: `204`, empty response
|
||||
|
||||
## `PUT /api/pleroma/admin/statuses/:id`
|
||||
|
||||
|
|
|
@ -379,13 +379,19 @@ For each pool, the options are:
|
|||
## Captcha
|
||||
|
||||
### Pleroma.Captcha
|
||||
|
||||
* `enabled`: Whether the captcha should be shown on registration.
|
||||
* `method`: The method/service to use for captcha.
|
||||
* `seconds_valid`: The time in seconds for which the captcha is valid.
|
||||
|
||||
### Captcha providers
|
||||
|
||||
#### Pleroma.Captcha.Native
|
||||
|
||||
A built-in captcha provider. Enabled by default.
|
||||
|
||||
#### Pleroma.Captcha.Kocaptcha
|
||||
|
||||
Kocaptcha is a very simple captcha service with a single API endpoint,
|
||||
the source code is here: https://github.com/koto-bank/kocaptcha. The default endpoint
|
||||
`https://captcha.kotobank.ch` is hosted by the developer.
|
||||
|
|
|
@ -12,6 +12,7 @@ defmodule Pleroma.Activity do
|
|||
alias Pleroma.Notification
|
||||
alias Pleroma.Object
|
||||
alias Pleroma.Repo
|
||||
alias Pleroma.ReportNote
|
||||
alias Pleroma.ThreadMute
|
||||
alias Pleroma.User
|
||||
|
||||
|
@ -48,6 +49,8 @@ defmodule Pleroma.Activity do
|
|||
has_one(:user_actor, User, on_delete: :nothing, foreign_key: :id)
|
||||
# This is a fake relation, do not use outside of with_preloaded_bookmark/get_bookmark
|
||||
has_one(:bookmark, Bookmark)
|
||||
# This is a fake relation, do not use outside of with_preloaded_report_notes
|
||||
has_many(:report_notes, ReportNote)
|
||||
has_many(:notifications, Notification, on_delete: :delete_all)
|
||||
|
||||
# Attention: this is a fake relation, don't try to preload it blindly and expect it to work!
|
||||
|
@ -114,6 +117,16 @@ def with_preloaded_bookmark(query, %User{} = user) do
|
|||
|
||||
def with_preloaded_bookmark(query, _), do: query
|
||||
|
||||
def with_preloaded_report_notes(query) do
|
||||
from([a] in query,
|
||||
left_join: r in ReportNote,
|
||||
on: a.id == r.activity_id,
|
||||
preload: [report_notes: r]
|
||||
)
|
||||
end
|
||||
|
||||
def with_preloaded_report_notes(query, _), do: query
|
||||
|
||||
def with_set_thread_muted_field(query, %User{} = user) do
|
||||
from([a] in query,
|
||||
left_join: tm in ThreadMute,
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
# Pleroma: A lightweight social networking server
|
||||
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.Captcha.Native do
|
||||
import Pleroma.Web.Gettext
|
||||
alias Pleroma.Captcha.Service
|
||||
@behaviour Service
|
||||
|
||||
@impl Service
|
||||
def new do
|
||||
case Captcha.get() do
|
||||
{:timeout} ->
|
||||
%{error: dgettext("errors", "Captcha timeout")}
|
||||
|
||||
{:ok, answer_data, img_binary} ->
|
||||
%{
|
||||
type: :native,
|
||||
token: token(),
|
||||
url: "data:image/png;base64," <> Base.encode64(img_binary),
|
||||
answer_data: answer_data
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
@impl Service
|
||||
def validate(_token, captcha, captcha) when not is_nil(captcha), do: :ok
|
||||
def validate(_token, _captcha, _answer), do: {:error, dgettext("errors", "Invalid CAPTCHA")}
|
||||
|
||||
defp token do
|
||||
10
|
||||
|> :crypto.strong_rand_bytes()
|
||||
|> Base.url_encode64(padding: false)
|
||||
end
|
||||
end
|
|
@ -128,17 +128,35 @@ def insert_log(%{
|
|||
{:ok, ModerationLog} | {:error, any}
|
||||
def insert_log(%{
|
||||
actor: %User{} = actor,
|
||||
action: "report_response",
|
||||
action: "report_note",
|
||||
subject: %Activity{} = subject,
|
||||
text: text
|
||||
}) do
|
||||
%ModerationLog{
|
||||
data: %{
|
||||
"actor" => user_to_map(actor),
|
||||
"action" => "report_response",
|
||||
"action" => "report_note",
|
||||
"subject" => report_to_map(subject),
|
||||
"text" => text,
|
||||
"message" => ""
|
||||
"text" => text
|
||||
}
|
||||
}
|
||||
|> insert_log_entry_with_message()
|
||||
end
|
||||
|
||||
@spec insert_log(%{actor: User, subject: Activity, action: String.t(), text: String.t()}) ::
|
||||
{:ok, ModerationLog} | {:error, any}
|
||||
def insert_log(%{
|
||||
actor: %User{} = actor,
|
||||
action: "report_note_delete",
|
||||
subject: %Activity{} = subject,
|
||||
text: text
|
||||
}) do
|
||||
%ModerationLog{
|
||||
data: %{
|
||||
"actor" => user_to_map(actor),
|
||||
"action" => "report_note_delete",
|
||||
"subject" => report_to_map(subject),
|
||||
"text" => text
|
||||
}
|
||||
}
|
||||
|> insert_log_entry_with_message()
|
||||
|
@ -556,12 +574,24 @@ def get_log_entry_message(%ModerationLog{
|
|||
def get_log_entry_message(%ModerationLog{
|
||||
data: %{
|
||||
"actor" => %{"nickname" => actor_nickname},
|
||||
"action" => "report_response",
|
||||
"action" => "report_note",
|
||||
"subject" => %{"id" => subject_id, "type" => "report"},
|
||||
"text" => text
|
||||
}
|
||||
}) do
|
||||
"@#{actor_nickname} responded with '#{text}' to report ##{subject_id}"
|
||||
"@#{actor_nickname} added note '#{text}' to report ##{subject_id}"
|
||||
end
|
||||
|
||||
@spec get_log_entry_message(ModerationLog) :: String.t()
|
||||
def get_log_entry_message(%ModerationLog{
|
||||
data: %{
|
||||
"actor" => %{"nickname" => actor_nickname},
|
||||
"action" => "report_note_delete",
|
||||
"subject" => %{"id" => subject_id, "type" => "report"},
|
||||
"text" => text
|
||||
}
|
||||
}) do
|
||||
"@#{actor_nickname} deleted note '#{text}' from report ##{subject_id}"
|
||||
end
|
||||
|
||||
@spec get_log_entry_message(ModerationLog) :: String.t()
|
||||
|
|
|
@ -23,6 +23,23 @@ defmodule Pleroma.Object do
|
|||
timestamps()
|
||||
end
|
||||
|
||||
def with_joined_activity(query, activity_type \\ "Create", join_type \\ :inner) do
|
||||
object_position = Map.get(query.aliases, :object, 0)
|
||||
|
||||
join(query, join_type, [{object, object_position}], a in Activity,
|
||||
on:
|
||||
fragment(
|
||||
"COALESCE(?->'object'->>'id', ?->>'object') = (? ->> 'id') AND (?->>'type' = ?) ",
|
||||
a.data,
|
||||
a.data,
|
||||
object.data,
|
||||
a.data,
|
||||
^activity_type
|
||||
),
|
||||
as: :object_activity
|
||||
)
|
||||
end
|
||||
|
||||
def create(data) do
|
||||
Object.change(%Object{}, %{data: data})
|
||||
|> Repo.insert()
|
||||
|
|
|
@ -13,60 +13,66 @@ defmodule Pleroma.Pagination do
|
|||
alias Pleroma.Repo
|
||||
|
||||
@default_limit 20
|
||||
@page_keys ["max_id", "min_id", "limit", "since_id", "order"]
|
||||
|
||||
def fetch_paginated(query, params, type \\ :keyset)
|
||||
def page_keys, do: @page_keys
|
||||
|
||||
def fetch_paginated(query, %{"total" => true} = params, :keyset) do
|
||||
def fetch_paginated(query, params, type \\ :keyset, table_binding \\ nil)
|
||||
|
||||
def fetch_paginated(query, %{"total" => true} = params, :keyset, table_binding) do
|
||||
total = Repo.aggregate(query, :count, :id)
|
||||
|
||||
%{
|
||||
total: total,
|
||||
items: fetch_paginated(query, Map.drop(params, ["total"]), :keyset)
|
||||
items: fetch_paginated(query, Map.drop(params, ["total"]), :keyset, table_binding)
|
||||
}
|
||||
end
|
||||
|
||||
def fetch_paginated(query, params, :keyset) do
|
||||
def fetch_paginated(query, params, :keyset, table_binding) do
|
||||
options = cast_params(params)
|
||||
|
||||
query
|
||||
|> paginate(options, :keyset)
|
||||
|> paginate(options, :keyset, table_binding)
|
||||
|> Repo.all()
|
||||
|> enforce_order(options)
|
||||
end
|
||||
|
||||
def fetch_paginated(query, %{"total" => true} = params, :offset) do
|
||||
total = Repo.aggregate(query, :count, :id)
|
||||
def fetch_paginated(query, %{"total" => true} = params, :offset, table_binding) do
|
||||
total =
|
||||
query
|
||||
|> Ecto.Query.exclude(:left_join)
|
||||
|> Repo.aggregate(:count, :id)
|
||||
|
||||
%{
|
||||
total: total,
|
||||
items: fetch_paginated(query, Map.drop(params, ["total"]), :offset)
|
||||
items: fetch_paginated(query, Map.drop(params, ["total"]), :offset, table_binding)
|
||||
}
|
||||
end
|
||||
|
||||
def fetch_paginated(query, params, :offset) do
|
||||
def fetch_paginated(query, params, :offset, table_binding) do
|
||||
options = cast_params(params)
|
||||
|
||||
query
|
||||
|> paginate(options, :offset)
|
||||
|> paginate(options, :offset, table_binding)
|
||||
|> Repo.all()
|
||||
end
|
||||
|
||||
def paginate(query, options, method \\ :keyset)
|
||||
def paginate(query, options, method \\ :keyset, table_binding \\ nil)
|
||||
|
||||
def paginate(query, options, :keyset) do
|
||||
def paginate(query, options, :keyset, table_binding) do
|
||||
query
|
||||
|> restrict(:min_id, options)
|
||||
|> restrict(:since_id, options)
|
||||
|> restrict(:max_id, options)
|
||||
|> restrict(:order, options)
|
||||
|> restrict(:limit, options)
|
||||
|> restrict(:min_id, options, table_binding)
|
||||
|> restrict(:since_id, options, table_binding)
|
||||
|> restrict(:max_id, options, table_binding)
|
||||
|> restrict(:order, options, table_binding)
|
||||
|> restrict(:limit, options, table_binding)
|
||||
end
|
||||
|
||||
def paginate(query, options, :offset) do
|
||||
def paginate(query, options, :offset, table_binding) do
|
||||
query
|
||||
|> restrict(:order, options)
|
||||
|> restrict(:offset, options)
|
||||
|> restrict(:limit, options)
|
||||
|> restrict(:order, options, table_binding)
|
||||
|> restrict(:offset, options, table_binding)
|
||||
|> restrict(:limit, options, table_binding)
|
||||
end
|
||||
|
||||
defp cast_params(params) do
|
||||
|
@ -75,7 +81,8 @@ defp cast_params(params) do
|
|||
since_id: :string,
|
||||
max_id: :string,
|
||||
offset: :integer,
|
||||
limit: :integer
|
||||
limit: :integer,
|
||||
skip_order: :boolean
|
||||
}
|
||||
|
||||
params =
|
||||
|
@ -88,38 +95,48 @@ defp cast_params(params) do
|
|||
changeset.changes
|
||||
end
|
||||
|
||||
defp restrict(query, :min_id, %{min_id: min_id}) do
|
||||
where(query, [q], q.id > ^min_id)
|
||||
defp restrict(query, :min_id, %{min_id: min_id}, table_binding) do
|
||||
where(query, [{q, table_position(query, table_binding)}], q.id > ^min_id)
|
||||
end
|
||||
|
||||
defp restrict(query, :since_id, %{since_id: since_id}) do
|
||||
where(query, [q], q.id > ^since_id)
|
||||
defp restrict(query, :since_id, %{since_id: since_id}, table_binding) do
|
||||
where(query, [{q, table_position(query, table_binding)}], q.id > ^since_id)
|
||||
end
|
||||
|
||||
defp restrict(query, :max_id, %{max_id: max_id}) do
|
||||
where(query, [q], q.id < ^max_id)
|
||||
defp restrict(query, :max_id, %{max_id: max_id}, table_binding) do
|
||||
where(query, [{q, table_position(query, table_binding)}], q.id < ^max_id)
|
||||
end
|
||||
|
||||
defp restrict(query, :order, %{min_id: _}) do
|
||||
order_by(query, [u], fragment("? asc nulls last", u.id))
|
||||
defp restrict(query, :order, %{skip_order: true}, _), do: query
|
||||
|
||||
defp restrict(query, :order, %{min_id: _}, table_binding) do
|
||||
order_by(
|
||||
query,
|
||||
[{u, table_position(query, table_binding)}],
|
||||
fragment("? asc nulls last", u.id)
|
||||
)
|
||||
end
|
||||
|
||||
defp restrict(query, :order, _options) do
|
||||
order_by(query, [u], fragment("? desc nulls last", u.id))
|
||||
defp restrict(query, :order, _options, table_binding) do
|
||||
order_by(
|
||||
query,
|
||||
[{u, table_position(query, table_binding)}],
|
||||
fragment("? desc nulls last", u.id)
|
||||
)
|
||||
end
|
||||
|
||||
defp restrict(query, :offset, %{offset: offset}) do
|
||||
defp restrict(query, :offset, %{offset: offset}, _table_binding) do
|
||||
offset(query, ^offset)
|
||||
end
|
||||
|
||||
defp restrict(query, :limit, options) do
|
||||
defp restrict(query, :limit, options, _table_binding) do
|
||||
limit = Map.get(options, :limit, @default_limit)
|
||||
|
||||
query
|
||||
|> limit(^limit)
|
||||
end
|
||||
|
||||
defp restrict(query, _, _), do: query
|
||||
defp restrict(query, _, _, _), do: query
|
||||
|
||||
defp enforce_order(result, %{min_id: _}) do
|
||||
result
|
||||
|
@ -127,4 +144,10 @@ defp enforce_order(result, %{min_id: _}) do
|
|||
end
|
||||
|
||||
defp enforce_order(result, _), do: result
|
||||
|
||||
defp table_position(%Ecto.Query{} = query, binding_name) do
|
||||
Map.get(query.aliases, binding_name, 0)
|
||||
end
|
||||
|
||||
defp table_position(_, _), do: 0
|
||||
end
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
# Pleroma: A lightweight social networking server
|
||||
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.ReportNote do
|
||||
use Ecto.Schema
|
||||
|
||||
import Ecto.Changeset
|
||||
import Ecto.Query
|
||||
|
||||
alias Pleroma.Activity
|
||||
alias Pleroma.Repo
|
||||
alias Pleroma.ReportNote
|
||||
alias Pleroma.User
|
||||
|
||||
@type t :: %__MODULE__{}
|
||||
|
||||
schema "report_notes" do
|
||||
field(:content, :string)
|
||||
belongs_to(:user, User, type: FlakeId.Ecto.CompatType)
|
||||
belongs_to(:activity, Activity, type: FlakeId.Ecto.CompatType)
|
||||
|
||||
timestamps()
|
||||
end
|
||||
|
||||
@spec create(FlakeId.Ecto.CompatType.t(), FlakeId.Ecto.CompatType.t(), String.t()) ::
|
||||
{:ok, ReportNote.t()} | {:error, Changeset.t()}
|
||||
def create(user_id, activity_id, content) do
|
||||
attrs = %{
|
||||
user_id: user_id,
|
||||
activity_id: activity_id,
|
||||
content: content
|
||||
}
|
||||
|
||||
%ReportNote{}
|
||||
|> cast(attrs, [:user_id, :activity_id, :content])
|
||||
|> validate_required([:user_id, :activity_id, :content])
|
||||
|> Repo.insert()
|
||||
end
|
||||
|
||||
@spec destroy(FlakeId.Ecto.CompatType.t()) ::
|
||||
{:ok, ReportNote.t()} | {:error, Changeset.t()}
|
||||
def destroy(id) do
|
||||
from(r in ReportNote, where: r.id == ^id)
|
||||
|> Repo.one()
|
||||
|> Repo.delete()
|
||||
end
|
||||
end
|
|
@ -1068,6 +1068,13 @@ defp maybe_preload_bookmarks(query, opts) do
|
|||
|> Activity.with_preloaded_bookmark(opts["user"])
|
||||
end
|
||||
|
||||
defp maybe_preload_report_notes(query, %{"preload_report_notes" => true}) do
|
||||
query
|
||||
|> Activity.with_preloaded_report_notes()
|
||||
end
|
||||
|
||||
defp maybe_preload_report_notes(query, _), do: query
|
||||
|
||||
defp maybe_set_thread_muted_field(query, %{"skip_preload" => true}), do: query
|
||||
|
||||
defp maybe_set_thread_muted_field(query, opts) do
|
||||
|
@ -1121,6 +1128,7 @@ def fetch_activities_query(recipients, opts \\ %{}) do
|
|||
Activity
|
||||
|> maybe_preload_objects(opts)
|
||||
|> maybe_preload_bookmarks(opts)
|
||||
|> maybe_preload_report_notes(opts)
|
||||
|> maybe_set_thread_muted_field(opts)
|
||||
|> maybe_order(opts)
|
||||
|> restrict_recipients(recipients, opts["user"])
|
||||
|
@ -1157,6 +1165,25 @@ def fetch_activities(recipients, opts \\ %{}, pagination \\ :keyset) do
|
|||
|> maybe_update_cc(list_memberships, opts["user"])
|
||||
end
|
||||
|
||||
@doc """
|
||||
Fetch favorites activities of user with order by sort adds to favorites
|
||||
"""
|
||||
@spec fetch_favourites(User.t(), map(), atom()) :: list(Activity.t())
|
||||
def fetch_favourites(user, params \\ %{}, pagination \\ :keyset) do
|
||||
user.ap_id
|
||||
|> Activity.Queries.by_actor()
|
||||
|> Activity.Queries.by_type("Like")
|
||||
|> Activity.with_joined_object()
|
||||
|> Object.with_joined_activity()
|
||||
|> select([_like, object, activity], %{activity | object: object})
|
||||
|> order_by([like, _, _], desc: like.id)
|
||||
|> Pagination.fetch_paginated(
|
||||
Map.merge(params, %{"skip_order" => true}),
|
||||
pagination,
|
||||
:object_activity
|
||||
)
|
||||
end
|
||||
|
||||
defp maybe_update_cc(activities, list_memberships, %User{ap_id: user_ap_id})
|
||||
when is_list(list_memberships) and length(list_memberships) > 0 do
|
||||
Enum.map(activities, fn
|
||||
|
|
|
@ -9,6 +9,7 @@ defmodule Pleroma.Web.ActivityPub.Publisher do
|
|||
alias Pleroma.HTTP
|
||||
alias Pleroma.Instances
|
||||
alias Pleroma.Object
|
||||
alias Pleroma.Repo
|
||||
alias Pleroma.User
|
||||
alias Pleroma.Web.ActivityPub.Relay
|
||||
alias Pleroma.Web.ActivityPub.Transmogrifier
|
||||
|
@ -188,12 +189,15 @@ def publish(%User{} = actor, %{data: %{"bcc" => bcc}} = activity)
|
|||
|
||||
recipients = recipients(actor, activity)
|
||||
|
||||
inboxes =
|
||||
recipients
|
||||
|> Enum.filter(&User.ap_enabled?/1)
|
||||
|> Enum.map(fn %{source_data: data} -> data["inbox"] end)
|
||||
|> Enum.filter(fn inbox -> should_federate?(inbox, public) end)
|
||||
|> Instances.filter_reachable()
|
||||
|> Enum.each(fn {inbox, unreachable_since} ->
|
||||
|
||||
Repo.checkout(fn ->
|
||||
Enum.each(inboxes, fn {inbox, unreachable_since} ->
|
||||
%User{ap_id: ap_id} =
|
||||
Enum.find(recipients, fn %{source_data: data} -> data["inbox"] == inbox end)
|
||||
|
||||
|
@ -214,6 +218,7 @@ def publish(%User{} = actor, %{data: %{"bcc" => bcc}} = activity)
|
|||
unreachable_since: unreachable_since
|
||||
})
|
||||
end)
|
||||
end)
|
||||
end
|
||||
|
||||
@doc """
|
||||
|
|
|
@ -787,6 +787,7 @@ def get_reports(params, page, page_size) do
|
|||
params
|
||||
|> Map.put("type", "Flag")
|
||||
|> Map.put("skip_preload", true)
|
||||
|> Map.put("preload_report_notes", true)
|
||||
|> Map.put("total", true)
|
||||
|> Map.put("limit", page_size)
|
||||
|> Map.put("offset", (page - 1) * page_size)
|
||||
|
|
|
@ -201,7 +201,6 @@ def render("followers.json", %{user: user} = opts) do
|
|||
%{
|
||||
"id" => "#{user.ap_id}/followers",
|
||||
"type" => "OrderedCollection",
|
||||
"totalItems" => total,
|
||||
"first" =>
|
||||
if showing_items do
|
||||
collection(followers, "#{user.ap_id}/followers", 1, showing_items, total)
|
||||
|
@ -209,6 +208,7 @@ def render("followers.json", %{user: user} = opts) do
|
|||
"#{user.ap_id}/followers?page=1"
|
||||
end
|
||||
}
|
||||
|> maybe_put_total_items(showing_count, total)
|
||||
|> Map.merge(Utils.make_json_ld_header())
|
||||
end
|
||||
|
||||
|
@ -251,6 +251,12 @@ def render("activity_collection_page.json", %{activities: activities, iri: iri})
|
|||
|> Map.merge(Utils.make_json_ld_header())
|
||||
end
|
||||
|
||||
defp maybe_put_total_items(map, false, _total), do: map
|
||||
|
||||
defp maybe_put_total_items(map, true, total) do
|
||||
Map.put(map, "totalItems", total)
|
||||
end
|
||||
|
||||
def collection(collection, iri, page, show_items \\ true, total \\ nil) do
|
||||
offset = (page - 1) * 10
|
||||
items = Enum.slice(collection, offset, 10)
|
||||
|
|
|
@ -7,6 +7,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
|
|||
alias Pleroma.Activity
|
||||
alias Pleroma.ModerationLog
|
||||
alias Pleroma.Plugs.OAuthScopesPlug
|
||||
alias Pleroma.ReportNote
|
||||
alias Pleroma.User
|
||||
alias Pleroma.UserInviteToken
|
||||
alias Pleroma.Web.ActivityPub.ActivityPub
|
||||
|
@ -240,7 +241,7 @@ def list_instance_statuses(conn, %{"instance" => instance} = params) do
|
|||
})
|
||||
|
||||
conn
|
||||
|> put_view(StatusView)
|
||||
|> put_view(Pleroma.Web.AdminAPI.StatusView)
|
||||
|> render("index.json", %{activities: activities, as: :activity})
|
||||
end
|
||||
|
||||
|
@ -643,9 +644,11 @@ def force_password_reset(%{assigns: %{user: admin}} = conn, %{"nicknames" => nic
|
|||
def list_reports(conn, params) do
|
||||
{page, page_size} = page_params(params)
|
||||
|
||||
reports = Utils.get_reports(params, page, page_size)
|
||||
|
||||
conn
|
||||
|> put_view(ReportView)
|
||||
|> render("index.json", %{reports: Utils.get_reports(params, page, page_size)})
|
||||
|> render("index.json", %{reports: reports})
|
||||
end
|
||||
|
||||
def list_grouped_reports(conn, _params) do
|
||||
|
@ -689,32 +692,39 @@ def reports_update(%{assigns: %{user: admin}} = conn, %{"reports" => reports}) d
|
|||
end
|
||||
end
|
||||
|
||||
def report_respond(%{assigns: %{user: user}} = conn, %{"id" => id} = params) do
|
||||
with false <- is_nil(params["status"]),
|
||||
%Activity{} <- Activity.get_by_id(id) do
|
||||
params =
|
||||
params
|
||||
|> Map.put("in_reply_to_status_id", id)
|
||||
|> Map.put("visibility", "direct")
|
||||
|
||||
{:ok, activity} = CommonAPI.post(user, params)
|
||||
|
||||
def report_notes_create(%{assigns: %{user: user}} = conn, %{
|
||||
"id" => report_id,
|
||||
"content" => content
|
||||
}) do
|
||||
with {:ok, _} <- ReportNote.create(user.id, report_id, content) do
|
||||
ModerationLog.insert_log(%{
|
||||
action: "report_response",
|
||||
action: "report_note",
|
||||
actor: user,
|
||||
subject: activity,
|
||||
text: params["status"]
|
||||
subject: Activity.get_by_id(report_id),
|
||||
text: content
|
||||
})
|
||||
|
||||
conn
|
||||
|> put_view(StatusView)
|
||||
|> render("show.json", %{activity: activity})
|
||||
json_response(conn, :no_content, "")
|
||||
else
|
||||
true ->
|
||||
{:param_cast, nil}
|
||||
_ -> json_response(conn, :bad_request, "")
|
||||
end
|
||||
end
|
||||
|
||||
nil ->
|
||||
{:error, :not_found}
|
||||
def report_notes_delete(%{assigns: %{user: user}} = conn, %{
|
||||
"id" => note_id,
|
||||
"report_id" => report_id
|
||||
}) do
|
||||
with {:ok, note} <- ReportNote.destroy(note_id) do
|
||||
ModerationLog.insert_log(%{
|
||||
action: "report_note_delete",
|
||||
actor: user,
|
||||
subject: Activity.get_by_id(report_id),
|
||||
text: note.content
|
||||
})
|
||||
|
||||
json_response(conn, :no_content, "")
|
||||
else
|
||||
_ -> json_response(conn, :bad_request, "")
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -39,7 +39,8 @@ def render("show.json", %{report: report, user: user, account: account, statuses
|
|||
content: content,
|
||||
created_at: created_at,
|
||||
statuses: StatusView.render("index.json", %{activities: statuses, as: :activity}),
|
||||
state: report.data["state"]
|
||||
state: report.data["state"],
|
||||
notes: render(__MODULE__, "index_notes.json", %{notes: report.report_notes})
|
||||
}
|
||||
end
|
||||
|
||||
|
@ -69,6 +70,28 @@ def render("index_grouped.json", %{groups: groups}) do
|
|||
}
|
||||
end
|
||||
|
||||
def render("index_notes.json", %{notes: notes}) when is_list(notes) do
|
||||
Enum.map(notes, &render(__MODULE__, "show_note.json", &1))
|
||||
end
|
||||
|
||||
def render("index_notes.json", _), do: []
|
||||
|
||||
def render("show_note.json", %{
|
||||
id: id,
|
||||
content: content,
|
||||
user_id: user_id,
|
||||
inserted_at: inserted_at
|
||||
}) do
|
||||
user = User.get_by_id(user_id)
|
||||
|
||||
%{
|
||||
id: id,
|
||||
content: content,
|
||||
user: merge_account_views(user),
|
||||
created_at: Utils.to_masto_date(inserted_at)
|
||||
}
|
||||
end
|
||||
|
||||
defp merge_account_views(%User{} = user) do
|
||||
Pleroma.Web.MastodonAPI.AccountView.render("show.json", %{user: user})
|
||||
|> Map.merge(Pleroma.Web.AdminAPI.AccountView.render("show.json", %{user: user}))
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
# Pleroma: A lightweight social networking server
|
||||
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.Web.AdminAPI.StatusView do
|
||||
use Pleroma.Web, :view
|
||||
|
||||
require Pleroma.Constants
|
||||
|
||||
alias Pleroma.User
|
||||
|
||||
def render("index.json", opts) do
|
||||
render_many(opts.activities, __MODULE__, "show.json", opts)
|
||||
end
|
||||
|
||||
def render("show.json", %{activity: %{data: %{"object" => _object}} = activity} = opts) do
|
||||
user = get_user(activity.data["actor"])
|
||||
|
||||
Pleroma.Web.MastodonAPI.StatusView.render("show.json", opts)
|
||||
|> Map.merge(%{account: merge_account_views(user)})
|
||||
end
|
||||
|
||||
defp merge_account_views(%User{} = user) do
|
||||
Pleroma.Web.MastodonAPI.AccountView.render("show.json", %{user: user})
|
||||
|> Map.merge(Pleroma.Web.AdminAPI.AccountView.render("show.json", %{user: user}))
|
||||
end
|
||||
|
||||
defp merge_account_views(_), do: %{}
|
||||
|
||||
defp get_user(ap_id) do
|
||||
cond do
|
||||
user = User.get_cached_by_ap_id(ap_id) ->
|
||||
user
|
||||
|
||||
user = User.get_by_guessed_nickname(ap_id) ->
|
||||
user
|
||||
|
||||
true ->
|
||||
User.error_user(ap_id)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -346,15 +346,11 @@ def context(%{assigns: %{user: user}} = conn, %{"id" => id}) do
|
|||
|
||||
@doc "GET /api/v1/favourites"
|
||||
def favourites(%{assigns: %{user: user}} = conn, params) do
|
||||
params =
|
||||
params
|
||||
|> Map.put("type", "Create")
|
||||
|> Map.put("favorited_by", user.ap_id)
|
||||
|> Map.put("blocking_user", user)
|
||||
|
||||
activities =
|
||||
ActivityPub.fetch_activities([], params)
|
||||
|> Enum.reverse()
|
||||
ActivityPub.fetch_favourites(
|
||||
user,
|
||||
Map.take(params, Pleroma.Pagination.page_keys())
|
||||
)
|
||||
|
||||
conn
|
||||
|> add_link_headers(activities)
|
||||
|
|
|
@ -79,7 +79,9 @@ defp authorize_admin_scopes(scopes, app_scopes, %User{} = user) do
|
|||
if user.is_admin || !contains_admin_scopes?(scopes) || !contains_admin_scopes?(app_scopes) do
|
||||
{:ok, scopes}
|
||||
else
|
||||
{:error, :unsupported_scopes}
|
||||
# Gracefully dropping admin scopes from requested scopes if user isn't an admin (not raising)
|
||||
scopes = scopes -- OAuthScopesPlug.filter_descendants(scopes, ["admin"])
|
||||
validate(scopes, app_scopes, user)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -187,7 +187,8 @@ defmodule Pleroma.Web.Router do
|
|||
get("/grouped_reports", AdminAPIController, :list_grouped_reports)
|
||||
get("/reports/:id", AdminAPIController, :report_show)
|
||||
patch("/reports", AdminAPIController, :reports_update)
|
||||
post("/reports/:id/respond", AdminAPIController, :report_respond)
|
||||
post("/reports/:id/notes", AdminAPIController, :report_notes_create)
|
||||
delete("/reports/:report_id/notes/:id", AdminAPIController, :report_notes_delete)
|
||||
|
||||
put("/statuses/:id", AdminAPIController, :status_update)
|
||||
delete("/statuses/:id", AdminAPIController, :status_delete)
|
||||
|
|
3
mix.exs
3
mix.exs
|
@ -163,6 +163,9 @@ defp deps do
|
|||
{:remote_ip,
|
||||
git: "https://git.pleroma.social/pleroma/remote_ip.git",
|
||||
ref: "825dc00aaba5a1b7c4202a532b696b595dd3bcb3"},
|
||||
{:captcha,
|
||||
git: "https://git.pleroma.social/pleroma/elixir-libraries/elixir-captcha.git",
|
||||
ref: "c3c795c55f6b49d79d6ac70a0f91e525099fc3e2"},
|
||||
{:mox, "~> 0.5", only: :test}
|
||||
] ++ oauth_deps()
|
||||
end
|
||||
|
|
1
mix.lock
1
mix.lock
|
@ -8,6 +8,7 @@
|
|||
"bunt": {:hex, :bunt, "0.2.0", "951c6e801e8b1d2cbe58ebbd3e616a869061ddadcc4863d0a2182541acae9a38", [:mix], [], "hexpm"},
|
||||
"cachex": {:hex, :cachex, "3.0.3", "4e2d3e05814a5738f5ff3903151d5c25636d72a3527251b753f501ad9c657967", [:mix], [{:eternal, "~> 1.2", [hex: :eternal, repo: "hexpm", optional: false]}, {:unsafe, "~> 1.0", [hex: :unsafe, repo: "hexpm", optional: false]}], "hexpm"},
|
||||
"calendar": {:hex, :calendar, "0.17.6", "ec291cb2e4ba499c2e8c0ef5f4ace974e2f9d02ae9e807e711a9b0c7850b9aee", [:mix], [{:tzdata, "~> 0.5.20 or ~> 0.1.201603 or ~> 1.0", [hex: :tzdata, repo: "hexpm", optional: false]}], "hexpm"},
|
||||
"captcha": {:git, "https://git.pleroma.social/pleroma/elixir-libraries/elixir-captcha.git", "c3c795c55f6b49d79d6ac70a0f91e525099fc3e2", [ref: "c3c795c55f6b49d79d6ac70a0f91e525099fc3e2"]},
|
||||
"certifi": {:hex, :certifi, "2.5.1", "867ce347f7c7d78563450a18a6a28a8090331e77fa02380b4a21962a65d36ee5", [:rebar3], [{:parse_trans, "~>3.3", [hex: :parse_trans, repo: "hexpm", optional: false]}], "hexpm"},
|
||||
"combine": {:hex, :combine, "0.10.0", "eff8224eeb56498a2af13011d142c5e7997a80c8f5b97c499f84c841032e429f", [:mix], [], "hexpm"},
|
||||
"comeonin": {:hex, :comeonin, "4.1.2", "3eb5620fd8e35508991664b4c2b04dd41e52f1620b36957be837c1d7784b7592", [:mix], [{:argon2_elixir, "~> 1.2", [hex: :argon2_elixir, repo: "hexpm", optional: true]}, {:bcrypt_elixir, "~> 0.12.1 or ~> 1.0", [hex: :bcrypt_elixir, repo: "hexpm", optional: true]}, {:pbkdf2_elixir, "~> 0.12", [hex: :pbkdf2_elixir, repo: "hexpm", optional: true]}], "hexpm"},
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
defmodule Pleroma.Repo.Migrations.CreateReportNotes do
|
||||
use Ecto.Migration
|
||||
|
||||
def change do
|
||||
create_if_not_exists table(:report_notes) do
|
||||
add(:user_id, references(:users, type: :uuid))
|
||||
add(:activity_id, references(:activities, type: :uuid))
|
||||
add(:content, :string)
|
||||
|
||||
timestamps()
|
||||
end
|
||||
end
|
||||
end
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -1 +1 @@
|
|||
<!DOCTYPE html><html><head><meta charset=utf-8><meta http-equiv=X-UA-Compatible content="IE=edge,chrome=1"><meta name=renderer content=webkit><meta name=viewport content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no"><title>Admin FE</title><link rel="shortcut icon" href=favicon.ico><link href=chunk-elementUI.fbcb853d.css rel=stylesheet><link href=chunk-libs.74279b9a.css rel=stylesheet><link href=app.2d7d6c47.css rel=stylesheet></head><body><div id=app></div><script type=text/javascript src=static/js/runtime.5485cb1b.js></script><script type=text/javascript src=static/js/chunk-elementUI.adb56751.js></script><script type=text/javascript src=static/js/chunk-libs.16bdd178.js></script><script type=text/javascript src=static/js/app.9abe83aa.js></script></body></html>
|
||||
<!DOCTYPE html><html><head><meta charset=utf-8><meta http-equiv=X-UA-Compatible content="IE=edge,chrome=1"><meta name=renderer content=webkit><meta name=viewport content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no"><title>Admin FE</title><link rel="shortcut icon" href=favicon.ico><link href=chunk-elementUI.a842fb0a.css rel=stylesheet><link href=chunk-libs.57fe98a3.css rel=stylesheet><link href=app.8589ec81.css rel=stylesheet></head><body><script src=/pleroma/admin/static/tinymce4.7.5/tinymce.min.js></script><div id=app></div><script type=text/javascript src=static/js/runtime.46db235c.js></script><script type=text/javascript src=static/js/chunk-elementUI.fa319e7b.js></script><script type=text/javascript src=static/js/chunk-libs.35c18287.js></script><script type=text/javascript src=static/js/app.9c4316f1.js></script></body></html>
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -1 +1 @@
|
|||
<!DOCTYPE html><html lang=en><head><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1,user-scalable=no"><title>Pleroma</title><!--server-generated-meta--><link rel=icon type=image/png href=/favicon.png><link href=/static/css/vendors~app.b2603a50868c68a1c192.css rel=stylesheet><link href=/static/css/app.ae04505b31bb0ee2765e.css rel=stylesheet><link href=/static/fontello.1576078371855.css rel=stylesheet></head><body class=hidden><noscript>To use Pleroma, please enable JavaScript.</noscript><div id=app></div><script type=text/javascript src=/static/js/vendors~app.3f1ed7a4fdfc37ee27a7.js></script><script type=text/javascript src=/static/js/app.5879b8f3d0565ed4735f.js></script></body></html>
|
||||
<!DOCTYPE html><html lang=en><head><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1,user-scalable=no"><title>Pleroma</title><!--server-generated-meta--><link rel=icon type=image/png href=/favicon.png><link href=/static/css/vendors~app.b2603a50868c68a1c192.css rel=stylesheet><link href=/static/css/app.ae04505b31bb0ee2765e.css rel=stylesheet><link href=/static/fontello.1576166651574.css rel=stylesheet></head><body class=hidden><noscript>To use Pleroma, please enable JavaScript.</noscript><div id=app></div><script type=text/javascript src=/static/js/vendors~app.3f1ed7a4fdfc37ee27a7.js></script><script type=text/javascript src=/static/js/app.a9b3f4c3e79baf3fa8b7.js></script></body></html>
|
|
@ -1,39 +0,0 @@
|
|||
Font license info
|
||||
|
||||
|
||||
## Font Awesome
|
||||
|
||||
Copyright (C) 2016 by Dave Gandy
|
||||
|
||||
Author: Dave Gandy
|
||||
License: SIL ()
|
||||
Homepage: http://fortawesome.github.com/Font-Awesome/
|
||||
|
||||
|
||||
## Entypo
|
||||
|
||||
Copyright (C) 2012 by Daniel Bruce
|
||||
|
||||
Author: Daniel Bruce
|
||||
License: SIL (http://scripts.sil.org/OFL)
|
||||
Homepage: http://www.entypo.com
|
||||
|
||||
|
||||
## Iconic
|
||||
|
||||
Copyright (C) 2012 by P.J. Onori
|
||||
|
||||
Author: P.J. Onori
|
||||
License: SIL (http://scripts.sil.org/OFL)
|
||||
Homepage: http://somerandomdude.com/work/iconic/
|
||||
|
||||
|
||||
## Fontelico
|
||||
|
||||
Copyright (C) 2012 by Fontello project
|
||||
|
||||
Author: Crowdsourced, for Fontello project
|
||||
License: SIL (http://scripts.sil.org/OFL)
|
||||
Homepage: http://fontello.com
|
||||
|
||||
|
|
@ -1,75 +0,0 @@
|
|||
This webfont is generated by http://fontello.com open source project.
|
||||
|
||||
|
||||
================================================================================
|
||||
Please, note, that you should obey original font licenses, used to make this
|
||||
webfont pack. Details available in LICENSE.txt file.
|
||||
|
||||
- Usually, it's enough to publish content of LICENSE.txt file somewhere on your
|
||||
site in "About" section.
|
||||
|
||||
- If your project is open-source, usually, it will be ok to make LICENSE.txt
|
||||
file publicly available in your repository.
|
||||
|
||||
- Fonts, used in Fontello, don't require a clickable link on your site.
|
||||
But any kind of additional authors crediting is welcome.
|
||||
================================================================================
|
||||
|
||||
|
||||
Comments on archive content
|
||||
---------------------------
|
||||
|
||||
- /font/* - fonts in different formats
|
||||
|
||||
- /css/* - different kinds of css, for all situations. Should be ok with
|
||||
twitter bootstrap. Also, you can skip <i> style and assign icon classes
|
||||
directly to text elements, if you don't mind about IE7.
|
||||
|
||||
- demo.html - demo file, to show your webfont content
|
||||
|
||||
- LICENSE.txt - license info about source fonts, used to build your one.
|
||||
|
||||
- config.json - keeps your settings. You can import it back into fontello
|
||||
anytime, to continue your work
|
||||
|
||||
|
||||
Why so many CSS files ?
|
||||
-----------------------
|
||||
|
||||
Because we like to fit all your needs :)
|
||||
|
||||
- basic file, <your_font_name>.css - is usually enough, it contains @font-face
|
||||
and character code definitions
|
||||
|
||||
- *-ie7.css - if you need IE7 support, but still don't wish to put char codes
|
||||
directly into html
|
||||
|
||||
- *-codes.css and *-ie7-codes.css - if you like to use your own @font-face
|
||||
rules, but still wish to benefit from css generation. That can be very
|
||||
convenient for automated asset build systems. When you need to update font -
|
||||
no need to manually edit files, just override old version with archive
|
||||
content. See fontello source code for examples.
|
||||
|
||||
- *-embedded.css - basic css file, but with embedded WOFF font, to avoid
|
||||
CORS issues in Firefox and IE9+, when fonts are hosted on the separate domain.
|
||||
We strongly recommend to resolve this issue by `Access-Control-Allow-Origin`
|
||||
server headers. But if you ok with dirty hack - this file is for you. Note,
|
||||
that data url moved to separate @font-face to avoid problems with <IE9, when
|
||||
string is too long.
|
||||
|
||||
- animate.css - use it to get ideas about spinner rotation animation.
|
||||
|
||||
|
||||
Attention for server setup
|
||||
--------------------------
|
||||
|
||||
You MUST setup server to reply with proper `mime-types` for font files -
|
||||
otherwise some browsers will fail to show fonts.
|
||||
|
||||
Usually, `apache` already has necessary settings, but `nginx` and other
|
||||
webservers should be tuned. Here is list of mime types for our file extensions:
|
||||
|
||||
- `application/vnd.ms-fontobject` - eot
|
||||
- `application/x-font-woff` - woff
|
||||
- `application/x-font-ttf` - ttf
|
||||
- `image/svg+xml` - svg
|
|
@ -1,308 +0,0 @@
|
|||
{
|
||||
"name": "",
|
||||
"css_prefix_text": "icon-",
|
||||
"css_use_suffix": false,
|
||||
"hinting": true,
|
||||
"units_per_em": 1000,
|
||||
"ascent": 857,
|
||||
"glyphs": [
|
||||
{
|
||||
"uid": "9bd60140934a1eb9236fd7a8ab1ff6ba",
|
||||
"css": "spin4",
|
||||
"code": 59444,
|
||||
"src": "fontelico"
|
||||
},
|
||||
{
|
||||
"uid": "5211af474d3a9848f67f945e2ccaf143",
|
||||
"css": "cancel",
|
||||
"code": 59392,
|
||||
"src": "fontawesome"
|
||||
},
|
||||
{
|
||||
"uid": "eeec3208c90b7b48e804919d0d2d4a41",
|
||||
"css": "upload",
|
||||
"code": 59393,
|
||||
"src": "fontawesome"
|
||||
},
|
||||
{
|
||||
"uid": "2a6740fc2f9d0edea54205963f662594",
|
||||
"css": "spin3",
|
||||
"code": 59442,
|
||||
"src": "fontelico"
|
||||
},
|
||||
{
|
||||
"uid": "c6be5a58ee4e63a5ec399c2b0d15cf2c",
|
||||
"css": "reply",
|
||||
"code": 61714,
|
||||
"src": "fontawesome"
|
||||
},
|
||||
{
|
||||
"uid": "474656633f79ea2f1dad59ff63f6bf07",
|
||||
"css": "star",
|
||||
"code": 59394,
|
||||
"src": "fontawesome"
|
||||
},
|
||||
{
|
||||
"uid": "d17030afaecc1e1c22349b99f3c4992a",
|
||||
"css": "star-empty",
|
||||
"code": 59395,
|
||||
"src": "fontawesome"
|
||||
},
|
||||
{
|
||||
"uid": "09feb4465d9bd1364f4e301c9ddbaa92",
|
||||
"css": "retweet",
|
||||
"code": 59396,
|
||||
"src": "fontawesome"
|
||||
},
|
||||
{
|
||||
"uid": "7fd683b2c518ceb9e5fa6757f2276faa",
|
||||
"css": "eye-off",
|
||||
"code": 59397,
|
||||
"src": "fontawesome"
|
||||
},
|
||||
{
|
||||
"uid": "73ffeb70554099177620847206c12457",
|
||||
"css": "binoculars",
|
||||
"code": 61925,
|
||||
"src": "fontawesome"
|
||||
},
|
||||
{
|
||||
"uid": "e99461abfef3923546da8d745372c995",
|
||||
"css": "cog",
|
||||
"code": 59399,
|
||||
"src": "fontawesome"
|
||||
},
|
||||
{
|
||||
"uid": "1bafeeb1808a5fe24484c7890096901a",
|
||||
"css": "user-plus",
|
||||
"code": 62004,
|
||||
"src": "fontawesome"
|
||||
},
|
||||
{
|
||||
"uid": "559647a6f430b3aeadbecd67194451dd",
|
||||
"css": "menu",
|
||||
"code": 61641,
|
||||
"src": "fontawesome"
|
||||
},
|
||||
{
|
||||
"uid": "0d20938846444af8deb1920dc85a29fb",
|
||||
"css": "logout",
|
||||
"code": 59400,
|
||||
"src": "fontawesome"
|
||||
},
|
||||
{
|
||||
"uid": "ccddff8e8670dcd130e3cb55fdfc2fd0",
|
||||
"css": "down-open",
|
||||
"code": 59401,
|
||||
"src": "fontawesome"
|
||||
},
|
||||
{
|
||||
"uid": "44b9e75612c5fad5505edd70d071651f",
|
||||
"css": "attach",
|
||||
"code": 59402,
|
||||
"src": "entypo"
|
||||
},
|
||||
{
|
||||
"uid": "e15f0d620a7897e2035c18c80142f6d9",
|
||||
"css": "link-ext",
|
||||
"code": 61582,
|
||||
"src": "fontawesome"
|
||||
},
|
||||
{
|
||||
"uid": "e35de5ea31cd56970498e33efbcb8e36",
|
||||
"css": "link-ext-alt",
|
||||
"code": 61583,
|
||||
"src": "fontawesome"
|
||||
},
|
||||
{
|
||||
"uid": "381da2c2f7fd51f8de877c044d7f439d",
|
||||
"css": "picture",
|
||||
"code": 59403,
|
||||
"src": "fontawesome"
|
||||
},
|
||||
{
|
||||
"uid": "872d9516df93eb6b776cc4d94bd97dac",
|
||||
"css": "video",
|
||||
"code": 59404,
|
||||
"src": "fontawesome"
|
||||
},
|
||||
{
|
||||
"uid": "399ef63b1e23ab1b761dfbb5591fa4da",
|
||||
"css": "right-open",
|
||||
"code": 59405,
|
||||
"src": "fontawesome"
|
||||
},
|
||||
{
|
||||
"uid": "d870630ff8f81e6de3958ecaeac532f2",
|
||||
"css": "left-open",
|
||||
"code": 59406,
|
||||
"src": "fontawesome"
|
||||
},
|
||||
{
|
||||
"uid": "fe6697b391355dec12f3d86d6d490397",
|
||||
"css": "up-open",
|
||||
"code": 59407,
|
||||
"src": "fontawesome"
|
||||
},
|
||||
{
|
||||
"uid": "9c1376672bb4f1ed616fdd78a23667e9",
|
||||
"css": "comment-empty",
|
||||
"code": 61669,
|
||||
"src": "fontawesome"
|
||||
},
|
||||
{
|
||||
"uid": "ccc2329632396dc096bb638d4b46fb98",
|
||||
"css": "mail-alt",
|
||||
"code": 61664,
|
||||
"src": "fontawesome"
|
||||
},
|
||||
{
|
||||
"uid": "c1f1975c885aa9f3dad7810c53b82074",
|
||||
"css": "lock",
|
||||
"code": 59409,
|
||||
"src": "fontawesome"
|
||||
},
|
||||
{
|
||||
"uid": "05376be04a27d5a46e855a233d6e8508",
|
||||
"css": "lock-open-alt",
|
||||
"code": 61758,
|
||||
"src": "fontawesome"
|
||||
},
|
||||
{
|
||||
"uid": "197375a3cea8cb90b02d06e4ddf1433d",
|
||||
"css": "globe",
|
||||
"code": 59410,
|
||||
"src": "fontawesome"
|
||||
},
|
||||
{
|
||||
"uid": "b3a9e2dab4d19ea3b2f628242c926bfe",
|
||||
"css": "brush",
|
||||
"code": 59411,
|
||||
"src": "iconic"
|
||||
},
|
||||
{
|
||||
"uid": "9dd9e835aebe1060ba7190ad2b2ed951",
|
||||
"css": "search",
|
||||
"code": 59398,
|
||||
"src": "fontawesome"
|
||||
},
|
||||
{
|
||||
"uid": "ca90da02d2c6a3183f2458e4dc416285",
|
||||
"css": "adjust",
|
||||
"code": 59414,
|
||||
"src": "fontawesome"
|
||||
},
|
||||
{
|
||||
"uid": "5e2ab018e3044337bcef5f7e94098ea1",
|
||||
"css": "thumbs-up-alt",
|
||||
"code": 61796,
|
||||
"src": "fontawesome"
|
||||
},
|
||||
{
|
||||
"uid": "c76b7947c957c9b78b11741173c8349b",
|
||||
"css": "attention",
|
||||
"code": 59412,
|
||||
"src": "fontawesome"
|
||||
},
|
||||
{
|
||||
"uid": "1a5cfa186647e8c929c2b17b9fc4dac1",
|
||||
"css": "plus-squared",
|
||||
"code": 61694,
|
||||
"src": "fontawesome"
|
||||
},
|
||||
{
|
||||
"uid": "44e04715aecbca7f266a17d5a7863c68",
|
||||
"css": "plus",
|
||||
"code": 59413,
|
||||
"src": "fontawesome"
|
||||
},
|
||||
{
|
||||
"uid": "41087bc74d4b20b55059c60a33bf4008",
|
||||
"css": "edit",
|
||||
"code": 59415,
|
||||
"src": "fontawesome"
|
||||
},
|
||||
{
|
||||
"uid": "5717236f6134afe2d2a278a5c9b3927a",
|
||||
"css": "play-circled",
|
||||
"code": 61764,
|
||||
"src": "fontawesome"
|
||||
},
|
||||
{
|
||||
"uid": "d35a1d35efeb784d1dc9ac18b9b6c2b6",
|
||||
"css": "pencil",
|
||||
"code": 59416,
|
||||
"src": "fontawesome"
|
||||
},
|
||||
{
|
||||
"uid": "266d5d9adf15a61800477a5acf9a4462",
|
||||
"css": "chart-bar",
|
||||
"code": 59419,
|
||||
"src": "fontawesome"
|
||||
},
|
||||
{
|
||||
"uid": "d862a10e1448589215be19702f98f2c1",
|
||||
"css": "smile",
|
||||
"code": 61720,
|
||||
"src": "fontawesome"
|
||||
},
|
||||
{
|
||||
"uid": "671f29fa10dda08074a4c6a341bb4f39",
|
||||
"css": "bell-alt",
|
||||
"code": 61683,
|
||||
"src": "fontawesome"
|
||||
},
|
||||
{
|
||||
"uid": "5bb103cd29de77e0e06a52638527b575",
|
||||
"css": "wrench",
|
||||
"code": 59418,
|
||||
"src": "fontawesome"
|
||||
},
|
||||
{
|
||||
"uid": "5b0772e9484a1a11646793a82edd622a",
|
||||
"css": "pin",
|
||||
"code": 59417,
|
||||
"src": "fontawesome"
|
||||
},
|
||||
{
|
||||
"uid": "22411a88489225a018f68db737de3c77",
|
||||
"css": "ellipsis",
|
||||
"code": 61761,
|
||||
"src": "custom_icons",
|
||||
"selected": true,
|
||||
"svg": {
|
||||
"path": "M214 411V518Q214 540 199 556T161 571H54Q31 571 16 556T0 518V411Q0 388 16 373T54 357H161Q183 357 199 373T214 411ZM500 411V518Q500 540 484 556T446 571H339Q317 571 301 556T286 518V411Q286 388 301 373T339 357H446Q469 357 484 373T500 411ZM786 411V518Q786 540 770 556T732 571H625Q603 571 587 556T571 518V411Q571 388 587 373T625 357H732Q755 357 770 373T786 411Z",
|
||||
"width": 785.7
|
||||
},
|
||||
"search": [
|
||||
"ellipsis"
|
||||
]
|
||||
},
|
||||
{
|
||||
"uid": "0bef873af785ead27781fdf98b3ae740",
|
||||
"css": "bell-ringing-o",
|
||||
"code": 59408,
|
||||
"src": "custom_icons",
|
||||
"selected": true,
|
||||
"svg": {
|
||||
"path": "M497.8 0C468.3 0 444.4 23.9 444.4 53.3 444.4 61.1 446.1 68.3 448.9 75 301.7 96.7 213.3 213.3 213.3 320 213.3 588.3 117.8 712.8 35.6 782.2 35.6 821.1 67.8 853.3 106.7 853.3H355.6C355.6 931.7 419.4 995.6 497.8 995.6S640 931.7 640 853.3H888.9C927.8 853.3 960 821.1 960 782.2 877.8 712.8 782.2 588.3 782.2 320 782.2 213.3 693.9 96.7 546.7 75 549.4 68.3 551.1 61.1 551.1 53.3 551.1 23.9 527.2 0 497.8 0ZM189.4 44.8C108.4 118.6 70.5 215.1 71.1 320.2L142.2 319.8C141.7 231.2 170.4 158.3 237.3 97.4L189.4 44.8ZM806.2 44.8L758.3 97.4C825.2 158.3 853.9 231.2 853.3 319.8L924.4 320.2C925.1 215.1 887.2 118.6 806.2 44.8ZM408.9 844.4C413.9 844.4 417.8 848.3 417.8 853.3 417.8 897.2 453.9 933.3 497.8 933.3 502.8 933.3 506.7 937.2 506.7 942.2S502.8 951.1 497.8 951.1C443.9 951.1 400 907.2 400 853.3 400 848.3 403.9 844.4 408.9 844.4Z",
|
||||
"width": 1000
|
||||
},
|
||||
"search": [
|
||||
"bell-ringing-o"
|
||||
]
|
||||
},
|
||||
{
|
||||
"uid": "0b2b66e526028a6972d51a6f10281b4b",
|
||||
"css": "zoom-in",
|
||||
"code": 59420,
|
||||
"src": "fontawesome"
|
||||
},
|
||||
{
|
||||
"uid": "0bda4bc779d4c32623dec2e43bd67ee8",
|
||||
"css": "gauge",
|
||||
"code": 61668,
|
||||
"src": "fontawesome"
|
||||
}
|
||||
]
|
||||
}
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue