Merge remote-tracking branch 'upstream/develop' into restrict-origin
This commit is contained in:
commit
3f9263fb16
663 changed files with 16301 additions and 12107 deletions
|
|
@ -214,6 +214,10 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController.UpdateCredentialsTest do
|
|||
|
||||
assert user_data = json_response_and_validate_schema(conn, 200)
|
||||
assert user_data["display_name"] == "markorepairs"
|
||||
|
||||
update_activity = Repo.one(Pleroma.Activity)
|
||||
assert update_activity.data["type"] == "Update"
|
||||
assert update_activity.data["object"]["name"] == "markorepairs"
|
||||
end
|
||||
|
||||
test "updates the user's avatar", %{user: user, conn: conn} do
|
||||
|
|
|
|||
|
|
@ -1442,7 +1442,10 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do
|
|||
describe "verify_credentials" do
|
||||
test "verify_credentials" do
|
||||
%{user: user, conn: conn} = oauth_access(["read:accounts"])
|
||||
[notification | _] = insert_list(7, :notification, user: user)
|
||||
|
||||
[notification | _] =
|
||||
insert_list(7, :notification, user: user, activity: insert(:note_activity))
|
||||
|
||||
Pleroma.Notification.set_read_up_to(user, notification.id)
|
||||
conn = get(conn, "/api/v1/accounts/verify_credentials")
|
||||
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ defmodule Pleroma.Web.MastodonAPI.AuthControllerTest do
|
|||
end
|
||||
|
||||
test "it returns 204", %{conn: conn} do
|
||||
assert json_response(conn, :no_content)
|
||||
assert empty_json_response(conn)
|
||||
end
|
||||
|
||||
test "it creates a PasswordResetToken record for user", %{user: user} do
|
||||
|
|
@ -91,7 +91,7 @@ defmodule Pleroma.Web.MastodonAPI.AuthControllerTest do
|
|||
|
||||
assert conn
|
||||
|> post("/auth/password?nickname=#{user.nickname}")
|
||||
|> json_response(:no_content)
|
||||
|> empty_json_response()
|
||||
|
||||
ObanHelpers.perform_all()
|
||||
token_record = Repo.get_by(Pleroma.PasswordResetToken, user_id: user.id)
|
||||
|
|
@ -112,7 +112,7 @@ defmodule Pleroma.Web.MastodonAPI.AuthControllerTest do
|
|||
|
||||
assert conn
|
||||
|> post("/auth/password?nickname=#{user.nickname}")
|
||||
|> json_response(:no_content)
|
||||
|> empty_json_response()
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -122,17 +122,24 @@ defmodule Pleroma.Web.MastodonAPI.AuthControllerTest do
|
|||
{:ok, user: user}
|
||||
end
|
||||
|
||||
test "it returns 404 when user is not found", %{conn: conn, user: user} do
|
||||
test "it returns 204 when user is not found", %{conn: conn, user: user} do
|
||||
conn = post(conn, "/auth/password?email=nonexisting_#{user.email}")
|
||||
assert conn.status == 404
|
||||
assert conn.resp_body == ""
|
||||
|
||||
assert empty_json_response(conn)
|
||||
end
|
||||
|
||||
test "it returns 400 when user is not local", %{conn: conn, user: user} do
|
||||
test "it returns 204 when user is not local", %{conn: conn, user: user} do
|
||||
{:ok, user} = Repo.update(Ecto.Changeset.change(user, local: false))
|
||||
conn = post(conn, "/auth/password?email=#{user.email}")
|
||||
assert conn.status == 400
|
||||
assert conn.resp_body == ""
|
||||
|
||||
assert empty_json_response(conn)
|
||||
end
|
||||
|
||||
test "it returns 204 when user is deactivated", %{conn: conn, user: user} do
|
||||
{:ok, user} = Repo.update(Ecto.Changeset.change(user, deactivated: true, local: true))
|
||||
conn = post(conn, "/auth/password?email=#{user.email}")
|
||||
|
||||
assert empty_json_response(conn)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -64,11 +64,13 @@ defmodule Pleroma.Web.MastodonAPI.FilterControllerTest do
|
|||
test "get a filter" do
|
||||
%{user: user, conn: conn} = oauth_access(["read:filters"])
|
||||
|
||||
# check whole_word false
|
||||
query = %Pleroma.Filter{
|
||||
user_id: user.id,
|
||||
filter_id: 2,
|
||||
phrase: "knight",
|
||||
context: ["home"]
|
||||
context: ["home"],
|
||||
whole_word: false
|
||||
}
|
||||
|
||||
{:ok, filter} = Pleroma.Filter.create(query)
|
||||
|
|
@ -76,6 +78,25 @@ defmodule Pleroma.Web.MastodonAPI.FilterControllerTest do
|
|||
conn = get(conn, "/api/v1/filters/#{filter.filter_id}")
|
||||
|
||||
assert response = json_response_and_validate_schema(conn, 200)
|
||||
assert response["whole_word"] == false
|
||||
|
||||
# check whole_word true
|
||||
%{user: user, conn: conn} = oauth_access(["read:filters"])
|
||||
|
||||
query = %Pleroma.Filter{
|
||||
user_id: user.id,
|
||||
filter_id: 3,
|
||||
phrase: "knight",
|
||||
context: ["home"],
|
||||
whole_word: true
|
||||
}
|
||||
|
||||
{:ok, filter} = Pleroma.Filter.create(query)
|
||||
|
||||
conn = get(conn, "/api/v1/filters/#{filter.filter_id}")
|
||||
|
||||
assert response = json_response_and_validate_schema(conn, 200)
|
||||
assert response["whole_word"] == true
|
||||
end
|
||||
|
||||
test "update a filter" do
|
||||
|
|
@ -86,7 +107,8 @@ defmodule Pleroma.Web.MastodonAPI.FilterControllerTest do
|
|||
filter_id: 2,
|
||||
phrase: "knight",
|
||||
context: ["home"],
|
||||
hide: true
|
||||
hide: true,
|
||||
whole_word: true
|
||||
}
|
||||
|
||||
{:ok, _filter} = Pleroma.Filter.create(query)
|
||||
|
|
@ -108,6 +130,7 @@ defmodule Pleroma.Web.MastodonAPI.FilterControllerTest do
|
|||
assert response["phrase"] == new.phrase
|
||||
assert response["context"] == new.context
|
||||
assert response["irreversible"] == true
|
||||
assert response["whole_word"] == true
|
||||
end
|
||||
|
||||
test "delete a filter" do
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ defmodule Pleroma.Web.MastodonAPI.ListControllerTest do
|
|||
assert following == [other_user.follower_address]
|
||||
end
|
||||
|
||||
test "removing users from a list" do
|
||||
test "removing users from a list, body params" do
|
||||
%{user: user, conn: conn} = oauth_access(["write:lists"])
|
||||
other_user = insert(:user)
|
||||
third_user = insert(:user)
|
||||
|
|
@ -85,6 +85,24 @@ defmodule Pleroma.Web.MastodonAPI.ListControllerTest do
|
|||
assert following == [third_user.follower_address]
|
||||
end
|
||||
|
||||
test "removing users from a list, query params" do
|
||||
%{user: user, conn: conn} = oauth_access(["write:lists"])
|
||||
other_user = insert(:user)
|
||||
third_user = insert(:user)
|
||||
{:ok, list} = Pleroma.List.create("name", user)
|
||||
{:ok, list} = Pleroma.List.follow(list, other_user)
|
||||
{:ok, list} = Pleroma.List.follow(list, third_user)
|
||||
|
||||
assert %{} ==
|
||||
conn
|
||||
|> put_req_header("content-type", "application/json")
|
||||
|> delete("/api/v1/lists/#{list.id}/accounts?account_ids[]=#{other_user.id}")
|
||||
|> json_response_and_validate_schema(:ok)
|
||||
|
||||
%Pleroma.List{following: following} = Pleroma.List.get(list.id, user)
|
||||
assert following == [third_user.follower_address]
|
||||
end
|
||||
|
||||
test "listing users in a list" do
|
||||
%{user: user, conn: conn} = oauth_access(["read:lists"])
|
||||
other_user = insert(:user)
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ defmodule Pleroma.Web.MastodonAPI.MarkerControllerTest do
|
|||
test "gets markers with correct scopes", %{conn: conn} do
|
||||
user = insert(:user)
|
||||
token = insert(:oauth_token, user: user, scopes: ["read:statuses"])
|
||||
insert_list(7, :notification, user: user)
|
||||
insert_list(7, :notification, user: user, activity: insert(:note_activity))
|
||||
|
||||
{:ok, %{"notifications" => marker}} =
|
||||
Pleroma.Marker.upsert(
|
||||
|
|
|
|||
|
|
@ -282,18 +282,18 @@ defmodule Pleroma.Web.MastodonAPI.SearchControllerTest do
|
|||
capture_log(fn ->
|
||||
{:ok, %{id: activity_id}} =
|
||||
CommonAPI.post(insert(:user), %{
|
||||
status: "check out https://shitposter.club/notice/2827873"
|
||||
status: "check out http://mastodon.example.org/@admin/99541947525187367"
|
||||
})
|
||||
|
||||
results =
|
||||
conn
|
||||
|> get("/api/v1/search?q=https://shitposter.club/notice/2827873")
|
||||
|> get("/api/v1/search?q=http://mastodon.example.org/@admin/99541947525187367")
|
||||
|> json_response_and_validate_schema(200)
|
||||
|
||||
[status, %{"id" => ^activity_id}] = results["statuses"]
|
||||
|
||||
assert status["uri"] ==
|
||||
"tag:shitposter.club,2017-05-05:noticeId=2827873:objectType=comment"
|
||||
assert [
|
||||
%{"url" => "http://mastodon.example.org/@admin/99541947525187367"},
|
||||
%{"id" => ^activity_id}
|
||||
] = results["statuses"]
|
||||
end)
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -4,9 +4,9 @@
|
|||
|
||||
defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do
|
||||
use Pleroma.Web.ConnCase
|
||||
use Oban.Testing, repo: Pleroma.Repo
|
||||
|
||||
alias Pleroma.Activity
|
||||
alias Pleroma.ActivityExpiration
|
||||
alias Pleroma.Config
|
||||
alias Pleroma.Conversation.Participation
|
||||
alias Pleroma.Object
|
||||
|
|
@ -29,8 +29,8 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do
|
|||
setup do: oauth_access(["write:statuses"])
|
||||
|
||||
test "posting a status does not increment reblog_count when relaying", %{conn: conn} do
|
||||
Pleroma.Config.put([:instance, :federating], true)
|
||||
Pleroma.Config.get([:instance, :allow_relay], true)
|
||||
Config.put([:instance, :federating], true)
|
||||
Config.get([:instance, :allow_relay], true)
|
||||
|
||||
response =
|
||||
conn
|
||||
|
|
@ -103,7 +103,9 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do
|
|||
|
||||
# An activity that will expire:
|
||||
# 2 hours
|
||||
expires_in = 120 * 60
|
||||
expires_in = 2 * 60 * 60
|
||||
|
||||
expires_at = DateTime.add(DateTime.utc_now(), expires_in)
|
||||
|
||||
conn_four =
|
||||
conn
|
||||
|
|
@ -113,29 +115,22 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do
|
|||
"expires_in" => expires_in
|
||||
})
|
||||
|
||||
assert fourth_response =
|
||||
%{"id" => fourth_id} = json_response_and_validate_schema(conn_four, 200)
|
||||
assert %{"id" => fourth_id} = json_response_and_validate_schema(conn_four, 200)
|
||||
|
||||
assert activity = Activity.get_by_id(fourth_id)
|
||||
assert expiration = ActivityExpiration.get_by_activity_id(fourth_id)
|
||||
assert Activity.get_by_id(fourth_id)
|
||||
|
||||
estimated_expires_at =
|
||||
NaiveDateTime.utc_now()
|
||||
|> NaiveDateTime.add(expires_in)
|
||||
|> NaiveDateTime.truncate(:second)
|
||||
|
||||
# This assert will fail if the test takes longer than a minute. I sure hope it never does:
|
||||
assert abs(NaiveDateTime.diff(expiration.scheduled_at, estimated_expires_at, :second)) < 60
|
||||
|
||||
assert fourth_response["pleroma"]["expires_at"] ==
|
||||
NaiveDateTime.to_iso8601(expiration.scheduled_at)
|
||||
assert_enqueued(
|
||||
worker: Pleroma.Workers.PurgeExpiredActivity,
|
||||
args: %{activity_id: fourth_id},
|
||||
scheduled_at: expires_at
|
||||
)
|
||||
end
|
||||
|
||||
test "it fails to create a status if `expires_in` is less or equal than an hour", %{
|
||||
conn: conn
|
||||
} do
|
||||
# 1 hour
|
||||
expires_in = 60 * 60
|
||||
# 1 minute
|
||||
expires_in = 1 * 60
|
||||
|
||||
assert %{"error" => "Expiry date is too soon"} =
|
||||
conn
|
||||
|
|
@ -146,8 +141,8 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do
|
|||
})
|
||||
|> json_response_and_validate_schema(422)
|
||||
|
||||
# 30 minutes
|
||||
expires_in = 30 * 60
|
||||
# 5 minutes
|
||||
expires_in = 5 * 60
|
||||
|
||||
assert %{"error" => "Expiry date is too soon"} =
|
||||
conn
|
||||
|
|
@ -160,8 +155,8 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do
|
|||
end
|
||||
|
||||
test "Get MRF reason when posting a status is rejected by one", %{conn: conn} do
|
||||
Pleroma.Config.put([:mrf_keyword, :reject], ["GNO"])
|
||||
Pleroma.Config.put([:mrf, :policies], [Pleroma.Web.ActivityPub.MRF.KeywordPolicy])
|
||||
Config.put([:mrf_keyword, :reject], ["GNO"])
|
||||
Config.put([:mrf, :policies], [Pleroma.Web.ActivityPub.MRF.KeywordPolicy])
|
||||
|
||||
assert %{"error" => "[KeywordPolicy] Matches with rejected keyword"} =
|
||||
conn
|
||||
|
|
@ -296,9 +291,45 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do
|
|||
assert real_status == fake_status
|
||||
end
|
||||
|
||||
test "fake statuses' preview card is not cached", %{conn: conn} do
|
||||
clear_config([:rich_media, :enabled], true)
|
||||
|
||||
Tesla.Mock.mock(fn
|
||||
%{
|
||||
method: :get,
|
||||
url: "https://example.com/twitter-card"
|
||||
} ->
|
||||
%Tesla.Env{status: 200, body: File.read!("test/fixtures/rich_media/twitter_card.html")}
|
||||
|
||||
env ->
|
||||
apply(HttpRequestMock, :request, [env])
|
||||
end)
|
||||
|
||||
conn1 =
|
||||
conn
|
||||
|> put_req_header("content-type", "application/json")
|
||||
|> post("/api/v1/statuses", %{
|
||||
"status" => "https://example.com/ogp",
|
||||
"preview" => true
|
||||
})
|
||||
|
||||
conn2 =
|
||||
conn
|
||||
|> put_req_header("content-type", "application/json")
|
||||
|> post("/api/v1/statuses", %{
|
||||
"status" => "https://example.com/twitter-card",
|
||||
"preview" => true
|
||||
})
|
||||
|
||||
assert %{"card" => %{"title" => "The Rock"}} = json_response_and_validate_schema(conn1, 200)
|
||||
|
||||
assert %{"card" => %{"title" => "Small Island Developing States Photo Submission"}} =
|
||||
json_response_and_validate_schema(conn2, 200)
|
||||
end
|
||||
|
||||
test "posting a status with OGP link preview", %{conn: conn} do
|
||||
Tesla.Mock.mock(fn env -> apply(HttpRequestMock, :request, [env]) end)
|
||||
Config.put([:rich_media, :enabled], true)
|
||||
clear_config([:rich_media, :enabled], true)
|
||||
|
||||
conn =
|
||||
conn
|
||||
|
|
@ -1110,6 +1141,52 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do
|
|||
|> post("/api/v1/statuses/#{activity_two.id}/pin")
|
||||
|> json_response_and_validate_schema(400)
|
||||
end
|
||||
|
||||
test "on pin removes deletion job, on unpin reschedule deletion" do
|
||||
%{conn: conn} = oauth_access(["write:accounts", "write:statuses"])
|
||||
expires_in = 2 * 60 * 60
|
||||
|
||||
expires_at = DateTime.add(DateTime.utc_now(), expires_in)
|
||||
|
||||
assert %{"id" => id} =
|
||||
conn
|
||||
|> put_req_header("content-type", "application/json")
|
||||
|> post("api/v1/statuses", %{
|
||||
"status" => "oolong",
|
||||
"expires_in" => expires_in
|
||||
})
|
||||
|> json_response_and_validate_schema(200)
|
||||
|
||||
assert_enqueued(
|
||||
worker: Pleroma.Workers.PurgeExpiredActivity,
|
||||
args: %{activity_id: id},
|
||||
scheduled_at: expires_at
|
||||
)
|
||||
|
||||
assert %{"id" => ^id, "pinned" => true} =
|
||||
conn
|
||||
|> put_req_header("content-type", "application/json")
|
||||
|> post("/api/v1/statuses/#{id}/pin")
|
||||
|> json_response_and_validate_schema(200)
|
||||
|
||||
refute_enqueued(
|
||||
worker: Pleroma.Workers.PurgeExpiredActivity,
|
||||
args: %{activity_id: id},
|
||||
scheduled_at: expires_at
|
||||
)
|
||||
|
||||
assert %{"id" => ^id, "pinned" => false} =
|
||||
conn
|
||||
|> put_req_header("content-type", "application/json")
|
||||
|> post("/api/v1/statuses/#{id}/unpin")
|
||||
|> json_response_and_validate_schema(200)
|
||||
|
||||
assert_enqueued(
|
||||
worker: Pleroma.Workers.PurgeExpiredActivity,
|
||||
args: %{activity_id: id},
|
||||
scheduled_at: expires_at
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
describe "cards" do
|
||||
|
|
@ -1645,19 +1722,17 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do
|
|||
|
||||
test "expires_at is nil for another user" do
|
||||
%{conn: conn, user: user} = oauth_access(["read:statuses"])
|
||||
expires_at = DateTime.add(DateTime.utc_now(), 1_000_000)
|
||||
{:ok, activity} = CommonAPI.post(user, %{status: "foobar", expires_in: 1_000_000})
|
||||
|
||||
expires_at =
|
||||
activity.id
|
||||
|> ActivityExpiration.get_by_activity_id()
|
||||
|> Map.get(:scheduled_at)
|
||||
|> NaiveDateTime.to_iso8601()
|
||||
|
||||
assert %{"pleroma" => %{"expires_at" => ^expires_at}} =
|
||||
assert %{"pleroma" => %{"expires_at" => a_expires_at}} =
|
||||
conn
|
||||
|> get("/api/v1/statuses/#{activity.id}")
|
||||
|> json_response_and_validate_schema(:ok)
|
||||
|
||||
{:ok, a_expires_at, 0} = DateTime.from_iso8601(a_expires_at)
|
||||
assert DateTime.diff(expires_at, a_expires_at) == 0
|
||||
|
||||
%{conn: conn} = oauth_access(["read:statuses"])
|
||||
|
||||
assert %{"pleroma" => %{"expires_at" => nil}} =
|
||||
|
|
|
|||
|
|
@ -114,8 +114,16 @@ defmodule Pleroma.Web.MastodonAPI.TimelineControllerTest do
|
|||
{:ok, _reply_from_friend} =
|
||||
CommonAPI.post(friend, %{status: "status", in_reply_to_status_id: reply_from_blockee})
|
||||
|
||||
res_conn = get(conn, "/api/v1/timelines/public")
|
||||
[%{"id" => ^activity_id}] = json_response_and_validate_schema(res_conn, 200)
|
||||
# Still shows replies from yourself
|
||||
{:ok, %{id: reply_from_me}} =
|
||||
CommonAPI.post(blocker, %{status: "status", in_reply_to_status_id: reply_from_blockee})
|
||||
|
||||
response =
|
||||
get(conn, "/api/v1/timelines/public")
|
||||
|> json_response_and_validate_schema(200)
|
||||
|
||||
assert length(response) == 2
|
||||
[%{"id" => ^reply_from_me}, %{"id" => ^activity_id}] = response
|
||||
end
|
||||
|
||||
test "doesn't return replies if follow is posting with users from blocked domain" do
|
||||
|
|
@ -345,6 +353,46 @@ defmodule Pleroma.Web.MastodonAPI.TimelineControllerTest do
|
|||
describe "list" do
|
||||
setup do: oauth_access(["read:lists"])
|
||||
|
||||
test "does not contain retoots", %{user: user, conn: conn} do
|
||||
other_user = insert(:user)
|
||||
{:ok, activity_one} = CommonAPI.post(user, %{status: "Marisa is cute."})
|
||||
{:ok, activity_two} = CommonAPI.post(other_user, %{status: "Marisa is stupid."})
|
||||
{:ok, _} = CommonAPI.repeat(activity_one.id, other_user)
|
||||
|
||||
{:ok, list} = Pleroma.List.create("name", user)
|
||||
{:ok, list} = Pleroma.List.follow(list, other_user)
|
||||
|
||||
conn = get(conn, "/api/v1/timelines/list/#{list.id}")
|
||||
|
||||
assert [%{"id" => id}] = json_response_and_validate_schema(conn, :ok)
|
||||
|
||||
assert id == to_string(activity_two.id)
|
||||
end
|
||||
|
||||
test "works with pagination", %{user: user, conn: conn} do
|
||||
other_user = insert(:user)
|
||||
{:ok, list} = Pleroma.List.create("name", user)
|
||||
{:ok, list} = Pleroma.List.follow(list, other_user)
|
||||
|
||||
Enum.each(1..30, fn i ->
|
||||
CommonAPI.post(other_user, %{status: "post number #{i}"})
|
||||
end)
|
||||
|
||||
res =
|
||||
get(conn, "/api/v1/timelines/list/#{list.id}?limit=1")
|
||||
|> json_response_and_validate_schema(:ok)
|
||||
|
||||
assert length(res) == 1
|
||||
|
||||
[first] = res
|
||||
|
||||
res =
|
||||
get(conn, "/api/v1/timelines/list/#{list.id}?max_id=#{first["id"]}&limit=30")
|
||||
|> json_response_and_validate_schema(:ok)
|
||||
|
||||
assert length(res) == 29
|
||||
end
|
||||
|
||||
test "list timeline", %{user: user, conn: conn} do
|
||||
other_user = insert(:user)
|
||||
{:ok, _activity_one} = CommonAPI.post(user, %{status: "Marisa is cute."})
|
||||
|
|
@ -457,6 +505,23 @@ defmodule Pleroma.Web.MastodonAPI.TimelineControllerTest do
|
|||
assert length(json_response(res_conn, 200)) == 2
|
||||
end
|
||||
|
||||
test "with default settings on private instances, returns 403 for unauthenticated users", %{
|
||||
conn: conn,
|
||||
base_uri: base_uri,
|
||||
error_response: error_response
|
||||
} do
|
||||
clear_config([:instance, :public], false)
|
||||
clear_config([:restrict_unauthenticated, :timelines])
|
||||
|
||||
for local <- [true, false] do
|
||||
res_conn = get(conn, "#{base_uri}?local=#{local}")
|
||||
|
||||
assert json_response(res_conn, :unauthorized) == error_response
|
||||
end
|
||||
|
||||
ensure_authenticated_access(base_uri)
|
||||
end
|
||||
|
||||
test "with `%{local: true, federated: true}`, returns 403 for unauthenticated users", %{
|
||||
conn: conn,
|
||||
base_uri: base_uri,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue