Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
Pleroma
pleroma
Commits
dc4a448f
Verified
Commit
dc4a448f
authored
May 07, 2020
by
minibikini
Browse files
Add OpenAPI spec for SearchController
parent
cdca62e8
Pipeline
#25411
passed with stages
in 14 minutes and 9 seconds
Changes
4
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
lib/pleroma/web/api_spec/operations/account_operation.ex
View file @
dc4a448f
...
...
@@ -556,11 +556,12 @@ defp update_creadentials_request do
}
end
def
p
array_of_accounts
do
def
array_of_accounts
do
%
Schema
{
title:
"ArrayOfAccounts"
,
type:
:array
,
items:
Account
items:
Account
,
example:
[
Account
.
schema
()
.
example
]
}
end
...
...
lib/pleroma/web/api_spec/operations/search_operation.ex
0 → 100644
View file @
dc4a448f
# Pleroma: A lightweight social networking server
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule
Pleroma
.
Web
.
ApiSpec
.
SearchOperation
do
alias
OpenApiSpex
.
Operation
alias
OpenApiSpex
.
Schema
alias
Pleroma
.
Web
.
ApiSpec
.
AccountOperation
alias
Pleroma
.
Web
.
ApiSpec
.
Schemas
.
Account
alias
Pleroma
.
Web
.
ApiSpec
.
Schemas
.
BooleanLike
alias
Pleroma
.
Web
.
ApiSpec
.
Schemas
.
FlakeID
alias
Pleroma
.
Web
.
ApiSpec
.
Schemas
.
Status
alias
Pleroma
.
Web
.
ApiSpec
.
Schemas
.
Tag
import
Pleroma
.
Web
.
ApiSpec
.
Helpers
def
open_api_operation
(
action
)
do
operation
=
String
.
to_existing_atom
(
"
#{
action
}
_operation"
)
apply
(
__MODULE__
,
operation
,
[])
end
def
account_search_operation
do
%
Operation
{
tags:
[
"Search"
],
summary:
"Search for matching accounts by username or display name"
,
operationId:
"SearchController.account_search"
,
parameters:
[
Operation
.
parameter
(
:q
,
:query
,
%
Schema
{
type:
:string
},
"What to search for"
,
required:
true
),
Operation
.
parameter
(
:limit
,
:query
,
%
Schema
{
type:
:integer
,
default:
40
},
"Maximum number of results"
),
Operation
.
parameter
(
:resolve
,
:query
,
%
Schema
{
allOf:
[
BooleanLike
],
default:
false
},
"Attempt WebFinger lookup. Use this when `q` is an exact address."
),
Operation
.
parameter
(
:following
,
:query
,
%
Schema
{
allOf:
[
BooleanLike
],
default:
false
},
"Only who the user is following."
)
],
responses:
%{
200
=>
Operation
.
response
(
"Array of Account"
,
"application/json"
,
AccountOperation
.
array_of_accounts
()
)
}
}
end
def
search_operation
do
%
Operation
{
tags:
[
"Search"
],
summary:
"Search results"
,
security:
[%{
"oAuth"
=>
[
"read:search"
]}],
operationId:
"SearchController.search"
,
deprecated:
true
,
parameters:
[
Operation
.
parameter
(
:account_id
,
:query
,
FlakeID
,
"If provided, statuses returned will be authored only by this account"
),
Operation
.
parameter
(
:type
,
:query
,
%
Schema
{
type:
:string
,
enum:
[
"accounts"
,
"hashtags"
,
"statuses"
]},
"Search type"
),
Operation
.
parameter
(
:q
,
:query
,
%
Schema
{
type:
:string
},
"The search query"
,
required:
true
),
Operation
.
parameter
(
:resolve
,
:query
,
%
Schema
{
allOf:
[
BooleanLike
],
default:
false
},
"Attempt WebFinger lookup"
),
Operation
.
parameter
(
:following
,
:query
,
%
Schema
{
allOf:
[
BooleanLike
],
default:
false
},
"Only include accounts that the user is following"
),
Operation
.
parameter
(
:offset
,
:query
,
%
Schema
{
type:
:integer
},
"Offset"
)
|
pagination_params
()
],
responses:
%{
200
=>
Operation
.
response
(
"Results"
,
"application/json"
,
results
())
}
}
end
def
search2_operation
do
%
Operation
{
tags:
[
"Search"
],
summary:
"Search results"
,
security:
[%{
"oAuth"
=>
[
"read:search"
]}],
operationId:
"SearchController.search2"
,
parameters:
[
Operation
.
parameter
(
:account_id
,
:query
,
FlakeID
,
"If provided, statuses returned will be authored only by this account"
),
Operation
.
parameter
(
:type
,
:query
,
%
Schema
{
type:
:string
,
enum:
[
"accounts"
,
"hashtags"
,
"statuses"
]},
"Search type"
),
Operation
.
parameter
(
:q
,
:query
,
%
Schema
{
type:
:string
},
"What to search for"
,
required:
true
),
Operation
.
parameter
(
:resolve
,
:query
,
%
Schema
{
allOf:
[
BooleanLike
],
default:
false
},
"Attempt WebFinger lookup"
),
Operation
.
parameter
(
:following
,
:query
,
%
Schema
{
allOf:
[
BooleanLike
],
default:
false
},
"Only include accounts that the user is following"
)
|
pagination_params
()
],
responses:
%{
200
=>
Operation
.
response
(
"Results"
,
"application/json"
,
results2
())
}
}
end
defp
results2
do
%
Schema
{
title:
"SearchResults"
,
type:
:object
,
properties:
%{
accounts:
%
Schema
{
type:
:array
,
items:
Account
,
description:
"Accounts which match the given query"
},
statuses:
%
Schema
{
type:
:array
,
items:
Status
,
description:
"Statuses which match the given query"
},
hashtags:
%
Schema
{
type:
:array
,
items:
Tag
,
description:
"Hashtags which match the given query"
}
},
example:
%{
"accounts"
=>
[
Account
.
schema
()
.
example
],
"statuses"
=>
[
Status
.
schema
()
.
example
],
"hashtags"
=>
[
Tag
.
schema
()
.
example
]
}
}
end
defp
results
do
%
Schema
{
title:
"SearchResults"
,
type:
:object
,
properties:
%{
accounts:
%
Schema
{
type:
:array
,
items:
Account
,
description:
"Accounts which match the given query"
},
statuses:
%
Schema
{
type:
:array
,
items:
Status
,
description:
"Statuses which match the given query"
},
hashtags:
%
Schema
{
type:
:array
,
items:
%
Schema
{
type:
:string
},
description:
"Hashtags which match the given query"
}
},
example:
%{
"accounts"
=>
[
Account
.
schema
()
.
example
],
"statuses"
=>
[
Status
.
schema
()
.
example
],
"hashtags"
=>
[
"cofe"
]
}
}
end
end
lib/pleroma/web/mastodon_api/controllers/search_controller.ex
View file @
dc4a448f
...
...
@@ -5,7 +5,7 @@
defmodule
Pleroma
.
Web
.
MastodonAPI
.
SearchController
do
use
Pleroma
.
Web
,
:controller
import
Pleroma
.
Web
.
ControllerHelper
,
only:
[
fetch_integer_param:
2
,
skip_relationships?:
1
]
import
Pleroma
.
Web
.
ControllerHelper
,
only:
[
skip_relationships?:
1
]
alias
Pleroma
.
Activity
alias
Pleroma
.
Plugs
.
OAuthScopesPlug
...
...
@@ -18,6 +18,8 @@ defmodule Pleroma.Web.MastodonAPI.SearchController do
require
Logger
plug
(
Pleroma
.
Web
.
ApiSpec
.
CastAndValidate
)
# Note: Mastodon doesn't allow unauthenticated access (requires read:accounts / read:search)
plug
(
OAuthScopesPlug
,
%{
scopes:
[
"read:search"
],
fallback:
:proceed_unauthenticated
})
...
...
@@ -25,7 +27,9 @@ defmodule Pleroma.Web.MastodonAPI.SearchController do
plug
(
RateLimiter
,
[
name:
:search
]
when
action
in
[
:search
,
:search2
,
:account_search
])
def
account_search
(%{
assigns:
%{
user:
user
}}
=
conn
,
%{
"q"
=>
query
}
=
params
)
do
defdelegate
open_api_operation
(
action
),
to:
Pleroma
.
Web
.
ApiSpec
.
SearchOperation
def
account_search
(%{
assigns:
%{
user:
user
}}
=
conn
,
%{
q:
query
}
=
params
)
do
accounts
=
User
.
search
(
query
,
search_options
(
params
,
user
))
conn
...
...
@@ -36,7 +40,7 @@ def account_search(%{assigns: %{user: user}} = conn, %{"q" => query} = params) d
def
search2
(
conn
,
params
),
do
:
do_search
(
:v2
,
conn
,
params
)
def
search
(
conn
,
params
),
do
:
do_search
(
:v1
,
conn
,
params
)
defp
do_search
(
version
,
%{
assigns:
%{
user:
user
}}
=
conn
,
%{
"q"
=>
query
}
=
params
)
do
defp
do_search
(
version
,
%{
assigns:
%{
user:
user
}}
=
conn
,
%{
q:
query
}
=
params
)
do
options
=
search_options
(
params
,
user
)
timeout
=
Keyword
.
get
(
Repo
.
config
(),
:timeout
,
15_000
)
default_values
=
%{
"statuses"
=>
[],
"accounts"
=>
[],
"hashtags"
=>
[]}
...
...
@@ -44,7 +48,7 @@ defp do_search(version, %{assigns: %{user: user}} = conn, %{"q" => query} = para
result
=
default_values
|>
Enum
.
map
(
fn
{
resource
,
default_value
}
->
if
params
[
"
type
"
]
in
[
nil
,
resource
]
do
if
params
[
:
type
]
in
[
nil
,
resource
]
do
{
resource
,
fn
->
resource_search
(
version
,
resource
,
query
,
options
)
end
}
else
{
resource
,
fn
->
default_value
end
}
...
...
@@ -68,11 +72,11 @@ defp do_search(version, %{assigns: %{user: user}} = conn, %{"q" => query} = para
defp
search_options
(
params
,
user
)
do
[
skip_relationships:
skip_relationships?
(
params
),
resolve:
params
[
"
resolve
"
]
==
"true"
,
following:
params
[
"
following
"
]
==
"true"
,
limit:
fetch_integer_param
(
params
,
"
limit
"
)
,
offset:
fetch_integer_param
(
params
,
"
offset
"
)
,
type:
params
[
"
type
"
],
resolve:
params
[
:
resolve
]
,
following:
params
[
:
following
]
,
limit:
params
[
:
limit
]
,
offset:
params
[
:
offset
]
,
type:
params
[
:
type
],
author:
get_author
(
params
),
for_user:
user
]
...
...
@@ -135,7 +139,7 @@ defp with_fallback(f, fallback \\ []) do
end
end
defp
get_author
(%{
"
account_id
"
=>
account_id
})
when
is_binary
(
account_id
),
defp
get_author
(%{
account_id
:
account_id
})
when
is_binary
(
account_id
),
do
:
User
.
get_cached_by_id
(
account_id
)
defp
get_author
(
_params
),
do
:
nil
...
...
test/web/mastodon_api/controllers/search_controller_test.exs
View file @
dc4a448f
...
...
@@ -27,8 +27,8 @@ test "it returns empty result if user or status search return undefined error",
capture_log
(
fn
->
results
=
conn
|>
get
(
"/api/v2/search
"
,
%{
"q"
=>
"
2hu"
}
)
|>
json_response
(
200
)
|>
get
(
"/api/v2/search
?q=
2hu"
)
|>
json_response
_and_validate_schema
(
200
)
assert
results
[
"accounts"
]
==
[]
assert
results
[
"statuses"
]
==
[]
...
...
@@ -54,8 +54,8 @@ test "search", %{conn: conn} do
results
=
conn
|>
get
(
"/api/v2/search
"
,
%{
"q"
=>
"2hu #private"
})
|>
json_response
(
200
)
|>
get
(
"/api/v2/search
?
#{
URI
.
encode_query
(%{
q:
"2hu #private"
}
)
}"
)
|>
json_response
_and_validate_schema
(
200
)
[
account
|
_
]
=
results
[
"accounts"
]
assert
account
[
"id"
]
==
to_string
(
user_three
.
id
)
...
...
@@ -68,8 +68,8 @@ test "search", %{conn: conn} do
assert
status
[
"id"
]
==
to_string
(
activity
.
id
)
results
=
get
(
conn
,
"/api/v2/search
"
,
%{
"q"
=>
"
天子"
}
)
|>
json_response
(
200
)
get
(
conn
,
"/api/v2/search
?q=
天子"
)
|>
json_response
_and_validate_schema
(
200
)
[
status
]
=
results
[
"statuses"
]
assert
status
[
"id"
]
==
to_string
(
activity
.
id
)
...
...
@@ -89,8 +89,8 @@ test "excludes a blocked users from search results", %{conn: conn} do
conn
|>
assign
(
:user
,
user
)
|>
assign
(
:token
,
insert
(
:oauth_token
,
user:
user
,
scopes:
[
"read"
]))
|>
get
(
"/api/v2/search
"
,
%{
"q"
=>
"
Agent"
}
)
|>
json_response
(
200
)
|>
get
(
"/api/v2/search
?q=
Agent"
)
|>
json_response
_and_validate_schema
(
200
)
status_ids
=
Enum
.
map
(
results
[
"statuses"
],
fn
g
->
g
[
"id"
]
end
)
...
...
@@ -107,8 +107,8 @@ test "account search", %{conn: conn} do
results
=
conn
|>
get
(
"/api/v1/accounts/search
"
,
%{
"q"
=>
"
shp"
}
)
|>
json_response
(
200
)
|>
get
(
"/api/v1/accounts/search
?q=
shp"
)
|>
json_response
_and_validate_schema
(
200
)
result_ids
=
for
result
<-
results
,
do
:
result
[
"acct"
]
...
...
@@ -117,8 +117,8 @@ test "account search", %{conn: conn} do
results
=
conn
|>
get
(
"/api/v1/accounts/search
"
,
%{
"q"
=>
"
2hu"
}
)
|>
json_response
(
200
)
|>
get
(
"/api/v1/accounts/search
?q=
2hu"
)
|>
json_response
_and_validate_schema
(
200
)
result_ids
=
for
result
<-
results
,
do
:
result
[
"acct"
]
...
...
@@ -130,8 +130,8 @@ test "returns account if query contains a space", %{conn: conn} do
results
=
conn
|>
get
(
"/api/v1/accounts/search
"
,
%{
"q"
=>
"
shp@shitposter.club xxx
"
}
)
|>
json_response
(
200
)
|>
get
(
"/api/v1/accounts/search
?q=
shp@shitposter.club xxx
"
)
|>
json_response
_and_validate_schema
(
200
)
assert
length
(
results
)
==
1
end
...
...
@@ -146,8 +146,8 @@ test "it returns empty result if user or status search return undefined error",
capture_log
(
fn
->
results
=
conn
|>
get
(
"/api/v1/search
"
,
%{
"q"
=>
"
2hu"
}
)
|>
json_response
(
200
)
|>
get
(
"/api/v1/search
?q=
2hu"
)
|>
json_response
_and_validate_schema
(
200
)
assert
results
[
"accounts"
]
==
[]
assert
results
[
"statuses"
]
==
[]
...
...
@@ -173,8 +173,8 @@ test "search", %{conn: conn} do
results
=
conn
|>
get
(
"/api/v1/search
"
,
%{
"q"
=>
"
2hu"
}
)
|>
json_response
(
200
)
|>
get
(
"/api/v1/search
?q=
2hu"
)
|>
json_response
_and_validate_schema
(
200
)
[
account
|
_
]
=
results
[
"accounts"
]
assert
account
[
"id"
]
==
to_string
(
user_three
.
id
)
...
...
@@ -194,8 +194,8 @@ test "search fetches remote statuses and prefers them over other results", %{con
results
=
conn
|>
get
(
"/api/v1/search
"
,
%{
"q"
=>
"
https://shitposter.club/notice/2827873"
}
)
|>
json_response
(
200
)
|>
get
(
"/api/v1/search
?q=
https://shitposter.club/notice/2827873"
)
|>
json_response
_and_validate_schema
(
200
)
[
status
,
%{
"id"
=>
^
activity_id
}]
=
results
[
"statuses"
]
...
...
@@ -212,10 +212,12 @@ test "search doesn't show statuses that it shouldn't", %{conn: conn} do
})
capture_log
(
fn
->
q
=
Object
.
normalize
(
activity
)
.
data
[
"id"
]
results
=
conn
|>
get
(
"/api/v1/search
"
,
%{
"q"
=>
Object
.
normalize
(
activity
)
.
data
[
"id"
]}
)
|>
json_response
(
200
)
|>
get
(
"/api/v1/search
?q=
#{
q
}
"
)
|>
json_response
_and_validate_schema
(
200
)
[]
=
results
[
"statuses"
]
end
)
...
...
@@ -228,8 +230,8 @@ test "search fetches remote accounts", %{conn: conn} do
conn
|>
assign
(
:user
,
user
)
|>
assign
(
:token
,
insert
(
:oauth_token
,
user:
user
,
scopes:
[
"read"
]))
|>
get
(
"/api/v1/search
"
,
%{
"q"
=>
"
mike@osada.macgirvin.com
"
,
"
resolve
"
=>
"
true"
}
)
|>
json_response
(
200
)
|>
get
(
"/api/v1/search
?q=
mike@osada.macgirvin.com
&
resolve
=
true"
)
|>
json_response
_and_validate_schema
(
200
)
[
account
]
=
results
[
"accounts"
]
assert
account
[
"acct"
]
==
"mike@osada.macgirvin.com"
...
...
@@ -238,8 +240,8 @@ test "search fetches remote accounts", %{conn: conn} do
test
"search doesn't fetch remote accounts if resolve is false"
,
%{
conn:
conn
}
do
results
=
conn
|>
get
(
"/api/v1/search
"
,
%{
"q"
=>
"
mike@osada.macgirvin.com
"
,
"
resolve
"
=>
"
false"
}
)
|>
json_response
(
200
)
|>
get
(
"/api/v1/search
?q=
mike@osada.macgirvin.com
&
resolve
=
false"
)
|>
json_response
_and_validate_schema
(
200
)
assert
[]
==
results
[
"accounts"
]
end
...
...
@@ -254,16 +256,16 @@ test "search with limit and offset", %{conn: conn} do
result
=
conn
|>
get
(
"/api/v1/search
"
,
%{
"q"
=>
"2hu"
,
"limit"
=>
1
}
)
|>
get
(
"/api/v1/search
?q=2hu&limit=1"
)
assert
results
=
json_response
(
result
,
200
)
assert
results
=
json_response
_and_validate_schema
(
result
,
200
)
assert
[%{
"id"
=>
activity_id1
}]
=
results
[
"statuses"
]
assert
[
_
]
=
results
[
"accounts"
]
results
=
conn
|>
get
(
"/api/v1/search
"
,
%{
"q"
=>
"2hu"
,
"limit"
=>
1
,
"offset"
=>
1
}
)
|>
json_response
(
200
)
|>
get
(
"/api/v1/search
?q=2hu&limit=1&offset=1"
)
|>
json_response
_and_validate_schema
(
200
)
assert
[%{
"id"
=>
activity_id2
}]
=
results
[
"statuses"
]
assert
[]
=
results
[
"accounts"
]
...
...
@@ -279,13 +281,13 @@ test "search returns results only for the given type", %{conn: conn} do
assert
%{
"statuses"
=>
[
_activity
],
"accounts"
=>
[],
"hashtags"
=>
[]}
=
conn
|>
get
(
"/api/v1/search
"
,
%{
"q"
=>
"2hu"
,
"type"
=>
"
statuses"
}
)
|>
json_response
(
200
)
|>
get
(
"/api/v1/search
?q=2hu&type=
statuses"
)
|>
json_response
_and_validate_schema
(
200
)
assert
%{
"statuses"
=>
[],
"accounts"
=>
[
_user_two
],
"hashtags"
=>
[]}
=
conn
|>
get
(
"/api/v1/search
"
,
%{
"q"
=>
"2hu"
,
"type"
=>
"
accounts"
}
)
|>
json_response
(
200
)
|>
get
(
"/api/v1/search
?q=2hu&type=
accounts"
)
|>
json_response
_and_validate_schema
(
200
)
end
test
"search uses account_id to filter statuses by the author"
,
%{
conn:
conn
}
do
...
...
@@ -297,8 +299,8 @@ test "search uses account_id to filter statuses by the author", %{conn: conn} do
results
=
conn
|>
get
(
"/api/v1/search
"
,
%{
"q"
=>
"2hu"
,
"
account_id
"
=>
user
.
id
})
|>
json_response
(
200
)
|>
get
(
"/api/v1/search
?q=2hu&
account_id
=
#{
user
.
id
}
"
)
|>
json_response
_and_validate_schema
(
200
)
assert
[%{
"id"
=>
activity_id1
}]
=
results
[
"statuses"
]
assert
activity_id1
==
activity1
.
id
...
...
@@ -306,8 +308,8 @@ test "search uses account_id to filter statuses by the author", %{conn: conn} do
results
=
conn
|>
get
(
"/api/v1/search
"
,
%{
"q"
=>
"2hu"
,
"
account_id
"
=>
user_two
.
id
})
|>
json_response
(
200
)
|>
get
(
"/api/v1/search
?q=2hu&
account_id
=
#{
user_two
.
id
}
"
)
|>
json_response
_and_validate_schema
(
200
)
assert
[%{
"id"
=>
activity_id2
}]
=
results
[
"statuses"
]
assert
activity_id2
==
activity2
.
id
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment