profile.go 7.6 KB
Newer Older
B
Brendan Abolivier 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
// Copyright 2017 Vector Creations Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package readers

import (
	"net/http"

20
	"github.com/matrix-org/dendrite/clientapi/auth/authtypes"
B
Brendan Abolivier 已提交
21
	"github.com/matrix-org/dendrite/clientapi/auth/storage/accounts"
22
	"github.com/matrix-org/dendrite/clientapi/events"
B
Brendan Abolivier 已提交
23 24
	"github.com/matrix-org/dendrite/clientapi/httputil"
	"github.com/matrix-org/dendrite/clientapi/jsonerror"
B
Brendan Abolivier 已提交
25
	"github.com/matrix-org/dendrite/clientapi/producers"
26 27 28
	"github.com/matrix-org/dendrite/common/config"
	"github.com/matrix-org/dendrite/roomserver/api"
	"github.com/matrix-org/gomatrixserverlib"
B
Brendan Abolivier 已提交
29

B
Brendan Abolivier 已提交
30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
	"github.com/matrix-org/util"
)

type profileResponse struct {
	AvatarURL   string `json:"avatar_url"`
	DisplayName string `json:"displayname"`
}

type avatarURL struct {
	AvatarURL string `json:"avatar_url"`
}

type displayName struct {
	DisplayName string `json:"displayname"`
}

// GetProfile implements GET /profile/{userID}
func GetProfile(
	req *http.Request, accountDB *accounts.Database, userID string,
) util.JSONResponse {
	if req.Method != "GET" {
		return util.JSONResponse{
			Code: 405,
			JSON: jsonerror.NotFound("Bad method"),
		}
	}
56 57 58 59 60
	localpart, _, err := gomatrixserverlib.SplitID('@', userID)
	if err != nil {
		return httputil.LogThenError(req, err)
	}

B
Brendan Abolivier 已提交
61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
	profile, err := accountDB.GetProfileByLocalpart(localpart)
	if err != nil {
		return httputil.LogThenError(req, err)
	}
	res := profileResponse{
		AvatarURL:   profile.AvatarURL,
		DisplayName: profile.DisplayName,
	}
	return util.JSONResponse{
		Code: 200,
		JSON: res,
	}
}

// GetAvatarURL implements GET /profile/{userID}/avatar_url
func GetAvatarURL(
	req *http.Request, accountDB *accounts.Database, userID string,
) util.JSONResponse {
79 80 81 82 83
	localpart, _, err := gomatrixserverlib.SplitID('@', userID)
	if err != nil {
		return httputil.LogThenError(req, err)
	}

B
Brendan Abolivier 已提交
84 85 86 87 88 89 90 91 92 93 94 95 96 97 98
	profile, err := accountDB.GetProfileByLocalpart(localpart)
	if err != nil {
		return httputil.LogThenError(req, err)
	}
	res := avatarURL{
		AvatarURL: profile.AvatarURL,
	}
	return util.JSONResponse{
		Code: 200,
		JSON: res,
	}
}

// SetAvatarURL implements PUT /profile/{userID}/avatar_url
func SetAvatarURL(
99 100 101
	req *http.Request, accountDB *accounts.Database, device *authtypes.Device,
	userID string, producer *producers.UserUpdateProducer, cfg *config.Dendrite,
	rsProducer *producers.RoomserverProducer, queryAPI api.RoomserverQueryAPI,
B
Brendan Abolivier 已提交
102
) util.JSONResponse {
103 104 105 106 107 108 109 110 111
	if userID != device.UserID {
		return util.JSONResponse{
			Code: 403,
			JSON: jsonerror.Forbidden("userID does not match the current user"),
		}
	}

	changedKey := "avatar_url"

B
Brendan Abolivier 已提交
112 113 114 115 116 117 118 119 120 121 122
	var r avatarURL
	if resErr := httputil.UnmarshalJSONRequest(req, &r); resErr != nil {
		return *resErr
	}
	if r.AvatarURL == "" {
		return util.JSONResponse{
			Code: 400,
			JSON: jsonerror.BadJSON("'avatar_url' must be supplied."),
		}
	}

123 124 125 126
	localpart, _, err := gomatrixserverlib.SplitID('@', userID)
	if err != nil {
		return httputil.LogThenError(req, err)
	}
B
Brendan Abolivier 已提交
127 128 129 130 131 132

	oldProfile, err := accountDB.GetProfileByLocalpart(localpart)
	if err != nil {
		return httputil.LogThenError(req, err)
	}

133
	if err = accountDB.SetAvatarURL(localpart, r.AvatarURL); err != nil {
B
Brendan Abolivier 已提交
134 135
		return httputil.LogThenError(req, err)
	}
B
Brendan Abolivier 已提交
136

137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157
	memberships, err := accountDB.GetMembershipsByLocalpart(localpart)
	if err != nil {
		return httputil.LogThenError(req, err)
	}

	newProfile := authtypes.Profile{
		Localpart:   localpart,
		DisplayName: oldProfile.DisplayName,
		AvatarURL:   r.AvatarURL,
	}

	events, err := buildMembershipEvents(memberships, accountDB, newProfile, userID, cfg, queryAPI)
	if err != nil {
		return httputil.LogThenError(req, err)
	}

	if err := rsProducer.SendEvents(events, cfg.Matrix.ServerName); err != nil {
		return httputil.LogThenError(req, err)
	}

	if err := producer.SendUpdate(userID, changedKey, oldProfile.AvatarURL, r.AvatarURL); err != nil {
B
Brendan Abolivier 已提交
158 159 160
		return httputil.LogThenError(req, err)
	}

B
Brendan Abolivier 已提交
161 162 163 164 165 166 167 168 169 170
	return util.JSONResponse{
		Code: 200,
		JSON: struct{}{},
	}
}

// GetDisplayName implements GET /profile/{userID}/displayname
func GetDisplayName(
	req *http.Request, accountDB *accounts.Database, userID string,
) util.JSONResponse {
171 172 173 174 175
	localpart, _, err := gomatrixserverlib.SplitID('@', userID)
	if err != nil {
		return httputil.LogThenError(req, err)
	}

B
Brendan Abolivier 已提交
176 177 178 179 180 181 182 183 184 185 186 187 188 189 190
	profile, err := accountDB.GetProfileByLocalpart(localpart)
	if err != nil {
		return httputil.LogThenError(req, err)
	}
	res := displayName{
		DisplayName: profile.DisplayName,
	}
	return util.JSONResponse{
		Code: 200,
		JSON: res,
	}
}

// SetDisplayName implements PUT /profile/{userID}/displayname
func SetDisplayName(
191 192 193
	req *http.Request, accountDB *accounts.Database, device *authtypes.Device,
	userID string, producer *producers.UserUpdateProducer, cfg *config.Dendrite,
	rsProducer *producers.RoomserverProducer, queryAPI api.RoomserverQueryAPI,
B
Brendan Abolivier 已提交
194
) util.JSONResponse {
195 196 197 198 199 200 201 202 203
	if userID != device.UserID {
		return util.JSONResponse{
			Code: 403,
			JSON: jsonerror.Forbidden("userID does not match the current user"),
		}
	}

	changedKey := "displayname"

B
Brendan Abolivier 已提交
204 205 206 207 208 209 210 211 212 213 214
	var r displayName
	if resErr := httputil.UnmarshalJSONRequest(req, &r); resErr != nil {
		return *resErr
	}
	if r.DisplayName == "" {
		return util.JSONResponse{
			Code: 400,
			JSON: jsonerror.BadJSON("'displayname' must be supplied."),
		}
	}

215 216 217 218
	localpart, _, err := gomatrixserverlib.SplitID('@', userID)
	if err != nil {
		return httputil.LogThenError(req, err)
	}
B
Brendan Abolivier 已提交
219 220 221 222 223 224

	oldProfile, err := accountDB.GetProfileByLocalpart(localpart)
	if err != nil {
		return httputil.LogThenError(req, err)
	}

225
	if err = accountDB.SetDisplayName(localpart, r.DisplayName); err != nil {
B
Brendan Abolivier 已提交
226 227
		return httputil.LogThenError(req, err)
	}
B
Brendan Abolivier 已提交
228

229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249
	memberships, err := accountDB.GetMembershipsByLocalpart(localpart)
	if err != nil {
		return httputil.LogThenError(req, err)
	}

	newProfile := authtypes.Profile{
		Localpart:   localpart,
		DisplayName: r.DisplayName,
		AvatarURL:   oldProfile.AvatarURL,
	}

	events, err := buildMembershipEvents(memberships, accountDB, newProfile, userID, cfg, queryAPI)
	if err != nil {
		return httputil.LogThenError(req, err)
	}

	if err := rsProducer.SendEvents(events, cfg.Matrix.ServerName); err != nil {
		return httputil.LogThenError(req, err)
	}

	if err := producer.SendUpdate(userID, changedKey, oldProfile.DisplayName, r.DisplayName); err != nil {
B
Brendan Abolivier 已提交
250 251 252
		return httputil.LogThenError(req, err)
	}

B
Brendan Abolivier 已提交
253 254 255 256 257 258
	return util.JSONResponse{
		Code: 200,
		JSON: struct{}{},
	}
}

259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284
func buildMembershipEvents(
	memberships []authtypes.Membership, db *accounts.Database,
	newProfile authtypes.Profile, userID string, cfg *config.Dendrite,
	queryAPI api.RoomserverQueryAPI,
) ([]gomatrixserverlib.Event, error) {
	evs := []gomatrixserverlib.Event{}

	for _, membership := range memberships {
		builder := gomatrixserverlib.EventBuilder{
			Sender:   userID,
			RoomID:   membership.RoomID,
			Type:     "m.room.member",
			StateKey: &userID,
		}

		content := events.MemberContent{
			Membership: "join",
		}

		content.DisplayName = newProfile.DisplayName
		content.AvatarURL = newProfile.AvatarURL

		if err := builder.SetContent(content); err != nil {
			return nil, err
		}

285
		event, err := events.BuildEvent(&builder, *cfg, queryAPI, nil)
286 287 288 289
		if err != nil {
			return nil, err
		}

290
		evs = append(evs, *event)
B
Brendan Abolivier 已提交
291 292
	}

293
	return evs, nil
B
Brendan Abolivier 已提交
294
}