Add user profile tests, refactor user API methods (#3030)
This adds tests for `/profile`. Also, as a first change in this regard, refactors the methods defined on the `UserInternalAPI` to not use structs as the request/response parameters.
This commit is contained in:
parent
4cb9cd7842
commit
c2db38d295
|
@ -22,8 +22,6 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
"github.com/matrix-org/gomatrixserverlib"
|
|
||||||
|
|
||||||
"github.com/matrix-org/dendrite/clientapi/auth/authtypes"
|
"github.com/matrix-org/dendrite/clientapi/auth/authtypes"
|
||||||
userapi "github.com/matrix-org/dendrite/userapi/api"
|
userapi "github.com/matrix-org/dendrite/userapi/api"
|
||||||
)
|
)
|
||||||
|
@ -150,6 +148,10 @@ type ASLocationResponse struct {
|
||||||
Fields json.RawMessage `json:"fields"`
|
Fields json.RawMessage `json:"fields"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ErrProfileNotExists is returned when trying to lookup a user's profile that
|
||||||
|
// doesn't exist locally.
|
||||||
|
var ErrProfileNotExists = errors.New("no known profile for given user ID")
|
||||||
|
|
||||||
// RetrieveUserProfile is a wrapper that queries both the local database and
|
// RetrieveUserProfile is a wrapper that queries both the local database and
|
||||||
// application services for a given user's profile
|
// application services for a given user's profile
|
||||||
// TODO: Remove this, it's called from federationapi and clientapi but is a pure function
|
// TODO: Remove this, it's called from federationapi and clientapi but is a pure function
|
||||||
|
@ -157,25 +159,11 @@ func RetrieveUserProfile(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
userID string,
|
userID string,
|
||||||
asAPI AppServiceInternalAPI,
|
asAPI AppServiceInternalAPI,
|
||||||
profileAPI userapi.ClientUserAPI,
|
profileAPI userapi.ProfileAPI,
|
||||||
) (*authtypes.Profile, error) {
|
) (*authtypes.Profile, error) {
|
||||||
localpart, _, err := gomatrixserverlib.SplitID('@', userID)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Try to query the user from the local database
|
// Try to query the user from the local database
|
||||||
res := &userapi.QueryProfileResponse{}
|
profile, err := profileAPI.QueryProfile(ctx, userID)
|
||||||
err = profileAPI.QueryProfile(ctx, &userapi.QueryProfileRequest{UserID: userID}, res)
|
if err == nil {
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
profile := &authtypes.Profile{
|
|
||||||
Localpart: localpart,
|
|
||||||
DisplayName: res.DisplayName,
|
|
||||||
AvatarURL: res.AvatarURL,
|
|
||||||
}
|
|
||||||
if res.UserExists {
|
|
||||||
return profile, nil
|
return profile, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -188,19 +176,15 @@ func RetrieveUserProfile(
|
||||||
|
|
||||||
// If no user exists, return
|
// If no user exists, return
|
||||||
if !userResp.UserIDExists {
|
if !userResp.UserIDExists {
|
||||||
return nil, errors.New("no known profile for given user ID")
|
return nil, ErrProfileNotExists
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try to query the user from the local database again
|
// Try to query the user from the local database again
|
||||||
err = profileAPI.QueryProfile(ctx, &userapi.QueryProfileRequest{UserID: userID}, res)
|
profile, err = profileAPI.QueryProfile(ctx, userID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// profile should not be nil at this point
|
// profile should not be nil at this point
|
||||||
return &authtypes.Profile{
|
return profile, nil
|
||||||
Localpart: localpart,
|
|
||||||
DisplayName: res.DisplayName,
|
|
||||||
AvatarURL: res.AvatarURL,
|
|
||||||
}, nil
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -261,6 +261,25 @@ func TestAdminEvacuateRoom(t *testing.T) {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Wait for the FS API to have consumed every message
|
||||||
|
js, _ := natsInstance.Prepare(processCtx, &cfg.Global.JetStream)
|
||||||
|
timeout := time.After(time.Second)
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-timeout:
|
||||||
|
t.Fatalf("FS API didn't process all events in time")
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
info, err := js.ConsumerInfo(cfg.Global.JetStream.Prefixed(jetstream.OutputRoomEvent), cfg.Global.JetStream.Durable("FederationAPIRoomServerConsumer")+"Pull")
|
||||||
|
if err != nil {
|
||||||
|
time.Sleep(time.Millisecond * 10)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if info.NumPending == 0 && info.NumAckPending == 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,25 +4,30 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/matrix-org/gomatrixserverlib"
|
||||||
|
"github.com/matrix-org/util"
|
||||||
|
"github.com/tidwall/gjson"
|
||||||
|
|
||||||
|
"github.com/matrix-org/dendrite/appservice"
|
||||||
"github.com/matrix-org/dendrite/clientapi/auth/authtypes"
|
"github.com/matrix-org/dendrite/clientapi/auth/authtypes"
|
||||||
"github.com/matrix-org/dendrite/internal/caching"
|
"github.com/matrix-org/dendrite/internal/caching"
|
||||||
"github.com/matrix-org/dendrite/internal/httputil"
|
"github.com/matrix-org/dendrite/internal/httputil"
|
||||||
"github.com/matrix-org/dendrite/internal/sqlutil"
|
"github.com/matrix-org/dendrite/internal/sqlutil"
|
||||||
"github.com/matrix-org/dendrite/roomserver"
|
"github.com/matrix-org/dendrite/roomserver"
|
||||||
|
"github.com/matrix-org/dendrite/setup/base"
|
||||||
"github.com/matrix-org/dendrite/setup/jetstream"
|
"github.com/matrix-org/dendrite/setup/jetstream"
|
||||||
"github.com/matrix-org/dendrite/test"
|
"github.com/matrix-org/dendrite/test"
|
||||||
"github.com/matrix-org/dendrite/test/testrig"
|
"github.com/matrix-org/dendrite/test/testrig"
|
||||||
"github.com/matrix-org/dendrite/userapi"
|
"github.com/matrix-org/dendrite/userapi"
|
||||||
uapi "github.com/matrix-org/dendrite/userapi/api"
|
uapi "github.com/matrix-org/dendrite/userapi/api"
|
||||||
"github.com/matrix-org/gomatrixserverlib"
|
|
||||||
"github.com/matrix-org/util"
|
|
||||||
"github.com/tidwall/gjson"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type userDevice struct {
|
type userDevice struct {
|
||||||
|
@ -371,3 +376,227 @@ func createAccessTokens(t *testing.T, accessTokens map[*test.User]userDevice, us
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestSetDisplayname(t *testing.T) {
|
||||||
|
alice := test.NewUser(t)
|
||||||
|
bob := test.NewUser(t)
|
||||||
|
notLocalUser := &test.User{ID: "@charlie:localhost", Localpart: "charlie"}
|
||||||
|
changeDisplayName := "my new display name"
|
||||||
|
|
||||||
|
testCases := []struct {
|
||||||
|
name string
|
||||||
|
user *test.User
|
||||||
|
wantOK bool
|
||||||
|
changeReq io.Reader
|
||||||
|
wantDisplayName string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "invalid user",
|
||||||
|
user: &test.User{ID: "!notauser"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "non-existent user",
|
||||||
|
user: &test.User{ID: "@doesnotexist:test"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "non-local user is not allowed",
|
||||||
|
user: notLocalUser,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "existing user is allowed to change own name",
|
||||||
|
user: alice,
|
||||||
|
wantOK: true,
|
||||||
|
wantDisplayName: changeDisplayName,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "existing user is not allowed to change own name if name is empty",
|
||||||
|
user: bob,
|
||||||
|
wantOK: false,
|
||||||
|
wantDisplayName: "",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
test.WithAllDatabases(t, func(t *testing.T, dbType test.DBType) {
|
||||||
|
cfg, processCtx, closeDB := testrig.CreateConfig(t, dbType)
|
||||||
|
defer closeDB()
|
||||||
|
caches := caching.NewRistrettoCache(128*1024*1024, time.Hour, caching.DisableMetrics)
|
||||||
|
routers := httputil.NewRouters()
|
||||||
|
cm := sqlutil.NewConnectionManager(processCtx, cfg.Global.DatabaseOptions)
|
||||||
|
natsInstance := &jetstream.NATSInstance{}
|
||||||
|
|
||||||
|
rsAPI := roomserver.NewInternalAPI(processCtx, cfg, cm, natsInstance, caches, caching.DisableMetrics)
|
||||||
|
rsAPI.SetFederationAPI(nil, nil)
|
||||||
|
userAPI := userapi.NewInternalAPI(processCtx, cfg, cm, natsInstance, rsAPI, nil)
|
||||||
|
asPI := appservice.NewInternalAPI(processCtx, cfg, natsInstance, userAPI, rsAPI)
|
||||||
|
|
||||||
|
AddPublicRoutes(processCtx, routers, cfg, natsInstance, base.CreateFederationClient(cfg, nil), rsAPI, asPI, nil, nil, userAPI, nil, nil, caching.DisableMetrics)
|
||||||
|
|
||||||
|
accessTokens := map[*test.User]userDevice{
|
||||||
|
alice: {},
|
||||||
|
bob: {},
|
||||||
|
}
|
||||||
|
|
||||||
|
createAccessTokens(t, accessTokens, userAPI, processCtx.Context(), routers)
|
||||||
|
|
||||||
|
for _, tc := range testCases {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
wantDisplayName := tc.user.Localpart
|
||||||
|
if tc.changeReq == nil {
|
||||||
|
tc.changeReq = strings.NewReader("")
|
||||||
|
}
|
||||||
|
|
||||||
|
// check profile after initial account creation
|
||||||
|
rec := httptest.NewRecorder()
|
||||||
|
req := httptest.NewRequest(http.MethodGet, "/_matrix/client/v3/profile/"+tc.user.ID, strings.NewReader(""))
|
||||||
|
t.Logf("%s", req.URL.String())
|
||||||
|
routers.Client.ServeHTTP(rec, req)
|
||||||
|
|
||||||
|
if tc.wantOK && rec.Code != http.StatusOK {
|
||||||
|
t.Fatalf("expected HTTP 200, got %d", rec.Code)
|
||||||
|
}
|
||||||
|
|
||||||
|
if gotDisplayName := gjson.GetBytes(rec.Body.Bytes(), "displayname").Str; tc.wantOK && gotDisplayName != wantDisplayName {
|
||||||
|
t.Fatalf("expected displayname to be '%s', but got '%s'", wantDisplayName, gotDisplayName)
|
||||||
|
}
|
||||||
|
|
||||||
|
// now set the new display name
|
||||||
|
wantDisplayName = tc.wantDisplayName
|
||||||
|
tc.changeReq = strings.NewReader(fmt.Sprintf(`{"displayname":"%s"}`, tc.wantDisplayName))
|
||||||
|
|
||||||
|
rec = httptest.NewRecorder()
|
||||||
|
req = httptest.NewRequest(http.MethodPut, "/_matrix/client/v3/profile/"+tc.user.ID+"/displayname", tc.changeReq)
|
||||||
|
req.Header.Set("Authorization", "Bearer "+accessTokens[tc.user].accessToken)
|
||||||
|
|
||||||
|
routers.Client.ServeHTTP(rec, req)
|
||||||
|
if tc.wantOK && rec.Code != http.StatusOK {
|
||||||
|
t.Fatalf("expected HTTP 200, got %d: %s", rec.Code, rec.Body.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
// now only get the display name
|
||||||
|
rec = httptest.NewRecorder()
|
||||||
|
req = httptest.NewRequest(http.MethodGet, "/_matrix/client/v3/profile/"+tc.user.ID+"/displayname", strings.NewReader(""))
|
||||||
|
|
||||||
|
routers.Client.ServeHTTP(rec, req)
|
||||||
|
if tc.wantOK && rec.Code != http.StatusOK {
|
||||||
|
t.Fatalf("expected HTTP 200, got %d: %s", rec.Code, rec.Body.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
if gotDisplayName := gjson.GetBytes(rec.Body.Bytes(), "displayname").Str; tc.wantOK && gotDisplayName != wantDisplayName {
|
||||||
|
t.Fatalf("expected displayname to be '%s', but got '%s'", wantDisplayName, gotDisplayName)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSetAvatarURL(t *testing.T) {
|
||||||
|
alice := test.NewUser(t)
|
||||||
|
bob := test.NewUser(t)
|
||||||
|
notLocalUser := &test.User{ID: "@charlie:localhost", Localpart: "charlie"}
|
||||||
|
changeDisplayName := "mxc://newMXID"
|
||||||
|
|
||||||
|
testCases := []struct {
|
||||||
|
name string
|
||||||
|
user *test.User
|
||||||
|
wantOK bool
|
||||||
|
changeReq io.Reader
|
||||||
|
avatar_url string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "invalid user",
|
||||||
|
user: &test.User{ID: "!notauser"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "non-existent user",
|
||||||
|
user: &test.User{ID: "@doesnotexist:test"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "non-local user is not allowed",
|
||||||
|
user: notLocalUser,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "existing user is allowed to change own avatar",
|
||||||
|
user: alice,
|
||||||
|
wantOK: true,
|
||||||
|
avatar_url: changeDisplayName,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "existing user is not allowed to change own avatar if avatar is empty",
|
||||||
|
user: bob,
|
||||||
|
wantOK: false,
|
||||||
|
avatar_url: "",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
test.WithAllDatabases(t, func(t *testing.T, dbType test.DBType) {
|
||||||
|
cfg, processCtx, closeDB := testrig.CreateConfig(t, dbType)
|
||||||
|
defer closeDB()
|
||||||
|
caches := caching.NewRistrettoCache(128*1024*1024, time.Hour, caching.DisableMetrics)
|
||||||
|
routers := httputil.NewRouters()
|
||||||
|
cm := sqlutil.NewConnectionManager(processCtx, cfg.Global.DatabaseOptions)
|
||||||
|
natsInstance := &jetstream.NATSInstance{}
|
||||||
|
|
||||||
|
rsAPI := roomserver.NewInternalAPI(processCtx, cfg, cm, natsInstance, caches, caching.DisableMetrics)
|
||||||
|
rsAPI.SetFederationAPI(nil, nil)
|
||||||
|
userAPI := userapi.NewInternalAPI(processCtx, cfg, cm, natsInstance, rsAPI, nil)
|
||||||
|
asPI := appservice.NewInternalAPI(processCtx, cfg, natsInstance, userAPI, rsAPI)
|
||||||
|
|
||||||
|
AddPublicRoutes(processCtx, routers, cfg, natsInstance, base.CreateFederationClient(cfg, nil), rsAPI, asPI, nil, nil, userAPI, nil, nil, caching.DisableMetrics)
|
||||||
|
|
||||||
|
accessTokens := map[*test.User]userDevice{
|
||||||
|
alice: {},
|
||||||
|
bob: {},
|
||||||
|
}
|
||||||
|
|
||||||
|
createAccessTokens(t, accessTokens, userAPI, processCtx.Context(), routers)
|
||||||
|
|
||||||
|
for _, tc := range testCases {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
wantAvatarURL := ""
|
||||||
|
if tc.changeReq == nil {
|
||||||
|
tc.changeReq = strings.NewReader("")
|
||||||
|
}
|
||||||
|
|
||||||
|
// check profile after initial account creation
|
||||||
|
rec := httptest.NewRecorder()
|
||||||
|
req := httptest.NewRequest(http.MethodGet, "/_matrix/client/v3/profile/"+tc.user.ID, strings.NewReader(""))
|
||||||
|
t.Logf("%s", req.URL.String())
|
||||||
|
routers.Client.ServeHTTP(rec, req)
|
||||||
|
|
||||||
|
if tc.wantOK && rec.Code != http.StatusOK {
|
||||||
|
t.Fatalf("expected HTTP 200, got %d", rec.Code)
|
||||||
|
}
|
||||||
|
|
||||||
|
if gotDisplayName := gjson.GetBytes(rec.Body.Bytes(), "avatar_url").Str; tc.wantOK && gotDisplayName != wantAvatarURL {
|
||||||
|
t.Fatalf("expected displayname to be '%s', but got '%s'", wantAvatarURL, gotDisplayName)
|
||||||
|
}
|
||||||
|
|
||||||
|
// now set the new display name
|
||||||
|
wantAvatarURL = tc.avatar_url
|
||||||
|
tc.changeReq = strings.NewReader(fmt.Sprintf(`{"avatar_url":"%s"}`, tc.avatar_url))
|
||||||
|
|
||||||
|
rec = httptest.NewRecorder()
|
||||||
|
req = httptest.NewRequest(http.MethodPut, "/_matrix/client/v3/profile/"+tc.user.ID+"/avatar_url", tc.changeReq)
|
||||||
|
req.Header.Set("Authorization", "Bearer "+accessTokens[tc.user].accessToken)
|
||||||
|
|
||||||
|
routers.Client.ServeHTTP(rec, req)
|
||||||
|
if tc.wantOK && rec.Code != http.StatusOK {
|
||||||
|
t.Fatalf("expected HTTP 200, got %d: %s", rec.Code, rec.Body.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
// now only get the display name
|
||||||
|
rec = httptest.NewRecorder()
|
||||||
|
req = httptest.NewRequest(http.MethodGet, "/_matrix/client/v3/profile/"+tc.user.ID+"/avatar_url", strings.NewReader(""))
|
||||||
|
|
||||||
|
routers.Client.ServeHTTP(rec, req)
|
||||||
|
if tc.wantOK && rec.Code != http.StatusOK {
|
||||||
|
t.Fatalf("expected HTTP 200, got %d: %s", rec.Code, rec.Body.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
if gotDisplayName := gjson.GetBytes(rec.Body.Bytes(), "avatar_url").Str; tc.wantOK && gotDisplayName != wantAvatarURL {
|
||||||
|
t.Fatalf("expected displayname to be '%s', but got '%s'", wantAvatarURL, gotDisplayName)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
appserviceAPI "github.com/matrix-org/dendrite/appservice/api"
|
||||||
"github.com/matrix-org/dendrite/clientapi/httputil"
|
"github.com/matrix-org/dendrite/clientapi/httputil"
|
||||||
"github.com/matrix-org/dendrite/clientapi/jsonerror"
|
"github.com/matrix-org/dendrite/clientapi/jsonerror"
|
||||||
roomserverAPI "github.com/matrix-org/dendrite/roomserver/api"
|
roomserverAPI "github.com/matrix-org/dendrite/roomserver/api"
|
||||||
|
@ -61,21 +62,19 @@ func JoinRoomByIDOrAlias(
|
||||||
// Work out our localpart for the client profile request.
|
// Work out our localpart for the client profile request.
|
||||||
|
|
||||||
// Request our profile content to populate the request content with.
|
// Request our profile content to populate the request content with.
|
||||||
res := &api.QueryProfileResponse{}
|
profile, err := profileAPI.QueryProfile(req.Context(), device.UserID)
|
||||||
err := profileAPI.QueryProfile(req.Context(), &api.QueryProfileRequest{UserID: device.UserID}, res)
|
|
||||||
if err != nil || !res.UserExists {
|
switch err {
|
||||||
if !res.UserExists {
|
case nil:
|
||||||
|
joinReq.Content["displayname"] = profile.DisplayName
|
||||||
|
joinReq.Content["avatar_url"] = profile.AvatarURL
|
||||||
|
case appserviceAPI.ErrProfileNotExists:
|
||||||
util.GetLogger(req.Context()).Error("Unable to query user profile, no profile found.")
|
util.GetLogger(req.Context()).Error("Unable to query user profile, no profile found.")
|
||||||
return util.JSONResponse{
|
return util.JSONResponse{
|
||||||
Code: http.StatusInternalServerError,
|
Code: http.StatusInternalServerError,
|
||||||
JSON: jsonerror.Unknown("Unable to query user profile, no profile found."),
|
JSON: jsonerror.Unknown("Unable to query user profile, no profile found."),
|
||||||
}
|
}
|
||||||
}
|
default:
|
||||||
|
|
||||||
util.GetLogger(req.Context()).WithError(err).Error("UserProfileAPI.QueryProfile failed")
|
|
||||||
} else {
|
|
||||||
joinReq.Content["displayname"] = res.DisplayName
|
|
||||||
joinReq.Content["avatar_url"] = res.AvatarURL
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ask the roomserver to perform the join.
|
// Ask the roomserver to perform the join.
|
||||||
|
|
|
@ -36,14 +36,14 @@ import (
|
||||||
|
|
||||||
// GetProfile implements GET /profile/{userID}
|
// GetProfile implements GET /profile/{userID}
|
||||||
func GetProfile(
|
func GetProfile(
|
||||||
req *http.Request, profileAPI userapi.ClientUserAPI, cfg *config.ClientAPI,
|
req *http.Request, profileAPI userapi.ProfileAPI, cfg *config.ClientAPI,
|
||||||
userID string,
|
userID string,
|
||||||
asAPI appserviceAPI.AppServiceInternalAPI,
|
asAPI appserviceAPI.AppServiceInternalAPI,
|
||||||
federation *gomatrixserverlib.FederationClient,
|
federation *gomatrixserverlib.FederationClient,
|
||||||
) util.JSONResponse {
|
) util.JSONResponse {
|
||||||
profile, err := getProfile(req.Context(), profileAPI, cfg, userID, asAPI, federation)
|
profile, err := getProfile(req.Context(), profileAPI, cfg, userID, asAPI, federation)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == eventutil.ErrProfileNoExists {
|
if err == appserviceAPI.ErrProfileNotExists {
|
||||||
return util.JSONResponse{
|
return util.JSONResponse{
|
||||||
Code: http.StatusNotFound,
|
Code: http.StatusNotFound,
|
||||||
JSON: jsonerror.NotFound("The user does not exist or does not have a profile"),
|
JSON: jsonerror.NotFound("The user does not exist or does not have a profile"),
|
||||||
|
@ -56,7 +56,7 @@ func GetProfile(
|
||||||
|
|
||||||
return util.JSONResponse{
|
return util.JSONResponse{
|
||||||
Code: http.StatusOK,
|
Code: http.StatusOK,
|
||||||
JSON: eventutil.ProfileResponse{
|
JSON: eventutil.UserProfile{
|
||||||
AvatarURL: profile.AvatarURL,
|
AvatarURL: profile.AvatarURL,
|
||||||
DisplayName: profile.DisplayName,
|
DisplayName: profile.DisplayName,
|
||||||
},
|
},
|
||||||
|
@ -65,34 +65,28 @@ func GetProfile(
|
||||||
|
|
||||||
// GetAvatarURL implements GET /profile/{userID}/avatar_url
|
// GetAvatarURL implements GET /profile/{userID}/avatar_url
|
||||||
func GetAvatarURL(
|
func GetAvatarURL(
|
||||||
req *http.Request, profileAPI userapi.ClientUserAPI, cfg *config.ClientAPI,
|
req *http.Request, profileAPI userapi.ProfileAPI, cfg *config.ClientAPI,
|
||||||
userID string, asAPI appserviceAPI.AppServiceInternalAPI,
|
userID string, asAPI appserviceAPI.AppServiceInternalAPI,
|
||||||
federation *gomatrixserverlib.FederationClient,
|
federation *gomatrixserverlib.FederationClient,
|
||||||
) util.JSONResponse {
|
) util.JSONResponse {
|
||||||
profile, err := getProfile(req.Context(), profileAPI, cfg, userID, asAPI, federation)
|
profile := GetProfile(req, profileAPI, cfg, userID, asAPI, federation)
|
||||||
if err != nil {
|
p, ok := profile.JSON.(eventutil.UserProfile)
|
||||||
if err == eventutil.ErrProfileNoExists {
|
// not a profile response, so most likely an error, return that
|
||||||
return util.JSONResponse{
|
if !ok {
|
||||||
Code: http.StatusNotFound,
|
return profile
|
||||||
JSON: jsonerror.NotFound("The user does not exist or does not have a profile"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
util.GetLogger(req.Context()).WithError(err).Error("getProfile failed")
|
|
||||||
return jsonerror.InternalServerError()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return util.JSONResponse{
|
return util.JSONResponse{
|
||||||
Code: http.StatusOK,
|
Code: http.StatusOK,
|
||||||
JSON: eventutil.AvatarURL{
|
JSON: eventutil.UserProfile{
|
||||||
AvatarURL: profile.AvatarURL,
|
AvatarURL: p.AvatarURL,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetAvatarURL implements PUT /profile/{userID}/avatar_url
|
// SetAvatarURL implements PUT /profile/{userID}/avatar_url
|
||||||
func SetAvatarURL(
|
func SetAvatarURL(
|
||||||
req *http.Request, profileAPI userapi.ClientUserAPI,
|
req *http.Request, profileAPI userapi.ProfileAPI,
|
||||||
device *userapi.Device, userID string, cfg *config.ClientAPI, rsAPI api.ClientRoomserverAPI,
|
device *userapi.Device, userID string, cfg *config.ClientAPI, rsAPI api.ClientRoomserverAPI,
|
||||||
) util.JSONResponse {
|
) util.JSONResponse {
|
||||||
if userID != device.UserID {
|
if userID != device.UserID {
|
||||||
|
@ -102,7 +96,7 @@ func SetAvatarURL(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var r eventutil.AvatarURL
|
var r eventutil.UserProfile
|
||||||
if resErr := httputil.UnmarshalJSONRequest(req, &r); resErr != nil {
|
if resErr := httputil.UnmarshalJSONRequest(req, &r); resErr != nil {
|
||||||
return *resErr
|
return *resErr
|
||||||
}
|
}
|
||||||
|
@ -134,24 +128,20 @@ func SetAvatarURL(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setRes := &userapi.PerformSetAvatarURLResponse{}
|
profile, changed, err := profileAPI.SetAvatarURL(req.Context(), localpart, domain, r.AvatarURL)
|
||||||
if err = profileAPI.SetAvatarURL(req.Context(), &userapi.PerformSetAvatarURLRequest{
|
if err != nil {
|
||||||
Localpart: localpart,
|
|
||||||
ServerName: domain,
|
|
||||||
AvatarURL: r.AvatarURL,
|
|
||||||
}, setRes); err != nil {
|
|
||||||
util.GetLogger(req.Context()).WithError(err).Error("profileAPI.SetAvatarURL failed")
|
util.GetLogger(req.Context()).WithError(err).Error("profileAPI.SetAvatarURL failed")
|
||||||
return jsonerror.InternalServerError()
|
return jsonerror.InternalServerError()
|
||||||
}
|
}
|
||||||
// No need to build new membership events, since nothing changed
|
// No need to build new membership events, since nothing changed
|
||||||
if !setRes.Changed {
|
if !changed {
|
||||||
return util.JSONResponse{
|
return util.JSONResponse{
|
||||||
Code: http.StatusOK,
|
Code: http.StatusOK,
|
||||||
JSON: struct{}{},
|
JSON: struct{}{},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
response, err := updateProfile(req.Context(), rsAPI, device, setRes.Profile, userID, cfg, evTime)
|
response, err := updateProfile(req.Context(), rsAPI, device, profile, userID, cfg, evTime)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return response
|
return response
|
||||||
}
|
}
|
||||||
|
@ -164,34 +154,28 @@ func SetAvatarURL(
|
||||||
|
|
||||||
// GetDisplayName implements GET /profile/{userID}/displayname
|
// GetDisplayName implements GET /profile/{userID}/displayname
|
||||||
func GetDisplayName(
|
func GetDisplayName(
|
||||||
req *http.Request, profileAPI userapi.ClientUserAPI, cfg *config.ClientAPI,
|
req *http.Request, profileAPI userapi.ProfileAPI, cfg *config.ClientAPI,
|
||||||
userID string, asAPI appserviceAPI.AppServiceInternalAPI,
|
userID string, asAPI appserviceAPI.AppServiceInternalAPI,
|
||||||
federation *gomatrixserverlib.FederationClient,
|
federation *gomatrixserverlib.FederationClient,
|
||||||
) util.JSONResponse {
|
) util.JSONResponse {
|
||||||
profile, err := getProfile(req.Context(), profileAPI, cfg, userID, asAPI, federation)
|
profile := GetProfile(req, profileAPI, cfg, userID, asAPI, federation)
|
||||||
if err != nil {
|
p, ok := profile.JSON.(eventutil.UserProfile)
|
||||||
if err == eventutil.ErrProfileNoExists {
|
// not a profile response, so most likely an error, return that
|
||||||
return util.JSONResponse{
|
if !ok {
|
||||||
Code: http.StatusNotFound,
|
return profile
|
||||||
JSON: jsonerror.NotFound("The user does not exist or does not have a profile"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
util.GetLogger(req.Context()).WithError(err).Error("getProfile failed")
|
|
||||||
return jsonerror.InternalServerError()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return util.JSONResponse{
|
return util.JSONResponse{
|
||||||
Code: http.StatusOK,
|
Code: http.StatusOK,
|
||||||
JSON: eventutil.DisplayName{
|
JSON: eventutil.UserProfile{
|
||||||
DisplayName: profile.DisplayName,
|
DisplayName: p.DisplayName,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetDisplayName implements PUT /profile/{userID}/displayname
|
// SetDisplayName implements PUT /profile/{userID}/displayname
|
||||||
func SetDisplayName(
|
func SetDisplayName(
|
||||||
req *http.Request, profileAPI userapi.ClientUserAPI,
|
req *http.Request, profileAPI userapi.ProfileAPI,
|
||||||
device *userapi.Device, userID string, cfg *config.ClientAPI, rsAPI api.ClientRoomserverAPI,
|
device *userapi.Device, userID string, cfg *config.ClientAPI, rsAPI api.ClientRoomserverAPI,
|
||||||
) util.JSONResponse {
|
) util.JSONResponse {
|
||||||
if userID != device.UserID {
|
if userID != device.UserID {
|
||||||
|
@ -201,7 +185,7 @@ func SetDisplayName(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var r eventutil.DisplayName
|
var r eventutil.UserProfile
|
||||||
if resErr := httputil.UnmarshalJSONRequest(req, &r); resErr != nil {
|
if resErr := httputil.UnmarshalJSONRequest(req, &r); resErr != nil {
|
||||||
return *resErr
|
return *resErr
|
||||||
}
|
}
|
||||||
|
@ -233,25 +217,20 @@ func SetDisplayName(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
profileRes := &userapi.PerformUpdateDisplayNameResponse{}
|
profile, changed, err := profileAPI.SetDisplayName(req.Context(), localpart, domain, r.DisplayName)
|
||||||
err = profileAPI.SetDisplayName(req.Context(), &userapi.PerformUpdateDisplayNameRequest{
|
|
||||||
Localpart: localpart,
|
|
||||||
ServerName: domain,
|
|
||||||
DisplayName: r.DisplayName,
|
|
||||||
}, profileRes)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
util.GetLogger(req.Context()).WithError(err).Error("profileAPI.SetDisplayName failed")
|
util.GetLogger(req.Context()).WithError(err).Error("profileAPI.SetDisplayName failed")
|
||||||
return jsonerror.InternalServerError()
|
return jsonerror.InternalServerError()
|
||||||
}
|
}
|
||||||
// No need to build new membership events, since nothing changed
|
// No need to build new membership events, since nothing changed
|
||||||
if !profileRes.Changed {
|
if !changed {
|
||||||
return util.JSONResponse{
|
return util.JSONResponse{
|
||||||
Code: http.StatusOK,
|
Code: http.StatusOK,
|
||||||
JSON: struct{}{},
|
JSON: struct{}{},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
response, err := updateProfile(req.Context(), rsAPI, device, profileRes.Profile, userID, cfg, evTime)
|
response, err := updateProfile(req.Context(), rsAPI, device, profile, userID, cfg, evTime)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return response
|
return response
|
||||||
}
|
}
|
||||||
|
@ -308,9 +287,9 @@ func updateProfile(
|
||||||
// getProfile gets the full profile of a user by querying the database or a
|
// getProfile gets the full profile of a user by querying the database or a
|
||||||
// remote homeserver.
|
// remote homeserver.
|
||||||
// Returns an error when something goes wrong or specifically
|
// Returns an error when something goes wrong or specifically
|
||||||
// eventutil.ErrProfileNoExists when the profile doesn't exist.
|
// eventutil.ErrProfileNotExists when the profile doesn't exist.
|
||||||
func getProfile(
|
func getProfile(
|
||||||
ctx context.Context, profileAPI userapi.ClientUserAPI, cfg *config.ClientAPI,
|
ctx context.Context, profileAPI userapi.ProfileAPI, cfg *config.ClientAPI,
|
||||||
userID string,
|
userID string,
|
||||||
asAPI appserviceAPI.AppServiceInternalAPI,
|
asAPI appserviceAPI.AppServiceInternalAPI,
|
||||||
federation *gomatrixserverlib.FederationClient,
|
federation *gomatrixserverlib.FederationClient,
|
||||||
|
@ -325,7 +304,7 @@ func getProfile(
|
||||||
if fedErr != nil {
|
if fedErr != nil {
|
||||||
if x, ok := fedErr.(gomatrix.HTTPError); ok {
|
if x, ok := fedErr.(gomatrix.HTTPError); ok {
|
||||||
if x.Code == http.StatusNotFound {
|
if x.Code == http.StatusNotFound {
|
||||||
return nil, eventutil.ErrProfileNoExists
|
return nil, appserviceAPI.ErrProfileNotExists
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -888,13 +888,7 @@ func completeRegistration(
|
||||||
}
|
}
|
||||||
|
|
||||||
if displayName != "" {
|
if displayName != "" {
|
||||||
nameReq := userapi.PerformUpdateDisplayNameRequest{
|
_, _, err = userAPI.SetDisplayName(ctx, username, serverName, displayName)
|
||||||
Localpart: username,
|
|
||||||
ServerName: serverName,
|
|
||||||
DisplayName: displayName,
|
|
||||||
}
|
|
||||||
var nameRes userapi.PerformUpdateDisplayNameResponse
|
|
||||||
err = userAPI.SetDisplayName(ctx, &nameReq, &nameRes)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return util.JSONResponse{
|
return util.JSONResponse{
|
||||||
Code: http.StatusInternalServerError,
|
Code: http.StatusInternalServerError,
|
||||||
|
|
|
@ -611,11 +611,9 @@ func TestRegisterUserWithDisplayName(t *testing.T) {
|
||||||
|
|
||||||
assert.Equal(t, http.StatusOK, response.Code)
|
assert.Equal(t, http.StatusOK, response.Code)
|
||||||
|
|
||||||
req := api.QueryProfileRequest{UserID: "@user:server"}
|
profile, err := userAPI.QueryProfile(processCtx.Context(), "@user:server")
|
||||||
var res api.QueryProfileResponse
|
|
||||||
err := userAPI.QueryProfile(processCtx.Context(), &req, &res)
|
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, expectedDisplayName, res.DisplayName)
|
assert.Equal(t, expectedDisplayName, profile.DisplayName)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -662,10 +660,8 @@ func TestRegisterAdminUsingSharedSecret(t *testing.T) {
|
||||||
)
|
)
|
||||||
assert.Equal(t, http.StatusOK, response.Code)
|
assert.Equal(t, http.StatusOK, response.Code)
|
||||||
|
|
||||||
profilReq := api.QueryProfileRequest{UserID: "@alice:server"}
|
profile, err := userAPI.QueryProfile(processCtx.Context(), "@alice:server")
|
||||||
var profileRes api.QueryProfileResponse
|
|
||||||
err = userAPI.QueryProfile(processCtx.Context(), &profilReq, &profileRes)
|
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, expectedDisplayName, profileRes.DisplayName)
|
assert.Equal(t, expectedDisplayName, profile.DisplayName)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -295,30 +295,28 @@ func getSenderDevice(
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the avatarurl for the user
|
// Set the avatarurl for the user
|
||||||
avatarRes := &userapi.PerformSetAvatarURLResponse{}
|
profile, avatarChanged, err := userAPI.SetAvatarURL(ctx,
|
||||||
if err = userAPI.SetAvatarURL(ctx, &userapi.PerformSetAvatarURLRequest{
|
cfg.Matrix.ServerNotices.LocalPart,
|
||||||
Localpart: cfg.Matrix.ServerNotices.LocalPart,
|
cfg.Matrix.ServerName,
|
||||||
ServerName: cfg.Matrix.ServerName,
|
cfg.Matrix.ServerNotices.AvatarURL,
|
||||||
AvatarURL: cfg.Matrix.ServerNotices.AvatarURL,
|
)
|
||||||
}, avatarRes); err != nil {
|
if err != nil {
|
||||||
util.GetLogger(ctx).WithError(err).Error("userAPI.SetAvatarURL failed")
|
util.GetLogger(ctx).WithError(err).Error("userAPI.SetAvatarURL failed")
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
profile := avatarRes.Profile
|
|
||||||
|
|
||||||
// Set the displayname for the user
|
// Set the displayname for the user
|
||||||
displayNameRes := &userapi.PerformUpdateDisplayNameResponse{}
|
_, displayNameChanged, err := userAPI.SetDisplayName(ctx,
|
||||||
if err = userAPI.SetDisplayName(ctx, &userapi.PerformUpdateDisplayNameRequest{
|
cfg.Matrix.ServerNotices.LocalPart,
|
||||||
Localpart: cfg.Matrix.ServerNotices.LocalPart,
|
cfg.Matrix.ServerName,
|
||||||
ServerName: cfg.Matrix.ServerName,
|
cfg.Matrix.ServerNotices.DisplayName,
|
||||||
DisplayName: cfg.Matrix.ServerNotices.DisplayName,
|
)
|
||||||
}, displayNameRes); err != nil {
|
if err != nil {
|
||||||
util.GetLogger(ctx).WithError(err).Error("userAPI.SetDisplayName failed")
|
util.GetLogger(ctx).WithError(err).Error("userAPI.SetDisplayName failed")
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if displayNameRes.Changed {
|
if displayNameChanged {
|
||||||
profile.DisplayName = cfg.Matrix.ServerNotices.DisplayName
|
profile.DisplayName = cfg.Matrix.ServerNotices.DisplayName
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -334,7 +332,7 @@ func getSenderDevice(
|
||||||
// We've got an existing account, return the first device of it
|
// We've got an existing account, return the first device of it
|
||||||
if len(deviceRes.Devices) > 0 {
|
if len(deviceRes.Devices) > 0 {
|
||||||
// If there were changes to the profile, create a new membership event
|
// If there were changes to the profile, create a new membership event
|
||||||
if displayNameRes.Changed || avatarRes.Changed {
|
if displayNameChanged || avatarChanged {
|
||||||
_, err = updateProfile(ctx, rsAPI, &deviceRes.Devices[0], profile, accRes.Account.UserID, cfg, time.Now())
|
_, err = updateProfile(ctx, rsAPI, &deviceRes.Devices[0], profile, accRes.Account.UserID, cfg, time.Now())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
|
@ -209,24 +209,17 @@ func queryIDServerStoreInvite(
|
||||||
body *MembershipRequest, roomID string,
|
body *MembershipRequest, roomID string,
|
||||||
) (*idServerStoreInviteResponse, error) {
|
) (*idServerStoreInviteResponse, error) {
|
||||||
// Retrieve the sender's profile to get their display name
|
// Retrieve the sender's profile to get their display name
|
||||||
localpart, serverName, err := gomatrixserverlib.SplitID('@', device.UserID)
|
_, serverName, err := gomatrixserverlib.SplitID('@', device.UserID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var profile *authtypes.Profile
|
var profile *authtypes.Profile
|
||||||
if cfg.Matrix.IsLocalServerName(serverName) {
|
if cfg.Matrix.IsLocalServerName(serverName) {
|
||||||
res := &userapi.QueryProfileResponse{}
|
profile, err = userAPI.QueryProfile(ctx, device.UserID)
|
||||||
err = userAPI.QueryProfile(ctx, &userapi.QueryProfileRequest{UserID: device.UserID}, res)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
profile = &authtypes.Profile{
|
|
||||||
Localpart: localpart,
|
|
||||||
DisplayName: res.DisplayName,
|
|
||||||
AvatarURL: res.AvatarURL,
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
profile = &authtypes.Profile{}
|
profile = &authtypes.Profile{}
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,10 +50,7 @@ func GetProfile(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var profileRes userapi.QueryProfileResponse
|
profile, err := userAPI.QueryProfile(httpReq.Context(), userID)
|
||||||
err = userAPI.QueryProfile(httpReq.Context(), &userapi.QueryProfileRequest{
|
|
||||||
UserID: userID,
|
|
||||||
}, &profileRes)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
util.GetLogger(httpReq.Context()).WithError(err).Error("userAPI.QueryProfile failed")
|
util.GetLogger(httpReq.Context()).WithError(err).Error("userAPI.QueryProfile failed")
|
||||||
return jsonerror.InternalServerError()
|
return jsonerror.InternalServerError()
|
||||||
|
@ -65,21 +62,21 @@ func GetProfile(
|
||||||
if field != "" {
|
if field != "" {
|
||||||
switch field {
|
switch field {
|
||||||
case "displayname":
|
case "displayname":
|
||||||
res = eventutil.DisplayName{
|
res = eventutil.UserProfile{
|
||||||
DisplayName: profileRes.DisplayName,
|
DisplayName: profile.DisplayName,
|
||||||
}
|
}
|
||||||
case "avatar_url":
|
case "avatar_url":
|
||||||
res = eventutil.AvatarURL{
|
res = eventutil.UserProfile{
|
||||||
AvatarURL: profileRes.AvatarURL,
|
AvatarURL: profile.AvatarURL,
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
code = http.StatusBadRequest
|
code = http.StatusBadRequest
|
||||||
res = jsonerror.InvalidArgumentValue("The request body did not contain an allowed value of argument 'field'. Allowed values are either: 'avatar_url', 'displayname'.")
|
res = jsonerror.InvalidArgumentValue("The request body did not contain an allowed value of argument 'field'. Allowed values are either: 'avatar_url', 'displayname'.")
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
res = eventutil.ProfileResponse{
|
res = eventutil.UserProfile{
|
||||||
AvatarURL: profileRes.AvatarURL,
|
AvatarURL: profile.AvatarURL,
|
||||||
DisplayName: profileRes.DisplayName,
|
DisplayName: profile.DisplayName,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,7 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
|
"github.com/matrix-org/dendrite/clientapi/auth/authtypes"
|
||||||
"github.com/matrix-org/dendrite/cmd/dendrite-demo-yggdrasil/signing"
|
"github.com/matrix-org/dendrite/cmd/dendrite-demo-yggdrasil/signing"
|
||||||
fedAPI "github.com/matrix-org/dendrite/federationapi"
|
fedAPI "github.com/matrix-org/dendrite/federationapi"
|
||||||
fedInternal "github.com/matrix-org/dendrite/federationapi/internal"
|
fedInternal "github.com/matrix-org/dendrite/federationapi/internal"
|
||||||
|
@ -43,8 +44,8 @@ type fakeUserAPI struct {
|
||||||
userAPI.FederationUserAPI
|
userAPI.FederationUserAPI
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *fakeUserAPI) QueryProfile(ctx context.Context, req *userAPI.QueryProfileRequest, res *userAPI.QueryProfileResponse) error {
|
func (u *fakeUserAPI) QueryProfile(ctx context.Context, userID string) (*authtypes.Profile, error) {
|
||||||
return nil
|
return &authtypes.Profile{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestHandleQueryProfile(t *testing.T) {
|
func TestHandleQueryProfile(t *testing.T) {
|
||||||
|
|
|
@ -256,17 +256,14 @@ func createInviteFrom3PIDInvite(
|
||||||
StateKey: &inv.MXID,
|
StateKey: &inv.MXID,
|
||||||
}
|
}
|
||||||
|
|
||||||
var res userapi.QueryProfileResponse
|
profile, err := userAPI.QueryProfile(ctx, inv.MXID)
|
||||||
err = userAPI.QueryProfile(ctx, &userapi.QueryProfileRequest{
|
|
||||||
UserID: inv.MXID,
|
|
||||||
}, &res)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
content := gomatrixserverlib.MemberContent{
|
content := gomatrixserverlib.MemberContent{
|
||||||
AvatarURL: res.AvatarURL,
|
AvatarURL: profile.AvatarURL,
|
||||||
DisplayName: res.DisplayName,
|
DisplayName: profile.DisplayName,
|
||||||
Membership: gomatrixserverlib.Invite,
|
Membership: gomatrixserverlib.Invite,
|
||||||
ThirdPartyInvite: &gomatrixserverlib.MemberThirdPartyInvite{
|
ThirdPartyInvite: &gomatrixserverlib.MemberThirdPartyInvite{
|
||||||
Signed: inv.Signed,
|
Signed: inv.Signed,
|
||||||
|
|
|
@ -15,16 +15,11 @@
|
||||||
package eventutil
|
package eventutil
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"github.com/matrix-org/dendrite/syncapi/types"
|
"github.com/matrix-org/dendrite/syncapi/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ErrProfileNoExists is returned when trying to lookup a user's profile that
|
|
||||||
// doesn't exist locally.
|
|
||||||
var ErrProfileNoExists = errors.New("no known profile for given user ID")
|
|
||||||
|
|
||||||
// AccountData represents account data sent from the client API server to the
|
// AccountData represents account data sent from the client API server to the
|
||||||
// sync API server
|
// sync API server
|
||||||
type AccountData struct {
|
type AccountData struct {
|
||||||
|
@ -56,20 +51,10 @@ type NotificationData struct {
|
||||||
UnreadNotificationCount int `json:"unread_notification_count"`
|
UnreadNotificationCount int `json:"unread_notification_count"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ProfileResponse is a struct containing all known user profile data
|
// UserProfile is a struct containing all known user profile data
|
||||||
type ProfileResponse struct {
|
type UserProfile struct {
|
||||||
AvatarURL string `json:"avatar_url"`
|
AvatarURL string `json:"avatar_url,omitempty"`
|
||||||
DisplayName string `json:"displayname"`
|
DisplayName string `json:"displayname,omitempty"`
|
||||||
}
|
|
||||||
|
|
||||||
// AvatarURL is a struct containing only the URL to a user's avatar
|
|
||||||
type AvatarURL struct {
|
|
||||||
AvatarURL string `json:"avatar_url"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// DisplayName is a struct containing only a user's display name
|
|
||||||
type DisplayName struct {
|
|
||||||
DisplayName string `json:"displayname"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// WeakBoolean is a type that will Unmarshal to true or false even if the encoded
|
// WeakBoolean is a type that will Unmarshal to true or false even if the encoded
|
||||||
|
|
|
@ -17,6 +17,7 @@ package test
|
||||||
import (
|
import (
|
||||||
"crypto/ed25519"
|
"crypto/ed25519"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strconv"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
@ -47,6 +48,7 @@ var (
|
||||||
|
|
||||||
type User struct {
|
type User struct {
|
||||||
ID string
|
ID string
|
||||||
|
Localpart string
|
||||||
AccountType api.AccountType
|
AccountType api.AccountType
|
||||||
// key ID and private key of the server who has this user, if known.
|
// key ID and private key of the server who has this user, if known.
|
||||||
keyID gomatrixserverlib.KeyID
|
keyID gomatrixserverlib.KeyID
|
||||||
|
@ -81,6 +83,7 @@ func NewUser(t *testing.T, opts ...UserOpt) *User {
|
||||||
WithSigningServer(serverName, keyID, privateKey)(&u)
|
WithSigningServer(serverName, keyID, privateKey)(&u)
|
||||||
}
|
}
|
||||||
u.ID = fmt.Sprintf("@%d:%s", counter, u.srvName)
|
u.ID = fmt.Sprintf("@%d:%s", counter, u.srvName)
|
||||||
|
u.Localpart = strconv.Itoa(int(counter))
|
||||||
t.Logf("NewUser: created user %s", u.ID)
|
t.Logf("NewUser: created user %s", u.ID)
|
||||||
return &u
|
return &u
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,7 +58,7 @@ type MediaUserAPI interface {
|
||||||
type FederationUserAPI interface {
|
type FederationUserAPI interface {
|
||||||
UploadDeviceKeysAPI
|
UploadDeviceKeysAPI
|
||||||
QueryOpenIDToken(ctx context.Context, req *QueryOpenIDTokenRequest, res *QueryOpenIDTokenResponse) error
|
QueryOpenIDToken(ctx context.Context, req *QueryOpenIDTokenRequest, res *QueryOpenIDTokenResponse) error
|
||||||
QueryProfile(ctx context.Context, req *QueryProfileRequest, res *QueryProfileResponse) error
|
QueryProfile(ctx context.Context, userID string) (*authtypes.Profile, error)
|
||||||
QueryDevices(ctx context.Context, req *QueryDevicesRequest, res *QueryDevicesResponse) error
|
QueryDevices(ctx context.Context, req *QueryDevicesRequest, res *QueryDevicesResponse) error
|
||||||
QueryKeys(ctx context.Context, req *QueryKeysRequest, res *QueryKeysResponse) error
|
QueryKeys(ctx context.Context, req *QueryKeysRequest, res *QueryKeysResponse) error
|
||||||
QuerySignatures(ctx context.Context, req *QuerySignaturesRequest, res *QuerySignaturesResponse) error
|
QuerySignatures(ctx context.Context, req *QuerySignaturesRequest, res *QuerySignaturesResponse) error
|
||||||
|
@ -83,9 +83,9 @@ type ClientUserAPI interface {
|
||||||
LoginTokenInternalAPI
|
LoginTokenInternalAPI
|
||||||
UserLoginAPI
|
UserLoginAPI
|
||||||
ClientKeyAPI
|
ClientKeyAPI
|
||||||
|
ProfileAPI
|
||||||
QueryNumericLocalpart(ctx context.Context, req *QueryNumericLocalpartRequest, res *QueryNumericLocalpartResponse) error
|
QueryNumericLocalpart(ctx context.Context, req *QueryNumericLocalpartRequest, res *QueryNumericLocalpartResponse) error
|
||||||
QueryDevices(ctx context.Context, req *QueryDevicesRequest, res *QueryDevicesResponse) error
|
QueryDevices(ctx context.Context, req *QueryDevicesRequest, res *QueryDevicesResponse) error
|
||||||
QueryProfile(ctx context.Context, req *QueryProfileRequest, res *QueryProfileResponse) error
|
|
||||||
QueryAccountData(ctx context.Context, req *QueryAccountDataRequest, res *QueryAccountDataResponse) error
|
QueryAccountData(ctx context.Context, req *QueryAccountDataRequest, res *QueryAccountDataResponse) error
|
||||||
QueryPushers(ctx context.Context, req *QueryPushersRequest, res *QueryPushersResponse) error
|
QueryPushers(ctx context.Context, req *QueryPushersRequest, res *QueryPushersResponse) error
|
||||||
QueryPushRules(ctx context.Context, req *QueryPushRulesRequest, res *QueryPushRulesResponse) error
|
QueryPushRules(ctx context.Context, req *QueryPushRulesRequest, res *QueryPushRulesResponse) error
|
||||||
|
@ -100,8 +100,6 @@ type ClientUserAPI interface {
|
||||||
PerformPushRulesPut(ctx context.Context, req *PerformPushRulesPutRequest, res *struct{}) error
|
PerformPushRulesPut(ctx context.Context, req *PerformPushRulesPutRequest, res *struct{}) error
|
||||||
PerformAccountDeactivation(ctx context.Context, req *PerformAccountDeactivationRequest, res *PerformAccountDeactivationResponse) error
|
PerformAccountDeactivation(ctx context.Context, req *PerformAccountDeactivationRequest, res *PerformAccountDeactivationResponse) error
|
||||||
PerformOpenIDTokenCreation(ctx context.Context, req *PerformOpenIDTokenCreationRequest, res *PerformOpenIDTokenCreationResponse) error
|
PerformOpenIDTokenCreation(ctx context.Context, req *PerformOpenIDTokenCreationRequest, res *PerformOpenIDTokenCreationResponse) error
|
||||||
SetAvatarURL(ctx context.Context, req *PerformSetAvatarURLRequest, res *PerformSetAvatarURLResponse) error
|
|
||||||
SetDisplayName(ctx context.Context, req *PerformUpdateDisplayNameRequest, res *PerformUpdateDisplayNameResponse) error
|
|
||||||
QueryNotifications(ctx context.Context, req *QueryNotificationsRequest, res *QueryNotificationsResponse) error
|
QueryNotifications(ctx context.Context, req *QueryNotificationsRequest, res *QueryNotificationsResponse) error
|
||||||
InputAccountData(ctx context.Context, req *InputAccountDataRequest, res *InputAccountDataResponse) error
|
InputAccountData(ctx context.Context, req *InputAccountDataRequest, res *InputAccountDataResponse) error
|
||||||
PerformKeyBackup(ctx context.Context, req *PerformKeyBackupRequest, res *PerformKeyBackupResponse) error
|
PerformKeyBackup(ctx context.Context, req *PerformKeyBackupRequest, res *PerformKeyBackupResponse) error
|
||||||
|
@ -113,6 +111,12 @@ type ClientUserAPI interface {
|
||||||
PerformSaveThreePIDAssociation(ctx context.Context, req *PerformSaveThreePIDAssociationRequest, res *struct{}) error
|
PerformSaveThreePIDAssociation(ctx context.Context, req *PerformSaveThreePIDAssociationRequest, res *struct{}) error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ProfileAPI interface {
|
||||||
|
QueryProfile(ctx context.Context, userID string) (*authtypes.Profile, error)
|
||||||
|
SetAvatarURL(ctx context.Context, localpart string, serverName gomatrixserverlib.ServerName, avatarURL string) (*authtypes.Profile, bool, error)
|
||||||
|
SetDisplayName(ctx context.Context, localpart string, serverName gomatrixserverlib.ServerName, displayName string) (*authtypes.Profile, bool, error)
|
||||||
|
}
|
||||||
|
|
||||||
// custom api functions required by pinecone / p2p demos
|
// custom api functions required by pinecone / p2p demos
|
||||||
type QuerySearchProfilesAPI interface {
|
type QuerySearchProfilesAPI interface {
|
||||||
QuerySearchProfiles(ctx context.Context, req *QuerySearchProfilesRequest, res *QuerySearchProfilesResponse) error
|
QuerySearchProfiles(ctx context.Context, req *QuerySearchProfilesRequest, res *QuerySearchProfilesResponse) error
|
||||||
|
@ -290,22 +294,6 @@ type QueryDevicesResponse struct {
|
||||||
Devices []Device
|
Devices []Device
|
||||||
}
|
}
|
||||||
|
|
||||||
// QueryProfileRequest is the request for QueryProfile
|
|
||||||
type QueryProfileRequest struct {
|
|
||||||
// The user ID to query
|
|
||||||
UserID string
|
|
||||||
}
|
|
||||||
|
|
||||||
// QueryProfileResponse is the response for QueryProfile
|
|
||||||
type QueryProfileResponse struct {
|
|
||||||
// True if the user exists. Querying for a profile does not create them.
|
|
||||||
UserExists bool
|
|
||||||
// The current display name if set.
|
|
||||||
DisplayName string
|
|
||||||
// The current avatar URL if set.
|
|
||||||
AvatarURL string
|
|
||||||
}
|
|
||||||
|
|
||||||
// QuerySearchProfilesRequest is the request for QueryProfile
|
// QuerySearchProfilesRequest is the request for QueryProfile
|
||||||
type QuerySearchProfilesRequest struct {
|
type QuerySearchProfilesRequest struct {
|
||||||
// The search string to match
|
// The search string to match
|
||||||
|
@ -600,16 +588,6 @@ type Notification struct {
|
||||||
TS gomatrixserverlib.Timestamp `json:"ts"` // Required.
|
TS gomatrixserverlib.Timestamp `json:"ts"` // Required.
|
||||||
}
|
}
|
||||||
|
|
||||||
type PerformSetAvatarURLRequest struct {
|
|
||||||
Localpart string
|
|
||||||
ServerName gomatrixserverlib.ServerName
|
|
||||||
AvatarURL string
|
|
||||||
}
|
|
||||||
type PerformSetAvatarURLResponse struct {
|
|
||||||
Profile *authtypes.Profile `json:"profile"`
|
|
||||||
Changed bool `json:"changed"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type QueryNumericLocalpartRequest struct {
|
type QueryNumericLocalpartRequest struct {
|
||||||
ServerName gomatrixserverlib.ServerName
|
ServerName gomatrixserverlib.ServerName
|
||||||
}
|
}
|
||||||
|
@ -638,17 +616,6 @@ type QueryAccountByPasswordResponse struct {
|
||||||
Exists bool
|
Exists bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type PerformUpdateDisplayNameRequest struct {
|
|
||||||
Localpart string
|
|
||||||
ServerName gomatrixserverlib.ServerName
|
|
||||||
DisplayName string
|
|
||||||
}
|
|
||||||
|
|
||||||
type PerformUpdateDisplayNameResponse struct {
|
|
||||||
Profile *authtypes.Profile `json:"profile"`
|
|
||||||
Changed bool `json:"changed"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type QueryLocalpartForThreePIDRequest struct {
|
type QueryLocalpartForThreePIDRequest struct {
|
||||||
ThreePID, Medium string
|
ThreePID, Medium string
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,8 @@ import (
|
||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
appserviceAPI "github.com/matrix-org/dendrite/appservice/api"
|
||||||
|
"github.com/matrix-org/dendrite/clientapi/auth/authtypes"
|
||||||
fedsenderapi "github.com/matrix-org/dendrite/federationapi/api"
|
fedsenderapi "github.com/matrix-org/dendrite/federationapi/api"
|
||||||
"github.com/matrix-org/gomatrixserverlib"
|
"github.com/matrix-org/gomatrixserverlib"
|
||||||
"github.com/matrix-org/util"
|
"github.com/matrix-org/util"
|
||||||
|
@ -418,25 +420,26 @@ func (a *UserInternalAPI) PerformDeviceUpdate(ctx context.Context, req *api.Perf
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *UserInternalAPI) QueryProfile(ctx context.Context, req *api.QueryProfileRequest, res *api.QueryProfileResponse) error {
|
var (
|
||||||
local, domain, err := gomatrixserverlib.SplitID('@', req.UserID)
|
ErrIsRemoteServer = errors.New("cannot query profile of remote users")
|
||||||
|
)
|
||||||
|
|
||||||
|
func (a *UserInternalAPI) QueryProfile(ctx context.Context, userID string) (*authtypes.Profile, error) {
|
||||||
|
local, domain, err := gomatrixserverlib.SplitID('@', userID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
if !a.Config.Matrix.IsLocalServerName(domain) {
|
if !a.Config.Matrix.IsLocalServerName(domain) {
|
||||||
return fmt.Errorf("cannot query profile of remote users (server name %s)", domain)
|
return nil, ErrIsRemoteServer
|
||||||
}
|
}
|
||||||
prof, err := a.DB.GetProfileByLocalpart(ctx, local, domain)
|
prof, err := a.DB.GetProfileByLocalpart(ctx, local, domain)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == sql.ErrNoRows {
|
if err == sql.ErrNoRows {
|
||||||
return nil
|
return nil, appserviceAPI.ErrProfileNotExists
|
||||||
}
|
}
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
res.UserExists = true
|
return prof, nil
|
||||||
res.AvatarURL = prof.AvatarURL
|
|
||||||
res.DisplayName = prof.DisplayName
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *UserInternalAPI) QuerySearchProfiles(ctx context.Context, req *api.QuerySearchProfilesRequest, res *api.QuerySearchProfilesResponse) error {
|
func (a *UserInternalAPI) QuerySearchProfiles(ctx context.Context, req *api.QuerySearchProfilesRequest, res *api.QuerySearchProfilesResponse) error {
|
||||||
|
@ -901,11 +904,8 @@ func (a *UserInternalAPI) QueryPushRules(ctx context.Context, req *api.QueryPush
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *UserInternalAPI) SetAvatarURL(ctx context.Context, req *api.PerformSetAvatarURLRequest, res *api.PerformSetAvatarURLResponse) error {
|
func (a *UserInternalAPI) SetAvatarURL(ctx context.Context, localpart string, serverName gomatrixserverlib.ServerName, avatarURL string) (*authtypes.Profile, bool, error) {
|
||||||
profile, changed, err := a.DB.SetAvatarURL(ctx, req.Localpart, req.ServerName, req.AvatarURL)
|
return a.DB.SetAvatarURL(ctx, localpart, serverName, avatarURL)
|
||||||
res.Profile = profile
|
|
||||||
res.Changed = changed
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *UserInternalAPI) QueryNumericLocalpart(ctx context.Context, req *api.QueryNumericLocalpartRequest, res *api.QueryNumericLocalpartResponse) error {
|
func (a *UserInternalAPI) QueryNumericLocalpart(ctx context.Context, req *api.QueryNumericLocalpartRequest, res *api.QueryNumericLocalpartResponse) error {
|
||||||
|
@ -939,11 +939,8 @@ func (a *UserInternalAPI) QueryAccountByPassword(ctx context.Context, req *api.Q
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *UserInternalAPI) SetDisplayName(ctx context.Context, req *api.PerformUpdateDisplayNameRequest, res *api.PerformUpdateDisplayNameResponse) error {
|
func (a *UserInternalAPI) SetDisplayName(ctx context.Context, localpart string, serverName gomatrixserverlib.ServerName, displayName string) (*authtypes.Profile, bool, error) {
|
||||||
profile, changed, err := a.DB.SetDisplayName(ctx, req.Localpart, req.ServerName, req.DisplayName)
|
return a.DB.SetDisplayName(ctx, localpart, serverName, displayName)
|
||||||
res.Profile = profile
|
|
||||||
res.Changed = changed
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *UserInternalAPI) QueryLocalpartForThreePID(ctx context.Context, req *api.QueryLocalpartForThreePIDRequest, res *api.QueryLocalpartForThreePIDResponse) error {
|
func (a *UserInternalAPI) QueryLocalpartForThreePID(ctx context.Context, req *api.QueryLocalpartForThreePIDRequest, res *api.QueryLocalpartForThreePIDResponse) error {
|
||||||
|
|
|
@ -22,6 +22,8 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
api2 "github.com/matrix-org/dendrite/appservice/api"
|
||||||
|
"github.com/matrix-org/dendrite/clientapi/auth/authtypes"
|
||||||
"github.com/matrix-org/dendrite/internal/sqlutil"
|
"github.com/matrix-org/dendrite/internal/sqlutil"
|
||||||
"github.com/matrix-org/dendrite/userapi/producers"
|
"github.com/matrix-org/dendrite/userapi/producers"
|
||||||
"github.com/matrix-org/gomatrixserverlib"
|
"github.com/matrix-org/gomatrixserverlib"
|
||||||
|
@ -111,33 +113,26 @@ func TestQueryProfile(t *testing.T) {
|
||||||
aliceDisplayName := "Alice"
|
aliceDisplayName := "Alice"
|
||||||
|
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
req api.QueryProfileRequest
|
userID string
|
||||||
wantRes api.QueryProfileResponse
|
wantRes *authtypes.Profile
|
||||||
wantErr error
|
wantErr error
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
req: api.QueryProfileRequest{
|
userID: fmt.Sprintf("@alice:%s", serverName),
|
||||||
UserID: fmt.Sprintf("@alice:%s", serverName),
|
wantRes: &authtypes.Profile{
|
||||||
},
|
Localpart: "alice",
|
||||||
wantRes: api.QueryProfileResponse{
|
|
||||||
UserExists: true,
|
|
||||||
AvatarURL: aliceAvatarURL,
|
|
||||||
DisplayName: aliceDisplayName,
|
DisplayName: aliceDisplayName,
|
||||||
|
AvatarURL: aliceAvatarURL,
|
||||||
|
ServerName: string(serverName),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
req: api.QueryProfileRequest{
|
userID: fmt.Sprintf("@bob:%s", serverName),
|
||||||
UserID: fmt.Sprintf("@bob:%s", serverName),
|
wantErr: api2.ErrProfileNotExists,
|
||||||
},
|
|
||||||
wantRes: api.QueryProfileResponse{
|
|
||||||
UserExists: false,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
req: api.QueryProfileRequest{
|
userID: "@alice:wrongdomain.com",
|
||||||
UserID: "@alice:wrongdomain.com",
|
wantErr: api2.ErrProfileNotExists,
|
||||||
},
|
|
||||||
wantErr: fmt.Errorf("wrong domain"),
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -147,14 +142,14 @@ func TestQueryProfile(t *testing.T) {
|
||||||
mode = "HTTP"
|
mode = "HTTP"
|
||||||
}
|
}
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
var gotRes api.QueryProfileResponse
|
|
||||||
gotErr := testAPI.QueryProfile(context.TODO(), &tc.req, &gotRes)
|
profile, gotErr := testAPI.QueryProfile(context.TODO(), tc.userID)
|
||||||
if tc.wantErr == nil && gotErr != nil || tc.wantErr != nil && gotErr == nil {
|
if tc.wantErr == nil && gotErr != nil || tc.wantErr != nil && gotErr == nil {
|
||||||
t.Errorf("QueryProfile %s error, got %s want %s", mode, gotErr, tc.wantErr)
|
t.Errorf("QueryProfile %s error, got %s want %s", mode, gotErr, tc.wantErr)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if !reflect.DeepEqual(tc.wantRes, gotRes) {
|
if !reflect.DeepEqual(tc.wantRes, profile) {
|
||||||
t.Errorf("QueryProfile %s response got %+v want %+v", mode, gotRes, tc.wantRes)
|
t.Errorf("QueryProfile %s response got %+v want %+v", mode, profile, tc.wantRes)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue