Profile retrieval

This commit is contained in:
Brendan Abolivier 2017-07-06 16:18:34 +01:00
parent b13cbb18fb
commit 490d14ebe7
No known key found for this signature in database
GPG key ID: 8EF1500759F70623
6 changed files with 189 additions and 12 deletions

View file

@ -23,6 +23,7 @@ type Account struct {
UserID string
Localpart string
ServerName gomatrixserverlib.ServerName
Profile *Profile
// TODO: Other flags like IsAdmin, IsGuest
// TODO: Devices
// TODO: Associations (e.g. with application services)

View file

@ -0,0 +1,22 @@
// 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 authtypes
// Profile represents the profile for a Matrix account on this home server.
type Profile struct {
Localpart string
DisplayName string
AvatarURL string
}

View file

@ -0,0 +1,81 @@
// 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 accounts
import (
"database/sql"
"github.com/matrix-org/dendrite/clientapi/auth/authtypes"
)
const profilesSchema = `
-- Stores data about accounts profiles.
CREATE TABLE IF NOT EXISTS profiles (
-- The Matrix user ID localpart for this account
localpart TEXT NOT NULL PRIMARY KEY,
-- The display name for this account
display_name TEXT,
-- The URL of the avatar for this account
avatar_url TEXT
);
`
const insertProfileSQL = "" +
"INSERT INTO profiles(localpart, display_name, avatar_url) VALUES ($1, $2, $3)"
const selectProfileByLocalpartSQL = "" +
"SELECT localpart, display_name, avatar_url FROM profiles WHERE localpart = $1"
const setAvatarURLSQL = "" +
"UPDATE profiles SET avatar_url = $1 WHERE localpart = $2"
type profilesStatements struct {
insertProfileStmt *sql.Stmt
selectProfileByLocalpartStmt *sql.Stmt
setAvatarURLStmt *sql.Stmt
}
func (s *profilesStatements) prepare(db *sql.DB) (err error) {
_, err = db.Exec(profilesSchema)
if err != nil {
return
}
if s.insertProfileStmt, err = db.Prepare(insertProfileSQL); err != nil {
return
}
if s.selectProfileByLocalpartStmt, err = db.Prepare(selectProfileByLocalpartSQL); err != nil {
return
}
if s.setAvatarURLStmt, err = db.Prepare(setAvatarURLSQL); err != nil {
return
}
return
}
func (s *profilesStatements) insertProfile(localpart string) (err error) {
_, err = s.insertProfileStmt.Exec(localpart, "", "")
return
}
func (s *profilesStatements) selectProfileByLocalpart(localpart string) (*authtypes.Profile, error) {
var profile authtypes.Profile
err := s.selectProfileByLocalpartStmt.QueryRow(localpart).Scan(&profile.Localpart, &profile.DisplayName, &profile.AvatarURL)
return &profile, err
}
func (s *profilesStatements) setAvatarURL(localpart string, avatarURL string) (err error) {
_, err = s.setAvatarURLStmt.Exec(avatarURL, localpart)
return
}

View file

@ -28,6 +28,7 @@ import (
type Database struct {
db *sql.DB
accounts accountsStatements
profiles profilesStatements
}
// NewDatabase creates a new accounts database
@ -41,7 +42,11 @@ func NewDatabase(dataSourceName string, serverName gomatrixserverlib.ServerName)
if err = a.prepare(db, serverName); err != nil {
return nil, err
}
return &Database{db, a}, nil
p := profilesStatements{}
if err = p.prepare(db); err != nil {
return nil, err
}
return &Database{db, a, p}, nil
}
// GetAccountByPassword returns the account associated with the given localpart and password.
@ -57,6 +62,10 @@ func (d *Database) GetAccountByPassword(localpart, plaintextPassword string) (*a
return d.accounts.selectAccountByLocalpart(localpart)
}
func (d *Database) GetProfileByLocalpart(localpart string) (*authtypes.Profile, error) {
return d.profiles.selectProfileByLocalpart(localpart)
}
// CreateAccount makes a new account with the given login name and password. If no password is supplied,
// the account will be a passwordless account.
func (d *Database) CreateAccount(localpart, plaintextPassword string) (*authtypes.Account, error) {
@ -64,6 +73,9 @@ func (d *Database) CreateAccount(localpart, plaintextPassword string) (*authtype
if err != nil {
return nil, err
}
if err := d.profiles.insertProfile(localpart); err != nil {
return nil, err
}
return d.accounts.insertAccount(localpart, hash)
}

View file

@ -0,0 +1,70 @@
// 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 (
"fmt"
"net/http"
"strings"
"github.com/matrix-org/dendrite/clientapi/auth/storage/accounts"
// "github.com/matrix-org/dendrite/clientapi/httputil"
"github.com/matrix-org/dendrite/clientapi/jsonerror"
// "github.com/matrix-org/gomatrixserverlib"
"github.com/matrix-org/util"
)
type profileResponse struct {
AvatarURL string `json:"avatar_url"`
DisplayName string `json:"displayname"`
}
func Profile(
req *http.Request, accountDB *accounts.Database, userID string,
) util.JSONResponse {
if req.Method == "GET" {
localpart := getLocalPart(userID)
profile, err := accountDB.GetProfileByLocalpart(localpart)
if err == nil {
res := profileResponse{
AvatarURL: profile.AvatarURL,
DisplayName: profile.DisplayName,
}
return util.JSONResponse{
Code: 200,
JSON: res,
}
}
return util.JSONResponse{
Code: 500,
JSON: jsonerror.Unknown("Failed to load user profile"),
}
}
return util.JSONResponse{
Code: 405,
JSON: jsonerror.NotFound("Bad method"),
}
}
func getLocalPart(userID string) string {
if !strings.HasPrefix(userID, "@") {
panic(fmt.Errorf("Invalid user ID"))
}
// Get the part before ":"
username := strings.Split(userID, ":")[0]
// Return the part after the "@"
return strings.Split(username, "@")[1]
}

View file

@ -164,10 +164,8 @@ func Setup(
r0mux.Handle("/profile/{userID}",
common.MakeAPI("profile", func(req *http.Request) util.JSONResponse {
// TODO: Get profile data for user ID
return util.JSONResponse{
Code: 200,
JSON: struct{}{},
}
vars := mux.Vars(req)
return readers.Profile(req, accountDB, vars["userID"])
}),
)
@ -237,13 +235,6 @@ func Setup(
}),
)
r0mux.Handle("/profile/{userID}/displayname",
common.MakeAPI("profile_displayname", func(req *http.Request) util.JSONResponse {
// TODO: Set and get the displayname
return util.JSONResponse{Code: 200, JSON: struct{}{}}
}),
)
r0mux.Handle("/user/{userID}/account_data/{type}",
common.MakeAPI("user_account_data", func(req *http.Request) util.JSONResponse {
// TODO: Set and get the account_data