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
3aae5231
Verified
Commit
3aae5231
authored
Mar 02, 2021
by
minibikini
Browse files
Add OpenAPI spec for AdminAPI.UserController
parent
4cb166e9
Pipeline
#35317
passed with stages
in 9 minutes and 24 seconds
Changes
7
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
CHANGELOG.md
View file @
3aae5231
...
...
@@ -64,6 +64,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
<details>
<summary>
API Changes
</summary>
-
Admin API: (
`GET /api/pleroma/admin/users`
) filter users by
`unconfirmed`
status and
`actor_type`
.
-
Admin API: OpenAPI spec for the user-related operations
-
Pleroma API:
`GET /api/v2/pleroma/chats`
added. It is exactly like
`GET /api/v1/pleroma/chats`
except supports pagination.
-
Pleroma API: Add
`idempotency_key`
to the chat message entity that can be used for optimistic message sending.
-
Pleroma API: (
`GET /api/v1/pleroma/federation_status`
) Add a way to get a list of unreachable instances.
...
...
lib/pleroma/user.ex
View file @
3aae5231
...
...
@@ -2255,13 +2255,6 @@ def update_background(user, background) do
|>
update_and_set_cache
()
end
def
roles
(%{
is_moderator:
is_moderator
,
is_admin:
is_admin
})
do
%{
admin:
is_admin
,
moderator:
is_moderator
}
end
def
validate_fields
(
changeset
,
remote?
\\
false
)
do
limit_name
=
if
remote?
,
do
:
:max_remote_account_fields
,
else
:
:max_account_fields
limit
=
Config
.
get
([
:instance
,
limit_name
],
0
)
...
...
lib/pleroma/web/admin_api/controllers/user_controller.ex
View file @
3aae5231
...
...
@@ -13,16 +13,17 @@ defmodule Pleroma.Web.AdminAPI.UserController do
alias
Pleroma
.
Web
.
ActivityPub
.
Builder
alias
Pleroma
.
Web
.
ActivityPub
.
Pipeline
alias
Pleroma
.
Web
.
AdminAPI
alias
Pleroma
.
Web
.
AdminAPI
.
AccountView
alias
Pleroma
.
Web
.
AdminAPI
.
Search
alias
Pleroma
.
Web
.
Plugs
.
OAuthScopesPlug
@users_page_size
50
plug
(
Pleroma
.
Web
.
ApiSpec
.
CastAndValidate
)
plug
(
OAuthScopesPlug
,
%{
scopes:
[
"admin:read:accounts"
]}
when
action
in
[
:
list
,
:show
]
when
action
in
[
:
index
,
:show
]
)
plug
(
...
...
@@ -44,13 +45,19 @@ defmodule Pleroma.Web.AdminAPI.UserController do
when
action
in
[
:follow
,
:unfollow
]
)
plug
(
:put_view
,
Pleroma
.
Web
.
AdminAPI
.
AccountView
)
action_fallback
(
AdminAPI
.
FallbackController
)
def
delete
(
conn
,
%{
"nickname"
=>
nickname
})
do
delete
(
conn
,
%{
"nicknames"
=>
[
nickname
]})
defdelegate
open_api_operation
(
action
),
to:
Pleroma
.
Web
.
ApiSpec
.
Admin
.
UserOperation
def
delete
(
conn
,
%{
nickname:
nickname
})
do
conn
|>
Map
.
put
(
:body_params
,
%{
nicknames:
[
nickname
]})
|>
delete
(%{})
end
def
delete
(%{
assigns:
%{
user:
admin
}
}
=
conn
,
%{
"
nicknames
"
=>
nicknames
})
do
def
delete
(%{
assigns:
%{
user:
admin
}
,
body_params:
%{
nicknames
:
nicknames
}
}
=
conn
,
_
)
do
users
=
Enum
.
map
(
nicknames
,
&
User
.
get_cached_by_nickname
/
1
)
Enum
.
each
(
users
,
fn
user
->
...
...
@@ -67,10 +74,16 @@ def delete(%{assigns: %{user: admin}} = conn, %{"nicknames" => nicknames}) do
json
(
conn
,
nicknames
)
end
def
follow
(%{
assigns:
%{
user:
admin
}}
=
conn
,
%{
"follower"
=>
follower_nick
,
"followed"
=>
followed_nick
})
do
def
follow
(
%{
assigns:
%{
user:
admin
},
body_params:
%{
follower:
follower_nick
,
followed:
followed_nick
}
}
=
conn
,
_
)
do
with
%
User
{}
=
follower
<-
User
.
get_cached_by_nickname
(
follower_nick
),
%
User
{}
=
followed
<-
User
.
get_cached_by_nickname
(
followed_nick
)
do
User
.
follow
(
follower
,
followed
)
...
...
@@ -86,10 +99,16 @@ def follow(%{assigns: %{user: admin}} = conn, %{
json
(
conn
,
"ok"
)
end
def
unfollow
(%{
assigns:
%{
user:
admin
}}
=
conn
,
%{
"follower"
=>
follower_nick
,
"followed"
=>
followed_nick
})
do
def
unfollow
(
%{
assigns:
%{
user:
admin
},
body_params:
%{
follower:
follower_nick
,
followed:
followed_nick
}
}
=
conn
,
_
)
do
with
%
User
{}
=
follower
<-
User
.
get_cached_by_nickname
(
follower_nick
),
%
User
{}
=
followed
<-
User
.
get_cached_by_nickname
(
followed_nick
)
do
User
.
unfollow
(
follower
,
followed
)
...
...
@@ -105,9 +124,10 @@ def unfollow(%{assigns: %{user: admin}} = conn, %{
json
(
conn
,
"ok"
)
end
def
create
(%{
assigns:
%{
user:
admin
}
}
=
conn
,
%{
"
users
"
=>
users
})
do
def
create
(%{
assigns:
%{
user:
admin
}
,
body_params:
%{
users
:
users
}
}
=
conn
,
_
)
do
changesets
=
Enum
.
map
(
users
,
fn
%{
"nickname"
=>
nickname
,
"email"
=>
email
,
"password"
=>
password
}
->
users
|>
Enum
.
map
(
fn
%{
nickname:
nickname
,
email:
email
,
password:
password
}
->
user_data
=
%{
nickname:
nickname
,
name:
nickname
,
...
...
@@ -124,52 +144,49 @@ def create(%{assigns: %{user: admin}} = conn, %{"users" => users}) do
end
)
case
Pleroma
.
Repo
.
transaction
(
changesets
)
do
{
:ok
,
users
}
->
r
e
s
=
users
{
:ok
,
users
_map
}
->
use
rs
=
users
_map
|>
Map
.
values
()
|>
Enum
.
map
(
fn
user
->
{
:ok
,
user
}
=
User
.
post_register_action
(
user
)
user
end
)
|>
Enum
.
map
(
&
AccountView
.
render
(
"created.json"
,
%{
user:
&1
}))
ModerationLog
.
insert_log
(%{
actor:
admin
,
subjects:
Map
.
values
(
users
)
,
subjects:
users
,
action:
"create"
})
json
(
conn
,
r
e
s
)
render
(
conn
,
"created_many.json"
,
users:
use
rs
)
{
:error
,
id
,
changeset
,
_
}
->
re
s
=
changeset
s
=
Enum
.
map
(
changesets
.
operations
,
fn
{
current_
id
,
{
:changeset
,
_current_changeset
,
_
}}
when
current_id
==
id
->
AccountView
.
render
(
"create-error.json"
,
%{
changeset:
changeset
})
{
^
id
,
{
:changeset
,
_current_changeset
,
_
}}
->
changeset
{
_
,
{
:changeset
,
current_changeset
,
_
}}
->
AccountView
.
render
(
"create-error.json"
,
%{
changeset:
current_changeset
})
current_changeset
end
)
conn
|>
put_status
(
:conflict
)
|>
json
(
re
s
)
|>
render
(
"create_errors.json"
,
changesets:
changeset
s
)
end
end
def
show
(%{
assigns:
%{
user:
admin
}}
=
conn
,
%{
"
nickname
"
=>
nickname
})
do
def
show
(%{
assigns:
%{
user:
admin
}}
=
conn
,
%{
nickname
:
nickname
})
do
with
%
User
{}
=
user
<-
User
.
get_cached_by_nickname_or_id
(
nickname
,
for:
admin
)
do
conn
|>
put_view
(
AccountView
)
|>
render
(
"show.json"
,
%{
user:
user
})
render
(
conn
,
"show.json"
,
%{
user:
user
})
else
_
->
{
:error
,
:not_found
}
end
end
def
toggle_activation
(%{
assigns:
%{
user:
admin
}}
=
conn
,
%{
"
nickname
"
=>
nickname
})
do
def
toggle_activation
(%{
assigns:
%{
user:
admin
}}
=
conn
,
%{
nickname
:
nickname
})
do
user
=
User
.
get_cached_by_nickname
(
nickname
)
{
:ok
,
updated_user
}
=
User
.
set_activation
(
user
,
!user
.
is_active
)
...
...
@@ -182,12 +199,10 @@ def toggle_activation(%{assigns: %{user: admin}} = conn, %{"nickname" => nicknam
action:
action
})
conn
|>
put_view
(
AccountView
)
|>
render
(
"show.json"
,
%{
user:
updated_user
})
render
(
conn
,
"show.json"
,
user:
updated_user
)
end
def
activate
(%{
assigns:
%{
user:
admin
}
}
=
conn
,
%{
"
nicknames
"
=>
nicknames
})
do
def
activate
(%{
assigns:
%{
user:
admin
}
,
body_params:
%{
nicknames
:
nicknames
}
}
=
conn
,
_
)
do
users
=
Enum
.
map
(
nicknames
,
&
User
.
get_cached_by_nickname
/
1
)
{
:ok
,
updated_users
}
=
User
.
set_activation
(
users
,
true
)
...
...
@@ -197,12 +212,10 @@ def activate(%{assigns: %{user: admin}} = conn, %{"nicknames" => nicknames}) do
action:
"activate"
})
conn
|>
put_view
(
AccountView
)
|>
render
(
"index.json"
,
%{
users:
Keyword
.
values
(
updated_users
)})
render
(
conn
,
"index.json"
,
users:
Keyword
.
values
(
updated_users
))
end
def
deactivate
(%{
assigns:
%{
user:
admin
}
}
=
conn
,
%{
"
nicknames
"
=>
nicknames
})
do
def
deactivate
(%{
assigns:
%{
user:
admin
}
,
body_params:
%{
nicknames
:
nicknames
}
}
=
conn
,
_
)
do
users
=
Enum
.
map
(
nicknames
,
&
User
.
get_cached_by_nickname
/
1
)
{
:ok
,
updated_users
}
=
User
.
set_activation
(
users
,
false
)
...
...
@@ -212,12 +225,10 @@ def deactivate(%{assigns: %{user: admin}} = conn, %{"nicknames" => nicknames}) d
action:
"deactivate"
})
conn
|>
put_view
(
AccountView
)
|>
render
(
"index.json"
,
%{
users:
Keyword
.
values
(
updated_users
)})
render
(
conn
,
"index.json"
,
users:
Keyword
.
values
(
updated_users
))
end
def
approve
(%{
assigns:
%{
user:
admin
}
}
=
conn
,
%{
"
nicknames
"
=>
nicknames
})
do
def
approve
(%{
assigns:
%{
user:
admin
}
,
body_params:
%{
nicknames
:
nicknames
}
}
=
conn
,
_
)
do
users
=
Enum
.
map
(
nicknames
,
&
User
.
get_cached_by_nickname
/
1
)
{
:ok
,
updated_users
}
=
User
.
approve
(
users
)
...
...
@@ -227,36 +238,27 @@ def approve(%{assigns: %{user: admin}} = conn, %{"nicknames" => nicknames}) do
action:
"approve"
})
conn
|>
put_view
(
AccountView
)
|>
render
(
"index.json"
,
%{
users:
updated_users
})
render
(
conn
,
"index.json"
,
users:
updated_users
)
end
def
list
(
conn
,
params
)
do
def
index
(
conn
,
params
)
do
{
page
,
page_size
}
=
page_params
(
params
)
filters
=
maybe_parse_filters
(
params
[
"
filters
"
])
filters
=
maybe_parse_filters
(
params
[
:
filters
])
search_params
=
%{
query:
params
[
"
query
"
],
query:
params
[
:
query
],
page:
page
,
page_size:
page_size
,
tags:
params
[
"
tags
"
],
name:
params
[
"
name
"
],
email:
params
[
"
email
"
],
actor_types:
params
[
"
actor_types
"
]
tags:
params
[
:
tags
],
name:
params
[
:
name
],
email:
params
[
:
email
],
actor_types:
params
[
:
actor_types
]
}
|>
Map
.
merge
(
filters
)
with
{
:ok
,
users
,
count
}
<-
Search
.
user
(
search_params
)
do
json
(
conn
,
AccountView
.
render
(
"index.json"
,
users:
users
,
count:
count
,
page_size:
page_size
)
)
render
(
conn
,
"index.json"
,
users:
users
,
count:
count
,
page_size:
page_size
)
end
end
...
...
@@ -274,8 +276,8 @@ defp maybe_parse_filters(filters) do
defp
page_params
(
params
)
do
{
fetch_integer_param
(
params
,
"
page
"
,
1
),
fetch_integer_param
(
params
,
"
page_size
"
,
@users_page_size
)
fetch_integer_param
(
params
,
:
page
,
1
),
fetch_integer_param
(
params
,
:
page_size
,
@users_page_size
)
}
end
end
lib/pleroma/web/admin_api/views/account_view.ex
View file @
3aae5231
...
...
@@ -75,7 +75,7 @@ def render("show.json", %{user: user}) do
"display_name"
=>
display_name
,
"is_active"
=>
user
.
is_active
,
"local"
=>
user
.
local
,
"roles"
=>
User
.
roles
(
user
),
"roles"
=>
roles
(
user
),
"tags"
=>
user
.
tags
||
[],
"is_confirmed"
=>
user
.
is_confirmed
,
"is_approved"
=>
user
.
is_approved
,
...
...
@@ -85,6 +85,10 @@ def render("show.json", %{user: user}) do
}
end
def
render
(
"created_many.json"
,
%{
users:
users
})
do
render_many
(
users
,
AccountView
,
"created.json"
,
as:
:user
)
end
def
render
(
"created.json"
,
%{
user:
user
})
do
%{
type:
"success"
,
...
...
@@ -96,7 +100,11 @@ def render("created.json", %{user: user}) do
}
end
def
render
(
"create-error.json"
,
%{
changeset:
%
Ecto
.
Changeset
{
changes:
changes
,
errors:
errors
}})
do
def
render
(
"create_errors.json"
,
%{
changesets:
changesets
})
do
render_many
(
changesets
,
AccountView
,
"create_error.json"
,
as:
:changeset
)
end
def
render
(
"create_error.json"
,
%{
changeset:
%
Ecto
.
Changeset
{
changes:
changes
,
errors:
errors
}})
do
%{
type:
"error"
,
code:
409
,
...
...
@@ -140,4 +148,11 @@ defp parse_error(errors) do
defp
image_url
(%{
"url"
=>
[%{
"href"
=>
href
}
|
_
]}),
do
:
href
defp
image_url
(
_
),
do
:
nil
defp
roles
(%{
is_moderator:
is_moderator
,
is_admin:
is_admin
})
do
%{
admin:
is_admin
,
moderator:
is_moderator
}
end
end
lib/pleroma/web/api_spec/operations/admin/user_operation.ex
0 → 100644
View file @
3aae5231
# Pleroma: A lightweight social networking server
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule
Pleroma
.
Web
.
ApiSpec
.
Admin
.
UserOperation
do
alias
OpenApiSpex
.
Operation
alias
OpenApiSpex
.
Schema
alias
Pleroma
.
Web
.
ApiSpec
.
Schemas
.
ActorType
alias
Pleroma
.
Web
.
ApiSpec
.
Schemas
.
ApiError
import
Pleroma
.
Web
.
ApiSpec
.
Helpers
def
open_api_operation
(
action
)
do
operation
=
String
.
to_existing_atom
(
"
#{
action
}
_operation"
)
apply
(
__MODULE__
,
operation
,
[])
end
def
index_operation
do
%
Operation
{
tags:
[
"Users"
],
summary:
"List users"
,
operationId:
"AdminAPI.UserController.index"
,
security:
[%{
"oAuth"
=>
[
"admin:read:accounts"
]}],
parameters:
[
Operation
.
parameter
(
:filters
,
:query
,
:string
,
"Comma separated list of filters"
),
Operation
.
parameter
(
:query
,
:query
,
:string
,
"Search users query"
),
Operation
.
parameter
(
:name
,
:query
,
:string
,
"Search by display name"
),
Operation
.
parameter
(
:email
,
:query
,
:string
,
"Search by email"
),
Operation
.
parameter
(
:page
,
:query
,
:integer
,
"Page Number"
),
Operation
.
parameter
(
:page_size
,
:query
,
:integer
,
"Number of users to return per page"
),
Operation
.
parameter
(
:actor_types
,
:query
,
%
Schema
{
type:
:array
,
items:
ActorType
},
"Filter by actor type"
),
Operation
.
parameter
(
:tags
,
:query
,
%
Schema
{
type:
:array
,
items:
%
Schema
{
type:
:string
}},
"Filter by tags"
)
|
admin_api_params
()
],
responses:
%{
200
=>
Operation
.
response
(
"Response"
,
"application/json"
,
%
Schema
{
type:
:object
,
properties:
%{
users:
%
Schema
{
type:
:array
,
items:
user
()},
count:
%
Schema
{
type:
:integer
},
page_size:
%
Schema
{
type:
:integer
}
}
}
),
403
=>
Operation
.
response
(
"Forbidden"
,
"application/json"
,
ApiError
)
}
}
end
def
create_operation
do
%
Operation
{
tags:
[
"Users"
],
summary:
"Create a single or multiple users"
,
operationId:
"AdminAPI.UserController.create"
,
security:
[%{
"oAuth"
=>
[
"admin:write:accounts"
]}],
parameters:
admin_api_params
(),
requestBody:
request_body
(
"Parameters"
,
%
Schema
{
description:
"POST body for creating users"
,
type:
:object
,
properties:
%{
users:
%
Schema
{
type:
:array
,
items:
%
Schema
{
type:
:object
,
properties:
%{
nickname:
%
Schema
{
type:
:string
},
email:
%
Schema
{
type:
:string
},
password:
%
Schema
{
type:
:string
}
}
}
}
}
}
),
responses:
%{
200
=>
Operation
.
response
(
"Response"
,
"application/json"
,
%
Schema
{
type:
:array
,
items:
%
Schema
{
type:
:object
,
properties:
%{
code:
%
Schema
{
type:
:integer
},
type:
%
Schema
{
type:
:string
},
data:
%
Schema
{
type:
:object
,
properties:
%{
email:
%
Schema
{
type:
:string
,
format:
:email
},
nickname:
%
Schema
{
type:
:string
}
}
}
}
}
}),
403
=>
Operation
.
response
(
"Forbidden"
,
"application/json"
,
ApiError
),
409
=>
Operation
.
response
(
"Conflict"
,
"application/json"
,
%
Schema
{
type:
:array
,
items:
%
Schema
{
type:
:object
,
properties:
%{
code:
%
Schema
{
type:
:integer
},
error:
%
Schema
{
type:
:string
},
type:
%
Schema
{
type:
:string
},
data:
%
Schema
{
type:
:object
,
properties:
%{
email:
%
Schema
{
type:
:string
,
format:
:email
},
nickname:
%
Schema
{
type:
:string
}
}
}
}
}
})
}
}
end
def
show_operation
do
%
Operation
{
tags:
[
"Users"
],
summary:
"Show user"
,
operationId:
"AdminAPI.UserController.show"
,
security:
[%{
"oAuth"
=>
[
"admin:read:accounts"
]}],
parameters:
[
Operation
.
parameter
(
:nickname
,
:path
,
:string
,
"User nickname or ID"
)
|
admin_api_params
()
],
responses:
%{
200
=>
Operation
.
response
(
"Response"
,
"application/json"
,
user
()),
403
=>
Operation
.
response
(
"Forbidden"
,
"application/json"
,
ApiError
),
404
=>
Operation
.
response
(
"Not Found"
,
"application/json"
,
ApiError
)
}
}
end
def
follow_operation
do
%
Operation
{
tags:
[
"Users"
],
summary:
"Follow"
,
operationId:
"AdminAPI.UserController.follow"
,
security:
[%{
"oAuth"
=>
[
"admin:write:follows"
]}],
parameters:
admin_api_params
(),
requestBody:
request_body
(
"Parameters"
,
%
Schema
{
type:
:object
,
properties:
%{
follower:
%
Schema
{
type:
:string
,
description:
"Follower nickname"
},
followed:
%
Schema
{
type:
:string
,
description:
"Followed nickname"
}
}
}
),
responses:
%{
200
=>
Operation
.
response
(
"Response"
,
"application/json"
,
%
Schema
{
type:
:string
}),
403
=>
Operation
.
response
(
"Forbidden"
,
"application/json"
,
ApiError
)
}
}
end
def
unfollow_operation
do
%
Operation
{
tags:
[
"Users"
],
summary:
"Unfollow"
,
operationId:
"AdminAPI.UserController.unfollow"
,
security:
[%{
"oAuth"
=>
[
"admin:write:follows"
]}],
parameters:
admin_api_params
(),
requestBody:
request_body
(
"Parameters"
,
%
Schema
{
type:
:object
,
properties:
%{
follower:
%
Schema
{
type:
:string
,
description:
"Follower nickname"
},
followed:
%
Schema
{
type:
:string
,
description:
"Followed nickname"
}
}
}
),
responses:
%{
200
=>
Operation
.
response
(
"Response"
,
"application/json"
,
%
Schema
{
type:
:string
}),
403
=>
Operation
.
response
(
"Forbidden"
,
"application/json"
,
ApiError
)
}
}
end
def
approve_operation
do
%
Operation
{
tags:
[
"Users"
],
summary:
"Approve multiple users"
,
operationId:
"AdminAPI.UserController.approve"
,
security:
[%{
"oAuth"
=>
[
"admin:write:accounts"
]}],
parameters:
admin_api_params
(),
requestBody:
request_body
(
"Parameters"
,
%
Schema
{
description:
"POST body for deleting multiple users"
,
type:
:object
,
properties:
%{
nicknames:
%
Schema
{
type:
:array
,
items:
%
Schema
{
type:
:string
}
}
}
}
),
responses:
%{
200
=>
Operation
.
response
(
"Response"
,
"application/json"
,
%
Schema
{
type:
:object
,
properties:
%{
user:
%
Schema
{
type:
:array
,
items:
user
()}}
}),
403
=>
Operation
.
response
(
"Forbidden"
,
"application/json"
,
ApiError
)
}
}
end
def
toggle_activation_operation
do
%
Operation
{
tags:
[
"Users"
],
summary:
"Toggle user activation"
,
operationId:
"AdminAPI.UserController.toggle_activation"
,
security:
[%{
"oAuth"
=>
[
"admin:write:accounts"
]}],
parameters:
[
Operation
.
parameter
(
:nickname
,
:path
,
:string
,
"User nickname"
)
|
admin_api_params
()
],
responses:
%{
200
=>
Operation
.
response
(
"Response"
,
"application/json"
,
user
()),
403
=>
Operation
.
response
(
"Forbidden"
,
"application/json"
,
ApiError
)
}
}
end