mirror of
https://github.com/element-hq/dendrite.git
synced 2025-09-13 21:02:25 +03:00
mas: implemented PUT /admin/v2/users/{userID} endpoint
MAS requires this endpoint to fetch the data for the account management page
This commit is contained in:
parent
9ebcebee43
commit
be8d490e56
5 changed files with 95 additions and 12 deletions
|
@ -21,8 +21,10 @@ import (
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"golang.org/x/exp/constraints"
|
"golang.org/x/exp/constraints"
|
||||||
|
|
||||||
|
appserviceAPI "github.com/element-hq/dendrite/appservice/api"
|
||||||
clientapi "github.com/element-hq/dendrite/clientapi/api"
|
clientapi "github.com/element-hq/dendrite/clientapi/api"
|
||||||
clienthttputil "github.com/element-hq/dendrite/clientapi/httputil"
|
clienthttputil "github.com/element-hq/dendrite/clientapi/httputil"
|
||||||
|
"github.com/element-hq/dendrite/clientapi/userutil"
|
||||||
"github.com/element-hq/dendrite/internal/httputil"
|
"github.com/element-hq/dendrite/internal/httputil"
|
||||||
roomserverAPI "github.com/element-hq/dendrite/roomserver/api"
|
roomserverAPI "github.com/element-hq/dendrite/roomserver/api"
|
||||||
"github.com/element-hq/dendrite/setup/config"
|
"github.com/element-hq/dendrite/setup/config"
|
||||||
|
@ -731,6 +733,76 @@ func AdminCreateOrModifyAccount(req *http.Request, userAPI userapi.ClientUserAPI
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func AdminRetrieveAccount(req *http.Request, cfg *config.ClientAPI, userAPI userapi.ClientUserAPI) util.JSONResponse {
|
||||||
|
logger := util.GetLogger(req.Context())
|
||||||
|
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
||||||
|
if err != nil {
|
||||||
|
return util.MessageResponse(http.StatusBadRequest, err.Error())
|
||||||
|
}
|
||||||
|
userID, ok := vars["userID"]
|
||||||
|
if !ok {
|
||||||
|
return util.JSONResponse{
|
||||||
|
Code: http.StatusBadRequest,
|
||||||
|
JSON: spec.MissingParam("Expecting user ID."),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
local, domain, err := userutil.ParseUsernameParam(userID, cfg.Matrix)
|
||||||
|
if err != nil {
|
||||||
|
return util.JSONResponse{
|
||||||
|
Code: http.StatusBadRequest,
|
||||||
|
JSON: spec.InvalidParam(err.Error()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
body := struct {
|
||||||
|
DisplayName string `json:"display_name"`
|
||||||
|
AvatarURL string `json:"avatar_url"`
|
||||||
|
Deactivated bool `json:"deactivated"`
|
||||||
|
}{}
|
||||||
|
|
||||||
|
{
|
||||||
|
var rs api.QueryAccountByLocalpartResponse
|
||||||
|
err := userAPI.QueryAccountByLocalpart(req.Context(), &api.QueryAccountByLocalpartRequest{Localpart: local, ServerName: domain}, &rs)
|
||||||
|
if err == sql.ErrNoRows {
|
||||||
|
return util.JSONResponse{
|
||||||
|
Code: http.StatusNotFound,
|
||||||
|
JSON: spec.NotFound(fmt.Sprintf("User '%s' not found", userID)),
|
||||||
|
}
|
||||||
|
} else if err != nil {
|
||||||
|
logger.WithError(err).Error("userAPI.QueryAccountByLocalpart")
|
||||||
|
return util.JSONResponse{
|
||||||
|
Code: http.StatusInternalServerError,
|
||||||
|
JSON: spec.Unknown(err.Error()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
body.Deactivated = rs.Account.Deactivated
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
profile, err := userAPI.QueryProfile(req.Context(), userID)
|
||||||
|
if err != nil {
|
||||||
|
if err == appserviceAPI.ErrProfileNotExists {
|
||||||
|
return util.JSONResponse{
|
||||||
|
Code: http.StatusNotFound,
|
||||||
|
JSON: spec.NotFound(err.Error()),
|
||||||
|
}
|
||||||
|
} else if err != nil {
|
||||||
|
return util.JSONResponse{
|
||||||
|
Code: http.StatusInternalServerError,
|
||||||
|
JSON: spec.Unknown(err.Error()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
body.AvatarURL = profile.AvatarURL
|
||||||
|
body.DisplayName = profile.DisplayName
|
||||||
|
}
|
||||||
|
|
||||||
|
return util.JSONResponse{
|
||||||
|
Code: http.StatusOK,
|
||||||
|
JSON: body,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// GetEventReports returns reported events for a given user/room.
|
// GetEventReports returns reported events for a given user/room.
|
||||||
func GetEventReports(
|
func GetEventReports(
|
||||||
req *http.Request,
|
req *http.Request,
|
||||||
|
|
|
@ -344,9 +344,16 @@ func Setup(
|
||||||
})).Methods(http.MethodGet)
|
})).Methods(http.MethodGet)
|
||||||
|
|
||||||
synapseAdminRouter.Handle("/admin/v2/users/{userID}",
|
synapseAdminRouter.Handle("/admin/v2/users/{userID}",
|
||||||
httputil.MakeServiceAdminAPI("admin_provision_user", m.AdminToken, func(r *http.Request) util.JSONResponse {
|
httputil.MakeServiceAdminAPI("admin_manage_user", m.AdminToken, func(r *http.Request) util.JSONResponse {
|
||||||
|
switch r.Method {
|
||||||
|
case http.MethodGet:
|
||||||
|
return AdminRetrieveAccount(r, cfg, userAPI)
|
||||||
|
case http.MethodPut:
|
||||||
return AdminCreateOrModifyAccount(r, userAPI)
|
return AdminCreateOrModifyAccount(r, userAPI)
|
||||||
})).Methods(http.MethodPut)
|
default:
|
||||||
|
return util.JSONResponse{Code: http.StatusMethodNotAllowed, JSON: nil}
|
||||||
|
}
|
||||||
|
})).Methods(http.MethodPut, http.MethodGet)
|
||||||
|
|
||||||
synapseAdminRouter.Handle("/admin/v2/users/{userID}/devices",
|
synapseAdminRouter.Handle("/admin/v2/users/{userID}/devices",
|
||||||
httputil.MakeServiceAdminAPI("admin_user_devices", m.AdminToken, func(r *http.Request) util.JSONResponse {
|
httputil.MakeServiceAdminAPI("admin_user_devices", m.AdminToken, func(r *http.Request) util.JSONResponse {
|
||||||
|
|
|
@ -31,7 +31,6 @@ type UserInternalAPI interface {
|
||||||
FederationUserAPI
|
FederationUserAPI
|
||||||
|
|
||||||
QuerySearchProfilesAPI // used by p2p demos
|
QuerySearchProfilesAPI // used by p2p demos
|
||||||
QueryAccountByLocalpart(ctx context.Context, req *QueryAccountByLocalpartRequest, res *QueryAccountByLocalpartResponse) (err error)
|
|
||||||
QueryExternalUserIDByLocalpartAndProvider(ctx context.Context, req *QueryLocalpartExternalIDRequest, res *QueryLocalpartExternalIDResponse) (err error)
|
QueryExternalUserIDByLocalpartAndProvider(ctx context.Context, req *QueryLocalpartExternalIDRequest, res *QueryLocalpartExternalIDResponse) (err error)
|
||||||
PerformLocalpartExternalUserIDCreation(ctx context.Context, req *PerformLocalpartExternalUserIDCreationRequest) (err error)
|
PerformLocalpartExternalUserIDCreation(ctx context.Context, req *PerformLocalpartExternalUserIDCreationRequest) (err error)
|
||||||
}
|
}
|
||||||
|
@ -89,6 +88,7 @@ type ClientUserAPI interface {
|
||||||
QueryPushers(ctx context.Context, req *QueryPushersRequest, res *QueryPushersResponse) error
|
QueryPushers(ctx context.Context, req *QueryPushersRequest, res *QueryPushersResponse) error
|
||||||
QueryPushRules(ctx context.Context, userID string) (*pushrules.AccountRuleSets, error)
|
QueryPushRules(ctx context.Context, userID string) (*pushrules.AccountRuleSets, error)
|
||||||
QueryAccountAvailability(ctx context.Context, req *QueryAccountAvailabilityRequest, res *QueryAccountAvailabilityResponse) error
|
QueryAccountAvailability(ctx context.Context, req *QueryAccountAvailabilityRequest, res *QueryAccountAvailabilityResponse) error
|
||||||
|
QueryAccountByLocalpart(ctx context.Context, req *QueryAccountByLocalpartRequest, res *QueryAccountByLocalpartResponse) (err error)
|
||||||
PerformAdminCreateRegistrationToken(ctx context.Context, registrationToken *clientapi.RegistrationToken) (bool, error)
|
PerformAdminCreateRegistrationToken(ctx context.Context, registrationToken *clientapi.RegistrationToken) (bool, error)
|
||||||
PerformAdminListRegistrationTokens(ctx context.Context, returnAll bool, valid bool) ([]clientapi.RegistrationToken, error)
|
PerformAdminListRegistrationTokens(ctx context.Context, returnAll bool, valid bool) ([]clientapi.RegistrationToken, error)
|
||||||
PerformAdminGetRegistrationToken(ctx context.Context, tokenString string) (*clientapi.RegistrationToken, error)
|
PerformAdminGetRegistrationToken(ctx context.Context, tokenString string) (*clientapi.RegistrationToken, error)
|
||||||
|
@ -461,6 +461,7 @@ type Account struct {
|
||||||
ServerName spec.ServerName
|
ServerName spec.ServerName
|
||||||
AppServiceID string
|
AppServiceID string
|
||||||
AccountType AccountType
|
AccountType AccountType
|
||||||
|
Deactivated bool
|
||||||
// TODO: Associations (e.g. with application services)
|
// TODO: Associations (e.g. with application services)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -55,7 +55,7 @@ const deactivateAccountSQL = "" +
|
||||||
"UPDATE userapi_accounts SET is_deactivated = TRUE WHERE localpart = $1 AND server_name = $2"
|
"UPDATE userapi_accounts SET is_deactivated = TRUE WHERE localpart = $1 AND server_name = $2"
|
||||||
|
|
||||||
const selectAccountByLocalpartSQL = "" +
|
const selectAccountByLocalpartSQL = "" +
|
||||||
"SELECT localpart, server_name, appservice_id, account_type FROM userapi_accounts WHERE localpart = $1 AND server_name = $2"
|
"SELECT localpart, server_name, appservice_id, account_type, is_deactivated FROM userapi_accounts WHERE localpart = $1 AND server_name = $2"
|
||||||
|
|
||||||
const selectPasswordHashSQL = "" +
|
const selectPasswordHashSQL = "" +
|
||||||
"SELECT password_hash FROM userapi_accounts WHERE localpart = $1 AND server_name = $2 AND is_deactivated = FALSE"
|
"SELECT password_hash FROM userapi_accounts WHERE localpart = $1 AND server_name = $2 AND is_deactivated = FALSE"
|
||||||
|
@ -116,6 +116,7 @@ func (s *accountsStatements) InsertAccount(
|
||||||
localpart string, serverName spec.ServerName,
|
localpart string, serverName spec.ServerName,
|
||||||
hash, appserviceID string, accountType api.AccountType,
|
hash, appserviceID string, accountType api.AccountType,
|
||||||
) (*api.Account, error) {
|
) (*api.Account, error) {
|
||||||
|
// TODO: can we replace "UnixNano() / 1M" with "UnixMilli()"?
|
||||||
createdTimeMS := time.Now().UnixNano() / 1000000
|
createdTimeMS := time.Now().UnixNano() / 1000000
|
||||||
stmt := sqlutil.TxStmt(txn, s.insertAccountStmt)
|
stmt := sqlutil.TxStmt(txn, s.insertAccountStmt)
|
||||||
|
|
||||||
|
@ -135,6 +136,7 @@ func (s *accountsStatements) InsertAccount(
|
||||||
ServerName: serverName,
|
ServerName: serverName,
|
||||||
AppServiceID: appserviceID,
|
AppServiceID: appserviceID,
|
||||||
AccountType: accountType,
|
AccountType: accountType,
|
||||||
|
Deactivated: false,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -167,7 +169,7 @@ func (s *accountsStatements) SelectAccountByLocalpart(
|
||||||
var acc api.Account
|
var acc api.Account
|
||||||
|
|
||||||
stmt := s.selectAccountByLocalpartStmt
|
stmt := s.selectAccountByLocalpartStmt
|
||||||
err := stmt.QueryRowContext(ctx, localpart, serverName).Scan(&acc.Localpart, &acc.ServerName, &appserviceIDPtr, &acc.AccountType)
|
err := stmt.QueryRowContext(ctx, localpart, serverName).Scan(&acc.Localpart, &acc.ServerName, &appserviceIDPtr, &acc.AccountType, &acc.Deactivated)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err != sql.ErrNoRows {
|
if err != sql.ErrNoRows {
|
||||||
log.WithError(err).Error("Unable to retrieve user from the db")
|
log.WithError(err).Error("Unable to retrieve user from the db")
|
||||||
|
|
|
@ -54,7 +54,7 @@ const deactivateAccountSQL = "" +
|
||||||
"UPDATE userapi_accounts SET is_deactivated = 1 WHERE localpart = $1 AND server_name = $2"
|
"UPDATE userapi_accounts SET is_deactivated = 1 WHERE localpart = $1 AND server_name = $2"
|
||||||
|
|
||||||
const selectAccountByLocalpartSQL = "" +
|
const selectAccountByLocalpartSQL = "" +
|
||||||
"SELECT localpart, server_name, appservice_id, account_type FROM userapi_accounts WHERE localpart = $1 AND server_name = $2"
|
"SELECT localpart, server_name, appservice_id, account_type, is_deactivated FROM userapi_accounts WHERE localpart = $1 AND server_name = $2"
|
||||||
|
|
||||||
const selectPasswordHashSQL = "" +
|
const selectPasswordHashSQL = "" +
|
||||||
"SELECT password_hash FROM userapi_accounts WHERE localpart = $1 AND server_name = $2 AND is_deactivated = 0"
|
"SELECT password_hash FROM userapi_accounts WHERE localpart = $1 AND server_name = $2 AND is_deactivated = 0"
|
||||||
|
@ -135,6 +135,7 @@ func (s *accountsStatements) InsertAccount(
|
||||||
ServerName: serverName,
|
ServerName: serverName,
|
||||||
AppServiceID: appserviceID,
|
AppServiceID: appserviceID,
|
||||||
AccountType: accountType,
|
AccountType: accountType,
|
||||||
|
Deactivated: false,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -167,7 +168,7 @@ func (s *accountsStatements) SelectAccountByLocalpart(
|
||||||
var acc api.Account
|
var acc api.Account
|
||||||
|
|
||||||
stmt := s.selectAccountByLocalpartStmt
|
stmt := s.selectAccountByLocalpartStmt
|
||||||
err := stmt.QueryRowContext(ctx, localpart, serverName).Scan(&acc.Localpart, &acc.ServerName, &appserviceIDPtr, &acc.AccountType)
|
err := stmt.QueryRowContext(ctx, localpart, serverName).Scan(&acc.Localpart, &acc.ServerName, &appserviceIDPtr, &acc.AccountType, &acc.Deactivated)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err != sql.ErrNoRows {
|
if err != sql.ErrNoRows {
|
||||||
log.WithError(err).Error("Unable to retrieve user from the db")
|
log.WithError(err).Error("Unable to retrieve user from the db")
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue