Implemented preferences endpoints for apiv4 (#5531)

* implemented preferences endpoints for apiv4

* added user id in preferences endpoints
Этот коммит содержится в:
Ruzette Tanyag
2017-02-28 04:14:16 -05:00
коммит произвёл George Goldberg
родитель 758402311a
Коммит cef5028cbe
7 изменённых файлов: 594 добавлений и 15 удалений

Просмотреть файл

@@ -130,7 +130,7 @@ func InitApi(full bool) {
BaseRoutes.OAuth = BaseRoutes.ApiRoot.PathPrefix("/oauth").Subrouter() BaseRoutes.OAuth = BaseRoutes.ApiRoot.PathPrefix("/oauth").Subrouter()
BaseRoutes.Admin = BaseRoutes.ApiRoot.PathPrefix("/admin").Subrouter() BaseRoutes.Admin = BaseRoutes.ApiRoot.PathPrefix("/admin").Subrouter()
BaseRoutes.System = BaseRoutes.ApiRoot.PathPrefix("/system").Subrouter() BaseRoutes.System = BaseRoutes.ApiRoot.PathPrefix("/system").Subrouter()
BaseRoutes.Preferences = BaseRoutes.ApiRoot.PathPrefix("/preferences").Subrouter() BaseRoutes.Preferences = BaseRoutes.User.PathPrefix("/preferences").Subrouter()
BaseRoutes.License = BaseRoutes.ApiRoot.PathPrefix("/license").Subrouter() BaseRoutes.License = BaseRoutes.ApiRoot.PathPrefix("/license").Subrouter()
BaseRoutes.Public = BaseRoutes.ApiRoot.PathPrefix("/public").Subrouter() BaseRoutes.Public = BaseRoutes.ApiRoot.PathPrefix("/public").Subrouter()
@@ -146,6 +146,7 @@ func InitApi(full bool) {
InitFile() InitFile()
InitSystem() InitSystem()
InitWebhook() InitWebhook()
InitPreference()
app.Srv.Router.Handle("/api/v4/{anything:.*}", http.HandlerFunc(Handle404)) app.Srv.Router.Handle("/api/v4/{anything:.*}", http.HandlerFunc(Handle404))

Просмотреть файл

@@ -431,3 +431,27 @@ func (c *Context) RequireEmail() *Context {
return c return c
} }
func (c *Context) RequireCategory() *Context {
if c.Err != nil {
return c
}
if !model.IsValidAlphaNum(c.Params.Category, true) {
c.SetInvalidUrlParam("category")
}
return c
}
func (c *Context) RequirePreferenceName() *Context {
if c.Err != nil {
return c
}
if !model.IsValidAlphaNum(c.Params.PreferenceName, true) {
c.SetInvalidUrlParam("preference_name")
}
return c
}

Просмотреть файл

@@ -17,20 +17,22 @@ const (
) )
type ApiParams struct { type ApiParams struct {
UserId string UserId string
TeamId string TeamId string
ChannelId string ChannelId string
PostId string PostId string
FileId string FileId string
CommandId string CommandId string
HookId string HookId string
EmojiId string EmojiId string
Email string Email string
Username string Username string
TeamName string TeamName string
ChannelName string ChannelName string
Page int PreferenceName string
PerPage int Category string
Page int
PerPage int
} }
func ApiParamsFromRequest(r *http.Request) *ApiParams { func ApiParamsFromRequest(r *http.Request) *ApiParams {
@@ -86,6 +88,14 @@ func ApiParamsFromRequest(r *http.Request) *ApiParams {
params.ChannelName = val params.ChannelName = val
} }
if val, ok := props["category"]; ok {
params.Category = val
}
if val, ok := props["preference_name"]; ok {
params.PreferenceName = val
}
if val, err := strconv.Atoi(r.URL.Query().Get("page")); err != nil { if val, err := strconv.Atoi(r.URL.Query().Get("page")); err != nil {
params.Page = PAGE_DEFAULT params.Page = PAGE_DEFAULT
} else { } else {

153
api4/preference.go Обычный файл
Просмотреть файл

@@ -0,0 +1,153 @@
// // Copyright (c) 2017 Mattermost, Inc. All Rights Reserved.
// // See License.txt for license information.
package api4
import (
"net/http"
l4g "github.com/alecthomas/log4go"
"github.com/mattermost/platform/app"
"github.com/mattermost/platform/model"
"github.com/mattermost/platform/utils"
)
func InitPreference() {
l4g.Debug(utils.T("api.preference.init.debug"))
BaseRoutes.Preferences.Handle("", ApiSessionRequired(getPreferences)).Methods("GET")
BaseRoutes.Preferences.Handle("", ApiSessionRequired(updatePreferences)).Methods("PUT")
BaseRoutes.Preferences.Handle("/delete", ApiSessionRequired(deletePreferences)).Methods("POST")
BaseRoutes.Preferences.Handle("/{category:[A-Za-z0-9_]+}", ApiSessionRequired(getPreferencesByCategory)).Methods("GET")
BaseRoutes.Preferences.Handle("/{category:[A-Za-z0-9_]+}/name/{preference_name:[A-Za-z0-9_]+}", ApiSessionRequired(getPreferenceByCategoryAndName)).Methods("GET")
}
func getPreferences(c *Context, w http.ResponseWriter, r *http.Request) {
c.RequireUserId()
if c.Err != nil {
return
}
if !app.SessionHasPermissionToUser(c.Session, c.Params.UserId) {
c.SetPermissionError(model.PERMISSION_EDIT_OTHER_USERS)
return
}
if preferences, err := app.GetPreferencesForUser(c.Params.UserId); err != nil {
c.Err = err
return
} else {
w.Write([]byte(preferences.ToJson()))
return
}
}
func getPreferencesByCategory(c *Context, w http.ResponseWriter, r *http.Request) {
c.RequireUserId().RequireCategory()
if c.Err != nil {
return
}
if !app.SessionHasPermissionToUser(c.Session, c.Params.UserId) {
c.SetPermissionError(model.PERMISSION_EDIT_OTHER_USERS)
return
}
if preferences, err := app.GetPreferenceByCategoryForUser(c.Params.UserId, c.Params.Category); err != nil {
c.Err = err
return
} else {
w.Write([]byte(preferences.ToJson()))
return
}
}
func getPreferenceByCategoryAndName(c *Context, w http.ResponseWriter, r *http.Request) {
c.RequireUserId().RequireCategory().RequirePreferenceName()
if c.Err != nil {
return
}
if !app.SessionHasPermissionToUser(c.Session, c.Params.UserId) {
c.SetPermissionError(model.PERMISSION_EDIT_OTHER_USERS)
return
}
if preferences, err := app.GetPreferenceByCategoryAndNameForUser(c.Params.UserId, c.Params.Category, c.Params.PreferenceName); err != nil {
c.Err = err
return
} else {
w.Write([]byte(preferences.ToJson()))
return
}
}
func updatePreferences(c *Context, w http.ResponseWriter, r *http.Request) {
c.RequireUserId()
if c.Err != nil {
return
}
if !app.SessionHasPermissionToUser(c.Session, c.Params.UserId) {
c.SetPermissionError(model.PERMISSION_EDIT_OTHER_USERS)
return
}
preferences, err := model.PreferencesFromJson(r.Body)
if err != nil {
c.SetInvalidParam("preferences")
return
}
for _, preference := range preferences {
if c.Params.UserId != preference.UserId {
c.Err = model.NewAppError("savePreferences", "api.preference.update_preferences.set.app_error", nil,
c.T("api.preference.update_preferences.set_details.app_error",
map[string]interface{}{"SessionUserId": c.Params.UserId, "PreferenceUserId": preference.UserId}),
http.StatusForbidden)
return
}
}
if _, err := app.UpdatePreferences(preferences); err != nil {
c.Err = err
return
}
ReturnStatusOK(w)
}
func deletePreferences(c *Context, w http.ResponseWriter, r *http.Request) {
c.RequireUserId()
if c.Err != nil {
return
}
if !app.SessionHasPermissionToUser(c.Session, c.Params.UserId) {
c.SetPermissionError(model.PERMISSION_EDIT_OTHER_USERS)
return
}
preferences, err := model.PreferencesFromJson(r.Body)
if err != nil {
c.SetInvalidParam("preferences")
return
}
for _, preference := range preferences {
if c.Params.UserId != preference.UserId {
c.Err = model.NewAppError("deletePreferences", "api.preference.delete_preferences.delete.app_error", nil,
c.T("api.preference.delete_preferences.delete.app_error",
map[string]interface{}{"SessionUserId": c.Params.UserId, "PreferenceUserId": preference.UserId}),
http.StatusForbidden)
return
}
}
if _, err := app.DeletePreferences(c.Params.UserId, preferences); err != nil {
c.Err = err
return
}
ReturnStatusOK(w)
}

287
api4/preference_test.go Обычный файл
Просмотреть файл

@@ -0,0 +1,287 @@
// Copyright (c) 2017 Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
package api4
import (
"github.com/mattermost/platform/model"
"testing"
)
func TestGetPreferences(t *testing.T) {
th := Setup().InitBasic()
defer TearDown()
Client := th.Client
th.LoginBasic()
user1 := th.BasicUser
category := model.NewId()
preferences1 := model.Preferences{
{
UserId: user1.Id,
Category: category,
Name: model.NewId(),
},
{
UserId: user1.Id,
Category: category,
Name: model.NewId(),
},
{
UserId: user1.Id,
Category: model.NewId(),
Name: model.NewId(),
},
}
Client.UpdatePreferences(user1.Id, &preferences1)
prefs, resp := Client.GetPreferences(user1.Id)
CheckNoError(t, resp)
if len(prefs) != 4 {
t.Fatal("received the wrong number of preferences")
}
for _, preference := range prefs {
if preference.UserId != th.BasicUser.Id {
t.Fatal("user id does not match")
}
}
th.LoginBasic2()
prefs, resp = Client.GetPreferences(th.BasicUser2.Id)
CheckNoError(t, resp)
if len(prefs) == 0 {
t.Fatal("received the wrong number of preferences")
}
_, resp = Client.GetPreferences(th.BasicUser.Id)
CheckForbiddenStatus(t, resp)
Client.Logout()
_, resp = Client.GetPreferences(th.BasicUser2.Id)
CheckUnauthorizedStatus(t, resp)
}
func TestGetPreferencesByCategory(t *testing.T) {
th := Setup().InitBasic()
defer TearDown()
Client := th.Client
th.LoginBasic()
user1 := th.BasicUser
category := model.NewId()
preferences1 := model.Preferences{
{
UserId: user1.Id,
Category: category,
Name: model.NewId(),
},
{
UserId: user1.Id,
Category: category,
Name: model.NewId(),
},
{
UserId: user1.Id,
Category: model.NewId(),
Name: model.NewId(),
},
}
Client.UpdatePreferences(user1.Id, &preferences1)
prefs, resp := Client.GetPreferencesByCategory(user1.Id, category)
CheckNoError(t, resp)
if len(prefs) != 2 {
t.Fatalf("received the wrong number of preferences %v:%v", len(prefs), 2)
}
prefs, resp = Client.GetPreferencesByCategory(user1.Id, "junk")
CheckNotFoundStatus(t, resp)
th.LoginBasic2()
prefs, resp = Client.GetPreferencesByCategory(th.BasicUser2.Id, category)
CheckNotFoundStatus(t, resp)
prefs, resp = Client.GetPreferencesByCategory(user1.Id, category)
CheckForbiddenStatus(t, resp)
prefs, resp = Client.GetPreferencesByCategory(th.BasicUser2.Id, "junk")
CheckNotFoundStatus(t, resp)
if len(prefs) != 0 {
t.Fatal("received the wrong number of preferences")
}
Client.Logout()
_, resp = Client.GetPreferencesByCategory(th.BasicUser2.Id, category)
CheckUnauthorizedStatus(t, resp)
}
func TestGetPreferenceByCategoryAndName(t *testing.T) {
th := Setup().InitBasic()
defer TearDown()
Client := th.Client
th.LoginBasic()
user := th.BasicUser
name := model.NewId()
value := model.NewId()
preferences := model.Preferences{
{
UserId: user.Id,
Category: model.PREFERENCE_CATEGORY_DIRECT_CHANNEL_SHOW,
Name: name,
Value: value,
},
{
UserId: user.Id,
Category: model.PREFERENCE_CATEGORY_DIRECT_CHANNEL_SHOW,
Name: model.NewId(),
Value: model.NewId(),
},
}
Client.UpdatePreferences(user.Id, &preferences)
pref, resp := Client.GetPreferenceByCategoryAndName(user.Id, model.PREFERENCE_CATEGORY_DIRECT_CHANNEL_SHOW, name)
CheckNoError(t, resp)
if (pref.UserId != preferences[0].UserId) && (pref.Category != preferences[0].Category) && (pref.Name != preferences[0].Name) {
t.Fatal("preference saved incorrectly")
}
preferences[0].Value = model.NewId()
Client.UpdatePreferences(user.Id, &preferences)
_, resp = Client.GetPreferenceByCategoryAndName(user.Id, "junk", preferences[0].Name)
CheckBadRequestStatus(t, resp)
_, resp = Client.GetPreferenceByCategoryAndName(user.Id, preferences[0].Category, "junk")
CheckBadRequestStatus(t, resp)
_, resp = Client.GetPreferenceByCategoryAndName(th.BasicUser2.Id, preferences[0].Category, "junk")
CheckForbiddenStatus(t, resp)
_, resp = Client.GetPreferenceByCategoryAndName(user.Id, preferences[0].Category, preferences[0].Name)
CheckNoError(t, resp)
Client.Logout()
_, resp = Client.GetPreferenceByCategoryAndName(user.Id, preferences[0].Category, preferences[0].Name)
CheckUnauthorizedStatus(t, resp)
}
func TestUpdatePreferences(t *testing.T) {
th := Setup().InitBasic()
defer TearDown()
Client := th.Client
th.LoginBasic()
user1 := th.BasicUser
category := model.NewId()
preferences1 := model.Preferences{
{
UserId: user1.Id,
Category: category,
Name: model.NewId(),
},
{
UserId: user1.Id,
Category: category,
Name: model.NewId(),
},
{
UserId: user1.Id,
Category: model.NewId(),
Name: model.NewId(),
},
}
_, resp := Client.UpdatePreferences(user1.Id, &preferences1)
CheckNoError(t, resp)
preferences := model.Preferences{
{
UserId: model.NewId(),
Category: category,
Name: model.NewId(),
},
}
_, resp = Client.UpdatePreferences(user1.Id, &preferences)
CheckForbiddenStatus(t, resp)
preferences = model.Preferences{
{
UserId: user1.Id,
Name: model.NewId(),
},
}
_, resp = Client.UpdatePreferences(user1.Id, &preferences)
CheckBadRequestStatus(t, resp)
_, resp = Client.UpdatePreferences(th.BasicUser2.Id, &preferences)
CheckForbiddenStatus(t, resp)
Client.Logout()
_, resp = Client.UpdatePreferences(user1.Id, &preferences1)
CheckUnauthorizedStatus(t, resp)
}
func TestDeletePreferences(t *testing.T) {
th := Setup().InitBasic()
defer TearDown()
Client := th.Client
th.LoginBasic()
prefs, resp := Client.GetPreferences(th.BasicUser.Id)
originalCount := len(prefs)
// save 10 preferences
var preferences model.Preferences
for i := 0; i < 10; i++ {
preference := model.Preference{
UserId: th.BasicUser.Id,
Category: model.PREFERENCE_CATEGORY_DIRECT_CHANNEL_SHOW,
Name: model.NewId(),
}
preferences = append(preferences, preference)
}
Client.UpdatePreferences(th.BasicUser.Id, &preferences)
// delete 10 preferences
th.LoginBasic2()
_, resp = Client.DeletePreferences(th.BasicUser2.Id, &preferences)
CheckForbiddenStatus(t, resp)
th.LoginBasic()
_, resp = Client.DeletePreferences(th.BasicUser.Id, &preferences)
CheckNoError(t, resp)
_, resp = Client.DeletePreferences(th.BasicUser2.Id, &preferences)
CheckForbiddenStatus(t, resp)
prefs, resp = Client.GetPreferences(th.BasicUser.Id)
if len(prefs) != originalCount {
t.Fatal("should've deleted preferences")
}
Client.Logout()
_, resp = Client.DeletePreferences(th.BasicUser.Id, &preferences)
CheckUnauthorizedStatus(t, resp)
}

Просмотреть файл

@@ -5,12 +5,56 @@ package app
import ( import (
"github.com/mattermost/platform/model" "github.com/mattermost/platform/model"
"net/http"
) )
func GetPreferencesForUser(userId string) (model.Preferences, *model.AppError) { func GetPreferencesForUser(userId string) (model.Preferences, *model.AppError) {
if result := <-Srv.Store.Preference().GetAll(userId); result.Err != nil { if result := <-Srv.Store.Preference().GetAll(userId); result.Err != nil {
result.Err.StatusCode = http.StatusBadRequest
return nil, result.Err return nil, result.Err
} else { } else {
return result.Data.(model.Preferences), nil return result.Data.(model.Preferences), nil
} }
} }
func GetPreferenceByCategoryForUser(userId string, category string) (model.Preferences, *model.AppError) {
if result := <-Srv.Store.Preference().GetCategory(userId, category); result.Err != nil {
result.Err.StatusCode = http.StatusBadRequest
return nil, result.Err
} else if len(result.Data.(model.Preferences)) == 0 {
err := model.NewAppError("getPreferenceCategory", "api.preference.preferences_category.get.app_error", nil, "", http.StatusNotFound)
return nil, err
} else {
return result.Data.(model.Preferences), nil
}
}
func GetPreferenceByCategoryAndNameForUser(userId string, category string, preferenceName string) (*model.Preference, *model.AppError) {
if result := <-Srv.Store.Preference().Get(userId, category, preferenceName); result.Err != nil {
result.Err.StatusCode = http.StatusBadRequest
return nil, result.Err
} else {
data := result.Data.(model.Preference)
return &data, nil
}
}
func UpdatePreferences(preferences model.Preferences) (bool, *model.AppError) {
if result := <-Srv.Store.Preference().Save(&preferences); result.Err != nil {
result.Err.StatusCode = http.StatusBadRequest
return false, result.Err
}
return true, nil
}
func DeletePreferences(userId string, preferences model.Preferences) (bool, *model.AppError) {
for _, preference := range preferences {
if result := <-Srv.Store.Preference().Delete(userId, preference.Category, preference.Name); result.Err != nil {
result.Err.StatusCode = http.StatusBadRequest
return false, result.Err
}
}
return true, nil
}

Просмотреть файл

@@ -141,6 +141,10 @@ func (c *Client4) GetIncomingWebhooksRoute() string {
return fmt.Sprintf("/hooks/incoming") return fmt.Sprintf("/hooks/incoming")
} }
func (c *Client4) GetPreferencesRoute(userId string) string {
return fmt.Sprintf(c.GetUserRoute(userId) + "/preferences")
}
func (c *Client4) DoApiGet(url string, etag string) (*http.Response, *AppError) { func (c *Client4) DoApiGet(url string, etag string) (*http.Response, *AppError) {
return c.DoApiRequest(http.MethodGet, url, "", etag) return c.DoApiRequest(http.MethodGet, url, "", etag)
} }
@@ -871,3 +875,59 @@ func (c *Client4) GetIncomingWebhooksForTeam(teamId string, page int, perPage in
return IncomingWebhookListFromJson(r.Body), BuildResponse(r) return IncomingWebhookListFromJson(r.Body), BuildResponse(r)
} }
} }
// Preferences Section
// GetPreferences returns the user's preferences
func (c *Client4) GetPreferences(userId string) (Preferences, *Response) {
if r, err := c.DoApiGet(c.GetPreferencesRoute(userId), ""); err != nil {
return nil, &Response{StatusCode: r.StatusCode, Error: err}
} else {
preferences, _ := PreferencesFromJson(r.Body)
defer closeBody(r)
return preferences, BuildResponse(r)
}
}
// UpdatePreferences saves the user's preferences
func (c *Client4) UpdatePreferences(userId string, preferences *Preferences) (bool, *Response) {
if r, err := c.DoApiPut(c.GetPreferencesRoute(userId), preferences.ToJson()); err != nil {
return false, &Response{StatusCode: r.StatusCode, Error: err}
} else {
defer closeBody(r)
return true, BuildResponse(r)
}
}
// DeletePreferences deletes the user's preferences
func (c *Client4) DeletePreferences(userId string, preferences *Preferences) (bool, *Response) {
if r, err := c.DoApiPost(c.GetPreferencesRoute(userId)+"/delete", preferences.ToJson()); err != nil {
return false, &Response{StatusCode: r.StatusCode, Error: err}
} else {
defer closeBody(r)
return true, BuildResponse(r)
}
}
// GetPreferencesByCategory returns the user's preferences from the provided category string
func (c *Client4) GetPreferencesByCategory(userId string, category string) (Preferences, *Response) {
url := fmt.Sprintf(c.GetPreferencesRoute(userId)+"/%s", category)
if r, err := c.DoApiGet(url, ""); err != nil {
return nil, &Response{StatusCode: r.StatusCode, Error: err}
} else {
preferences, _ := PreferencesFromJson(r.Body)
defer closeBody(r)
return preferences, BuildResponse(r)
}
}
// GetPreferenceByCategoryAndName returns the user's preferences from the provided category and preference name string
func (c *Client4) GetPreferenceByCategoryAndName(userId string, category string, preferenceName string) (*Preference, *Response) {
url := fmt.Sprintf(c.GetPreferencesRoute(userId)+"/%s/name/%v", category, preferenceName)
if r, err := c.DoApiGet(url, ""); err != nil {
return nil, &Response{StatusCode: r.StatusCode, Error: err}
} else {
defer closeBody(r)
return PreferenceFromJson(r.Body), BuildResponse(r)
}
}