summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile2
-rw-r--r--api/admin.go422
-rw-r--r--api/admin_test.go624
-rw-r--r--api/api.go131
-rw-r--r--api/api_test.go52
-rw-r--r--api/apitestlib.go508
-rw-r--r--api/channel.go843
-rw-r--r--api/channel_test.go2007
-rw-r--r--api/command.go286
-rw-r--r--api/command_echo_test.go36
-rw-r--r--api/command_expand_collapse_test.go51
-rw-r--r--api/command_groupmsg_test.go58
-rw-r--r--api/command_help_test.go37
-rw-r--r--api/command_invite_people_test.go33
-rw-r--r--api/command_join_test.go61
-rw-r--r--api/command_leave_test.go68
-rw-r--r--api/command_loadtest_test.go97
-rw-r--r--api/command_logout_test.go15
-rw-r--r--api/command_me_test.go38
-rw-r--r--api/command_msg_test.go47
-rw-r--r--api/command_open_test.go12
-rw-r--r--api/command_search_test.go15
-rw-r--r--api/command_settings_test.go15
-rw-r--r--api/command_shortcuts_test.go15
-rw-r--r--api/command_shrug_test.go38
-rw-r--r--api/command_statuses_test.go42
-rw-r--r--api/command_test.go310
-rw-r--r--api/context.go451
-rw-r--r--api/context_test.go29
-rw-r--r--api/deprecated_test.go4
-rw-r--r--api/emoji.go228
-rw-r--r--api/emoji_test.go437
-rw-r--r--api/file.go333
-rw-r--r--api/file_test.go950
-rw-r--r--api/general.go73
-rw-r--r--api/general_test.go63
-rw-r--r--api/license.go100
-rw-r--r--api/license_test.go51
-rw-r--r--api/oauth.go264
-rw-r--r--api/oauth_test.go895
-rw-r--r--api/post.go560
-rw-r--r--api/post_test.go1510
-rw-r--r--api/preference.go85
-rw-r--r--api/preference_test.go220
-rw-r--r--api/reaction.go149
-rw-r--r--api/reaction_test.go317
-rw-r--r--api/status.go37
-rw-r--r--api/status_test.go234
-rw-r--r--api/team.go543
-rw-r--r--api/team_test.go1196
-rw-r--r--api/user.go1245
-rw-r--r--api/user_test.go2737
-rw-r--r--api/webhook.go328
-rw-r--r--api/webhook_test.go968
-rw-r--r--api/webrtc.go23
-rw-r--r--api/websocket.go40
-rw-r--r--api/websocket_test.go381
-rw-r--r--api4/api.go7
-rw-r--r--api4/apitestlib.go2
-rw-r--r--api4/commands_test.go449
-rw-r--r--api4/oauth_test.go413
-rw-r--r--api4/websocket_test.go387
-rw-r--r--app/auto_channels.go16
-rw-r--r--app/auto_environment.go7
-rw-r--r--app/auto_posts.go10
-rw-r--r--app/auto_teams.go7
-rw-r--r--app/auto_users.go34
-rw-r--r--app/command_loadtest.go12
-rw-r--r--app/diagnostics.go5
-rw-r--r--app/file.go5
-rw-r--r--app/file_test.go61
-rw-r--r--cmd/commands/channel_test.go29
-rw-r--r--cmd/commands/roles_test.go4
-rw-r--r--cmd/commands/sampledata_test.go4
-rw-r--r--cmd/commands/server.go6
-rw-r--r--cmd/commands/team_test.go18
-rw-r--r--cmd/commands/test.go7
-rw-r--r--cmd/commands/user_test.go18
-rw-r--r--manualtesting/manual_testing.go34
-rw-r--r--manualtesting/test_autolink.go4
-rw-r--r--model/client.go2379
-rw-r--r--model/client4.go72
-rw-r--r--model/config.go5
-rw-r--r--model/websocket_client.go31
-rw-r--r--utils/config.go1
-rw-r--r--web/web_test.go5
-rw-r--r--web/webhook_test.go85
87 files changed, 1539 insertions, 22892 deletions
diff --git a/Makefile b/Makefile
index b21f3d785..2c8ccf926 100644
--- a/Makefile
+++ b/Makefile
@@ -496,8 +496,6 @@ clean: stop-docker ## Clean up everything except persistant server data.
rm -f mattermost.log
rm -f mattermost.log.jsonl
rm -f npm-debug.log
- rm -f api/mattermost.log
- rm -f api/mattermost.log.jsonl
rm -f .prepare-go
rm -f enterprise
rm -f cover.out
diff --git a/api/admin.go b/api/admin.go
deleted file mode 100644
index 6016e48f3..000000000
--- a/api/admin.go
+++ /dev/null
@@ -1,422 +0,0 @@
-// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-package api
-
-import (
- "net/http"
- "strconv"
-
- "github.com/avct/uasurfer"
- "github.com/gorilla/mux"
- "github.com/mattermost/mattermost-server/app"
- "github.com/mattermost/mattermost-server/model"
-)
-
-func (api *API) InitAdmin() {
- api.BaseRoutes.Admin.Handle("/logs", api.ApiAdminSystemRequired(getLogs)).Methods("GET")
- api.BaseRoutes.Admin.Handle("/audits", api.ApiAdminSystemRequired(getAllAudits)).Methods("GET")
- api.BaseRoutes.Admin.Handle("/config", api.ApiAdminSystemRequired(getConfig)).Methods("GET")
- api.BaseRoutes.Admin.Handle("/save_config", api.ApiAdminSystemRequired(saveConfig)).Methods("POST")
- api.BaseRoutes.Admin.Handle("/reload_config", api.ApiAdminSystemRequired(reloadConfig)).Methods("GET")
- api.BaseRoutes.Admin.Handle("/invalidate_all_caches", api.ApiAdminSystemRequired(invalidateAllCaches)).Methods("GET")
- api.BaseRoutes.Admin.Handle("/test_email", api.ApiAdminSystemRequired(testEmail)).Methods("POST")
- api.BaseRoutes.Admin.Handle("/recycle_db_conn", api.ApiAdminSystemRequired(recycleDatabaseConnection)).Methods("GET")
- api.BaseRoutes.Admin.Handle("/analytics/{id:[A-Za-z0-9]+}/{name:[A-Za-z0-9_]+}", api.ApiAdminSystemRequired(getAnalytics)).Methods("GET")
- api.BaseRoutes.Admin.Handle("/analytics/{name:[A-Za-z0-9_]+}", api.ApiAdminSystemRequired(getAnalytics)).Methods("GET")
- api.BaseRoutes.Admin.Handle("/save_compliance_report", api.ApiAdminSystemRequired(saveComplianceReport)).Methods("POST")
- api.BaseRoutes.Admin.Handle("/compliance_reports", api.ApiAdminSystemRequired(getComplianceReports)).Methods("GET")
- api.BaseRoutes.Admin.Handle("/download_compliance_report/{id:[A-Za-z0-9]+}", api.ApiAdminSystemRequiredTrustRequester(downloadComplianceReport)).Methods("GET")
- api.BaseRoutes.Admin.Handle("/upload_brand_image", api.ApiAdminSystemRequired(uploadBrandImage)).Methods("POST")
- api.BaseRoutes.Admin.Handle("/get_brand_image", api.ApiAppHandlerTrustRequester(getBrandImage)).Methods("GET")
- api.BaseRoutes.Admin.Handle("/reset_mfa", api.ApiAdminSystemRequired(adminResetMfa)).Methods("POST")
- api.BaseRoutes.Admin.Handle("/reset_password", api.ApiAdminSystemRequired(adminResetPassword)).Methods("POST")
- api.BaseRoutes.Admin.Handle("/ldap_sync_now", api.ApiAdminSystemRequired(ldapSyncNow)).Methods("POST")
- api.BaseRoutes.Admin.Handle("/ldap_test", api.ApiAdminSystemRequired(ldapTest)).Methods("POST")
- api.BaseRoutes.Admin.Handle("/saml_metadata", api.ApiAppHandler(samlMetadata)).Methods("GET")
- api.BaseRoutes.Admin.Handle("/add_certificate", api.ApiAdminSystemRequired(addCertificate)).Methods("POST")
- api.BaseRoutes.Admin.Handle("/remove_certificate", api.ApiAdminSystemRequired(removeCertificate)).Methods("POST")
- api.BaseRoutes.Admin.Handle("/saml_cert_status", api.ApiAdminSystemRequired(samlCertificateStatus)).Methods("GET")
- api.BaseRoutes.Admin.Handle("/cluster_status", api.ApiAdminSystemRequired(getClusterStatus)).Methods("GET")
- api.BaseRoutes.Admin.Handle("/recently_active_users/{team_id:[A-Za-z0-9]+}", api.ApiUserRequired(getRecentlyActiveUsers)).Methods("GET")
-}
-
-func getLogs(c *Context, w http.ResponseWriter, r *http.Request) {
- lines, err := c.App.GetLogs(0, 10000)
- if err != nil {
- c.Err = err
- return
- }
-
- w.Write([]byte(model.ArrayToJson(lines)))
-}
-
-func getClusterStatus(c *Context, w http.ResponseWriter, r *http.Request) {
- infos := c.App.GetClusterStatus()
-
- if c.App.Cluster != nil {
- w.Header().Set(model.HEADER_CLUSTER_ID, c.App.Cluster.GetClusterId())
- }
-
- w.Write([]byte(model.ClusterInfosToJson(infos)))
-}
-
-func getAllAudits(c *Context, w http.ResponseWriter, r *http.Request) {
- if audits, err := c.App.GetAudits("", 200); err != nil {
- c.Err = err
- return
- } else if c.HandleEtag(audits.Etag(), "Get All Audits", w, r) {
- return
- } else {
- etag := audits.Etag()
- if len(etag) > 0 {
- w.Header().Set(model.HEADER_ETAG_SERVER, etag)
- }
-
- w.Write([]byte(audits.ToJson()))
- return
- }
-}
-
-func getConfig(c *Context, w http.ResponseWriter, r *http.Request) {
- cfg := c.App.GetConfig()
- w.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate")
- w.Write([]byte(cfg.ToJson()))
-}
-
-func reloadConfig(c *Context, w http.ResponseWriter, r *http.Request) {
- c.App.ReloadConfig()
- w.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate")
- ReturnStatusOK(w)
-}
-
-func invalidateAllCaches(c *Context, w http.ResponseWriter, r *http.Request) {
- err := c.App.InvalidateAllCaches()
- if err != nil {
- c.Err = err
- return
- }
-
- w.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate")
- ReturnStatusOK(w)
-}
-
-func saveConfig(c *Context, w http.ResponseWriter, r *http.Request) {
- cfg := model.ConfigFromJson(r.Body)
- if cfg == nil {
- c.SetInvalidParam("saveConfig", "config")
- return
- }
-
- // Do not allow plugin uploads to be toggled through the API
- cfg.PluginSettings.EnableUploads = c.App.GetConfig().PluginSettings.EnableUploads
-
- err := c.App.SaveConfig(cfg, true)
- if err != nil {
- c.Err = err
- return
- }
-
- c.LogAudit("")
- ReturnStatusOK(w)
-}
-
-func recycleDatabaseConnection(c *Context, w http.ResponseWriter, r *http.Request) {
- c.App.RecycleDatabaseConnection()
- w.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate")
- ReturnStatusOK(w)
-}
-
-func testEmail(c *Context, w http.ResponseWriter, r *http.Request) {
- cfg := model.ConfigFromJson(r.Body)
- if cfg == nil {
- c.SetInvalidParam("testEmail", "config")
- return
- }
-
- err := c.App.TestEmail(c.Session.UserId, cfg)
- if err != nil {
- c.Err = err
- return
- }
-
- m := make(map[string]string)
- m["SUCCESS"] = "true"
- w.Write([]byte(model.MapToJson(m)))
-}
-
-func getComplianceReports(c *Context, w http.ResponseWriter, r *http.Request) {
- crs, err := c.App.GetComplianceReports(0, 10000)
- if err != nil {
- c.Err = err
- return
- }
- w.Write([]byte(crs.ToJson()))
-}
-
-func saveComplianceReport(c *Context, w http.ResponseWriter, r *http.Request) {
- job := model.ComplianceFromJson(r.Body)
- if job == nil {
- c.SetInvalidParam("saveComplianceReport", "compliance")
- return
- }
-
- job.UserId = c.Session.UserId
-
- rjob, err := c.App.SaveComplianceReport(job)
- if err != nil {
- c.Err = err
- return
- }
-
- c.LogAudit("")
- w.Write([]byte(rjob.ToJson()))
-}
-
-func downloadComplianceReport(c *Context, w http.ResponseWriter, r *http.Request) {
- params := mux.Vars(r)
-
- id := params["id"]
- if len(id) != 26 {
- c.SetInvalidParam("downloadComplianceReport", "id")
- return
- }
-
- job, err := c.App.GetComplianceReport(id)
- if err != nil {
- c.Err = err
- return
- }
-
- reportBytes, err := c.App.GetComplianceFile(job)
- if err != nil {
- c.Err = err
- return
- }
-
- c.LogAudit("downloaded " + job.Desc)
-
- w.Header().Set("Cache-Control", "max-age=2592000, public")
- w.Header().Set("Content-Length", strconv.Itoa(len(reportBytes)))
- w.Header().Del("Content-Type") // Content-Type will be set automatically by the http writer
-
- // attach extra headers to trigger a download on IE, Edge, and Safari
- ua := uasurfer.Parse(r.UserAgent())
-
- w.Header().Set("Content-Disposition", "attachment;filename=\""+job.JobName()+".zip\"")
-
- if ua.Browser.Name == uasurfer.BrowserIE || ua.Browser.Name == uasurfer.BrowserSafari {
- // trim off anything before the final / so we just get the file's name
- w.Header().Set("Content-Type", "application/octet-stream")
- }
-
- w.Write(reportBytes)
-}
-
-func getAnalytics(c *Context, w http.ResponseWriter, r *http.Request) {
- params := mux.Vars(r)
- teamId := params["id"]
- name := params["name"]
-
- rows, err := c.App.GetAnalytics(name, teamId)
- if err != nil {
- c.Err = err
- return
- }
-
- if rows == nil {
- c.SetInvalidParam("getAnalytics", "name")
- return
- }
-
- w.Write([]byte(rows.ToJson()))
-}
-
-func uploadBrandImage(c *Context, w http.ResponseWriter, r *http.Request) {
- if r.ContentLength > *c.App.Config().FileSettings.MaxFileSize {
- c.Err = model.NewAppError("uploadBrandImage", "api.admin.upload_brand_image.too_large.app_error", nil, "", http.StatusRequestEntityTooLarge)
- return
- }
-
- if err := r.ParseMultipartForm(*c.App.Config().FileSettings.MaxFileSize); err != nil {
- c.Err = model.NewAppError("uploadBrandImage", "api.admin.upload_brand_image.parse.app_error", nil, "", http.StatusBadRequest)
- return
- }
-
- m := r.MultipartForm
-
- imageArray, ok := m.File["image"]
- if !ok {
- c.Err = model.NewAppError("uploadBrandImage", "api.admin.upload_brand_image.no_file.app_error", nil, "", http.StatusBadRequest)
- c.Err.StatusCode = http.StatusBadRequest
- return
- }
-
- if len(imageArray) <= 0 {
- c.Err = model.NewAppError("uploadBrandImage", "api.admin.upload_brand_image.array.app_error", nil, "", http.StatusBadRequest)
- c.Err.StatusCode = http.StatusBadRequest
- return
- }
-
- if err := c.App.SaveBrandImage(imageArray[0]); err != nil {
- c.Err = err
- return
- }
-
- c.LogAudit("")
-
- ReturnStatusOK(w)
-}
-
-func getBrandImage(c *Context, w http.ResponseWriter, r *http.Request) {
- if img, err := c.App.GetBrandImage(); err != nil {
- w.Write(nil)
- } else {
- w.Header().Set("Content-Type", "image/png")
- w.Write(img)
- }
-}
-
-func adminResetMfa(c *Context, w http.ResponseWriter, r *http.Request) {
- props := model.MapFromJson(r.Body)
-
- userId := props["user_id"]
- if len(userId) != 26 {
- c.SetInvalidParam("adminResetMfa", "user_id")
- return
- }
-
- if err := c.App.DeactivateMfa(userId); err != nil {
- c.Err = err
- return
- }
-
- c.LogAudit("")
-
- rdata := map[string]string{}
- rdata["status"] = "ok"
- w.Write([]byte(model.MapToJson(rdata)))
-}
-
-func adminResetPassword(c *Context, w http.ResponseWriter, r *http.Request) {
- props := model.MapFromJson(r.Body)
-
- userId := props["user_id"]
- if len(userId) != 26 {
- c.SetInvalidParam("adminResetPassword", "user_id")
- return
- }
-
- newPassword := props["new_password"]
- if err := c.App.IsPasswordValid(newPassword); err != nil {
- c.Err = err
- return
- }
-
- if err := c.App.UpdatePasswordByUserIdSendEmail(userId, newPassword, c.T("api.user.reset_password.method")); err != nil {
- c.Err = err
- return
- }
-
- c.LogAudit("")
-
- rdata := map[string]string{}
- rdata["status"] = "ok"
- w.Write([]byte(model.MapToJson(rdata)))
-}
-
-func ldapSyncNow(c *Context, w http.ResponseWriter, r *http.Request) {
- c.App.SyncLdap()
-
- rdata := map[string]string{}
- rdata["status"] = "ok"
- w.Write([]byte(model.MapToJson(rdata)))
-}
-
-func ldapTest(c *Context, w http.ResponseWriter, r *http.Request) {
- if err := c.App.TestLdap(); err != nil {
- c.Err = err
- return
- }
-
- rdata := map[string]string{}
- rdata["status"] = "ok"
- w.Write([]byte(model.MapToJson(rdata)))
-}
-
-func samlMetadata(c *Context, w http.ResponseWriter, r *http.Request) {
- if result, err := c.App.GetSamlMetadata(); err != nil {
- c.Err = model.NewAppError("loginWithSaml", "api.admin.saml.metadata.app_error", nil, "err="+err.Message, http.StatusInternalServerError)
- return
- } else {
- w.Header().Set("Content-Type", "application/xml")
- w.Header().Set("Content-Disposition", "attachment; filename=\"metadata.xml\"")
- w.Write([]byte(result))
- }
-}
-
-func addCertificate(c *Context, w http.ResponseWriter, r *http.Request) {
- err := r.ParseMultipartForm(*c.App.Config().FileSettings.MaxFileSize)
- if err != nil {
- http.Error(w, err.Error(), http.StatusInternalServerError)
- return
- }
-
- m := r.MultipartForm
-
- fileArray, ok := m.File["certificate"]
- if !ok {
- c.Err = model.NewAppError("addCertificate", "api.admin.add_certificate.no_file.app_error", nil, "", http.StatusBadRequest)
- c.Err.StatusCode = http.StatusBadRequest
- return
- }
-
- if len(fileArray) <= 0 {
- c.Err = model.NewAppError("addCertificate", "api.admin.add_certificate.array.app_error", nil, "", http.StatusBadRequest)
- c.Err.StatusCode = http.StatusBadRequest
- return
- }
-
- fileData := fileArray[0]
-
- if err := app.WriteSamlFile(fileData); err != nil {
- c.Err = err
- return
- }
- ReturnStatusOK(w)
-}
-
-func removeCertificate(c *Context, w http.ResponseWriter, r *http.Request) {
- props := model.MapFromJson(r.Body)
-
- if err := app.RemoveSamlFile(props["filename"]); err != nil {
- c.Err = err
- return
- }
-
- ReturnStatusOK(w)
-}
-
-func samlCertificateStatus(c *Context, w http.ResponseWriter, r *http.Request) {
- status := c.App.GetSamlCertificateStatus()
-
- statusMap := map[string]interface{}{}
- statusMap["IdpCertificateFile"] = status.IdpCertificateFile
- statusMap["PrivateKeyFile"] = status.PrivateKeyFile
- statusMap["PublicCertificateFile"] = status.PublicCertificateFile
-
- w.Write([]byte(model.StringInterfaceToJson(statusMap)))
-}
-
-func getRecentlyActiveUsers(c *Context, w http.ResponseWriter, r *http.Request) {
- if profiles, err := c.App.GetRecentlyActiveUsersForTeam(c.TeamId); err != nil {
- c.Err = err
- return
- } else {
- for _, p := range profiles {
- sanitizeProfile(c, p)
- }
-
- w.Write([]byte(model.UserMapToJson(profiles)))
- }
-}
diff --git a/api/admin_test.go b/api/admin_test.go
deleted file mode 100644
index dfa6cd3b9..000000000
--- a/api/admin_test.go
+++ /dev/null
@@ -1,624 +0,0 @@
-// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-package api
-
-import (
- "net/http"
- "strings"
- "testing"
-
- "github.com/mattermost/mattermost-server/model"
- "github.com/mattermost/mattermost-server/store"
- "github.com/stretchr/testify/assert"
-)
-
-func TestGetLogs(t *testing.T) {
- th := Setup().InitSystemAdmin().InitBasic()
- defer th.TearDown()
-
- if _, err := th.BasicClient.GetLogs(); err == nil {
- t.Fatal("Shouldn't have permissions")
- }
-
- if logs, err := th.SystemAdminClient.GetLogs(); err != nil {
- t.Fatal(err)
- } else if len(logs.Data.([]string)) <= 0 {
- t.Fatal()
- }
-}
-
-func TestGetClusterInfos(t *testing.T) {
- if testing.Short() {
- t.SkipNow()
- }
- th := Setup().InitSystemAdmin().InitBasic()
- defer th.TearDown()
-
- if _, err := th.BasicClient.GetClusterStatus(); err == nil {
- t.Fatal("Shouldn't have permissions")
- }
-
- if _, err := th.SystemAdminClient.GetClusterStatus(); err != nil {
- t.Fatal(err)
- }
-}
-
-func TestGetAllAudits(t *testing.T) {
- th := Setup().InitBasic().InitSystemAdmin()
- defer th.TearDown()
-
- if _, err := th.BasicClient.GetAllAudits(); err == nil {
- t.Fatal("Shouldn't have permissions")
- }
-
- if audits, err := th.SystemAdminClient.GetAllAudits(); err != nil {
- t.Fatal(err)
- } else if len(audits.Data.(model.Audits)) <= 0 {
- t.Fatal()
- }
-}
-
-func TestGetConfig(t *testing.T) {
- th := Setup().InitBasic().InitSystemAdmin()
- defer th.TearDown()
-
- if _, err := th.BasicClient.GetConfig(); err == nil {
- t.Fatal("Shouldn't have permissions")
- }
-
- if result, err := th.SystemAdminClient.GetConfig(); err != nil {
- t.Fatal(err)
- } else {
- cfg := result.Data.(*model.Config)
-
- if len(cfg.TeamSettings.SiteName) == 0 {
- t.Fatal()
- }
-
- if *cfg.LdapSettings.BindPassword != model.FAKE_SETTING && len(*cfg.LdapSettings.BindPassword) != 0 {
- t.Fatal("did not sanitize properly")
- }
- if *cfg.FileSettings.PublicLinkSalt != model.FAKE_SETTING {
- t.Fatal("did not sanitize properly")
- }
- if cfg.FileSettings.AmazonS3SecretAccessKey != model.FAKE_SETTING && len(cfg.FileSettings.AmazonS3SecretAccessKey) != 0 {
- t.Fatal("did not sanitize properly")
- }
- if cfg.EmailSettings.InviteSalt != model.FAKE_SETTING {
- t.Fatal("did not sanitize properly")
- }
- if cfg.EmailSettings.SMTPPassword != model.FAKE_SETTING && len(cfg.EmailSettings.SMTPPassword) != 0 {
- t.Fatal("did not sanitize properly")
- }
- if cfg.GitLabSettings.Secret != model.FAKE_SETTING && len(cfg.GitLabSettings.Secret) != 0 {
- t.Fatal("did not sanitize properly")
- }
- if *cfg.SqlSettings.DataSource != model.FAKE_SETTING {
- t.Fatal("did not sanitize properly")
- }
- if cfg.SqlSettings.AtRestEncryptKey != model.FAKE_SETTING {
- t.Fatal("did not sanitize properly")
- }
- if !strings.Contains(strings.Join(cfg.SqlSettings.DataSourceReplicas, " "), model.FAKE_SETTING) && len(cfg.SqlSettings.DataSourceReplicas) != 0 {
- t.Fatal("did not sanitize properly")
- }
- }
-}
-
-func TestReloadConfig(t *testing.T) {
- th := Setup().InitBasic().InitSystemAdmin()
- defer th.TearDown()
-
- if _, err := th.BasicClient.ReloadConfig(); err == nil {
- t.Fatal("Shouldn't have permissions")
- }
-
- if _, err := th.SystemAdminClient.ReloadConfig(); err != nil {
- t.Fatal(err)
- }
-
- th.App.UpdateConfig(func(cfg *model.Config) { *cfg.TeamSettings.MaxUsersPerTeam = 50 })
- th.App.UpdateConfig(func(cfg *model.Config) { *cfg.TeamSettings.EnableOpenServer = true })
-}
-
-func TestInvalidateAllCache(t *testing.T) {
- th := Setup().InitBasic().InitSystemAdmin()
- defer th.TearDown()
-
- if _, err := th.BasicClient.InvalidateAllCaches(); err == nil {
- t.Fatal("Shouldn't have permissions")
- }
-
- if _, err := th.SystemAdminClient.InvalidateAllCaches(); err != nil {
- t.Fatal(err)
- }
-}
-
-func TestSaveConfig(t *testing.T) {
- th := Setup().InitBasic().InitSystemAdmin()
- defer th.TearDown()
-
- if _, err := th.BasicClient.SaveConfig(th.App.Config()); err == nil {
- t.Fatal("Shouldn't have permissions")
- }
-
- th.App.UpdateConfig(func(cfg *model.Config) { *cfg.TeamSettings.EnableOpenServer = false })
-
- if _, err := th.SystemAdminClient.SaveConfig(th.App.Config()); err != nil {
- t.Fatal(err)
- }
-
- th.App.UpdateConfig(func(cfg *model.Config) { *cfg.TeamSettings.EnableOpenServer = true })
-
- // Should not be able to modify PluginSettings.EnableUploads
- oldEnableUploads := *th.App.GetConfig().PluginSettings.EnableUploads
- cfg := &model.Config{}
- cfg.SetDefaults()
- *cfg.PluginSettings.EnableUploads = !oldEnableUploads
-
- if _, err := th.SystemAdminClient.SaveConfig(cfg); err != nil {
- t.Fatal(err)
- }
-
- assert.Equal(t, oldEnableUploads, *th.App.Config().PluginSettings.EnableUploads)
-}
-
-func TestRecycleDatabaseConnection(t *testing.T) {
- th := Setup().InitBasic().InitSystemAdmin()
- defer th.TearDown()
-
- if _, err := th.BasicClient.RecycleDatabaseConnection(); err == nil {
- t.Fatal("Shouldn't have permissions")
- }
-
- if _, err := th.SystemAdminClient.RecycleDatabaseConnection(); err != nil {
- t.Fatal(err)
- }
-}
-
-func TestEmailTest(t *testing.T) {
- th := Setup().InitBasic().InitSystemAdmin()
- defer th.TearDown()
-
- SendEmailNotifications := th.App.Config().EmailSettings.SendEmailNotifications
- SMTPServer := th.App.Config().EmailSettings.SMTPServer
- SMTPPort := th.App.Config().EmailSettings.SMTPPort
- FeedbackEmail := th.App.Config().EmailSettings.FeedbackEmail
- defer func() {
- th.App.UpdateConfig(func(cfg *model.Config) { cfg.EmailSettings.SendEmailNotifications = SendEmailNotifications })
- th.App.UpdateConfig(func(cfg *model.Config) { cfg.EmailSettings.SMTPServer = SMTPServer })
- th.App.UpdateConfig(func(cfg *model.Config) { cfg.EmailSettings.SMTPPort = SMTPPort })
- th.App.UpdateConfig(func(cfg *model.Config) { cfg.EmailSettings.FeedbackEmail = FeedbackEmail })
- }()
-
- th.App.UpdateConfig(func(cfg *model.Config) { cfg.EmailSettings.SendEmailNotifications = false })
- th.App.UpdateConfig(func(cfg *model.Config) { cfg.EmailSettings.SMTPServer = "" })
- th.App.UpdateConfig(func(cfg *model.Config) { cfg.EmailSettings.SMTPPort = "" })
- th.App.UpdateConfig(func(cfg *model.Config) { cfg.EmailSettings.FeedbackEmail = "" })
-
- if _, err := th.BasicClient.TestEmail(th.App.Config()); err == nil {
- t.Fatal("Shouldn't have permissions")
- }
-
- if _, err := th.SystemAdminClient.TestEmail(th.App.Config()); err == nil {
- t.Fatal("should have errored")
- } else {
- if err.Id != "api.admin.test_email.missing_server" {
- t.Fatal(err)
- }
- }
-}
-
-func TestLdapTest(t *testing.T) {
- th := Setup().InitBasic().InitSystemAdmin()
- defer th.TearDown()
-
- if _, err := th.BasicClient.TestLdap(th.App.Config()); err == nil {
- t.Fatal("Shouldn't have permissions")
- }
-
- if _, err := th.SystemAdminClient.TestLdap(th.App.Config()); err == nil {
- t.Fatal("should have errored")
- }
-}
-
-func TestGetTeamAnalyticsStandard(t *testing.T) {
- th := Setup().InitBasic().InitSystemAdmin()
- defer th.TearDown()
-
- th.CreatePrivateChannel(th.BasicClient, th.BasicTeam)
-
- if _, err := th.BasicClient.GetTeamAnalytics(th.BasicTeam.Id, "standard"); err == nil {
- t.Fatal("Shouldn't have permissions")
- }
-
- maxUsersForStats := *th.App.Config().AnalyticsSettings.MaxUsersForStatistics
- defer func() {
- th.App.UpdateConfig(func(cfg *model.Config) { *cfg.AnalyticsSettings.MaxUsersForStatistics = maxUsersForStats })
- }()
- th.App.UpdateConfig(func(cfg *model.Config) { *cfg.AnalyticsSettings.MaxUsersForStatistics = 1000000 })
-
- if result, err := th.SystemAdminClient.GetTeamAnalytics(th.BasicTeam.Id, "standard"); err != nil {
- t.Fatal(err)
- } else {
- rows := result.Data.(model.AnalyticsRows)
-
- if rows[0].Name != "channel_open_count" {
- t.Log(rows.ToJson())
- t.Fatal()
- }
-
- if rows[0].Value != 4 {
- t.Log(rows.ToJson())
- t.Fatal()
- }
-
- if rows[1].Name != "channel_private_count" {
- t.Log(rows.ToJson())
- t.Fatal()
- }
-
- if rows[1].Value != 1 {
- t.Log(rows.ToJson())
- t.Fatal()
- }
-
- if rows[2].Name != "post_count" {
- t.Log(rows.ToJson())
- t.Fatal()
- }
-
- if rows[2].Value != 9 {
- t.Log(rows.ToJson())
- t.Fatal()
- }
-
- if rows[3].Name != "unique_user_count" {
- t.Log(rows.ToJson())
- t.Fatal()
- }
-
- if rows[3].Value != 2 {
- t.Log(rows.ToJson())
- t.Fatal()
- }
-
- if rows[4].Name != "team_count" {
- t.Log(rows.ToJson())
- t.Fatal()
- }
-
- if rows[4].Value == 0 {
- t.Log(rows.ToJson())
- t.Fatal()
- }
- }
-
- if result, err := th.SystemAdminClient.GetSystemAnalytics("standard"); err != nil {
- t.Fatal(err)
- } else {
- rows := result.Data.(model.AnalyticsRows)
-
- if rows[0].Name != "channel_open_count" {
- t.Log(rows.ToJson())
- t.Fatal()
- }
-
- if rows[0].Value < 3 {
- t.Log(rows.ToJson())
- t.Fatal()
- }
-
- if rows[1].Name != "channel_private_count" {
- t.Log(rows.ToJson())
- t.Fatal()
- }
-
- if rows[1].Value == 0 {
- t.Log(rows.ToJson())
- t.Fatal()
- }
-
- if rows[2].Name != "post_count" {
- t.Log(rows.ToJson())
- t.Fatal()
- }
-
- if rows[2].Value == 0 {
- t.Log(rows.ToJson())
- t.Fatal()
- }
-
- if rows[3].Name != "unique_user_count" {
- t.Log(rows.ToJson())
- t.Fatal()
- }
-
- if rows[3].Value == 0 {
- t.Log(rows.ToJson())
- t.Fatal()
- }
-
- if rows[4].Name != "team_count" {
- t.Log(rows.ToJson())
- t.Fatal()
- }
-
- if rows[4].Value == 0 {
- t.Log(rows.ToJson())
- t.Fatal()
- }
- }
-
- th.App.UpdateConfig(func(cfg *model.Config) { *cfg.AnalyticsSettings.MaxUsersForStatistics = 1 })
-
- if result, err := th.SystemAdminClient.GetSystemAnalytics("standard"); err != nil {
- t.Fatal(err)
- } else {
- rows := result.Data.(model.AnalyticsRows)
-
- if rows[2].Name != "post_count" {
- t.Log(rows.ToJson())
- t.Fatal()
- }
-
- if rows[2].Value != -1 {
- t.Log(rows.ToJson())
- t.Fatal()
- }
- }
-}
-
-func TestGetTeamAnalyticsExtra(t *testing.T) {
- th := Setup().InitBasic().InitSystemAdmin()
- defer th.TearDown()
-
- th.CreatePost(th.BasicClient, th.BasicChannel)
-
- if _, err := th.BasicClient.GetTeamAnalytics("", "extra_counts"); err == nil {
- t.Fatal("Shouldn't have permissions")
- }
-
- maxUsersForStats := *th.App.Config().AnalyticsSettings.MaxUsersForStatistics
- defer func() {
- th.App.UpdateConfig(func(cfg *model.Config) { *cfg.AnalyticsSettings.MaxUsersForStatistics = maxUsersForStats })
- }()
- th.App.UpdateConfig(func(cfg *model.Config) { *cfg.AnalyticsSettings.MaxUsersForStatistics = 1000000 })
-
- if result, err := th.SystemAdminClient.GetTeamAnalytics(th.BasicTeam.Id, "extra_counts"); err != nil {
- t.Fatal(err)
- } else {
- rows := result.Data.(model.AnalyticsRows)
-
- if rows[0].Name != "file_post_count" {
- t.Log(rows.ToJson())
- t.Fatal()
- }
-
- if rows[0].Value != 0 {
- t.Log(rows.ToJson())
- t.Fatal()
- }
-
- if rows[1].Name != "hashtag_post_count" {
- t.Log(rows.ToJson())
- t.Fatal()
- }
-
- if rows[1].Value != 0 {
- t.Log(rows.ToJson())
- t.Fatal()
- }
-
- if rows[2].Name != "incoming_webhook_count" {
- t.Log(rows.ToJson())
- t.Fatal()
- }
-
- if rows[2].Value != 0 {
- t.Log(rows.ToJson())
- t.Fatal()
- }
-
- if rows[3].Name != "outgoing_webhook_count" {
- t.Log(rows.ToJson())
- t.Fatal()
- }
-
- if rows[3].Value != 0 {
- t.Log(rows.ToJson())
- t.Fatal()
- }
-
- if rows[4].Name != "command_count" {
- t.Log(rows.ToJson())
- t.Fatal()
- }
-
- if rows[4].Value != 0 {
- t.Log(rows.ToJson())
- t.Fatal()
- }
-
- if rows[5].Name != "session_count" {
- t.Log(rows.ToJson())
- t.Fatal()
- }
-
- if rows[5].Value == 0 {
- t.Log(rows.ToJson())
- t.Fatal()
- }
- }
-
- if result, err := th.SystemAdminClient.GetSystemAnalytics("extra_counts"); err != nil {
- t.Fatal(err)
- } else {
- rows := result.Data.(model.AnalyticsRows)
-
- if rows[0].Name != "file_post_count" {
- t.Log(rows.ToJson())
- t.Fatal()
- }
-
- if rows[1].Name != "hashtag_post_count" {
- t.Log(rows.ToJson())
- t.Fatal()
- }
-
- if rows[2].Name != "incoming_webhook_count" {
- t.Log(rows.ToJson())
- t.Fatal()
- }
-
- if rows[3].Name != "outgoing_webhook_count" {
- t.Log(rows.ToJson())
- t.Fatal()
- }
-
- if rows[4].Name != "command_count" {
- t.Log(rows.ToJson())
- t.Fatal()
- }
-
- if rows[5].Name != "session_count" {
- t.Log(rows.ToJson())
- t.Fatal()
- }
- }
-
- th.App.UpdateConfig(func(cfg *model.Config) { *cfg.AnalyticsSettings.MaxUsersForStatistics = 1 })
-
- if result, err := th.SystemAdminClient.GetSystemAnalytics("extra_counts"); err != nil {
- t.Fatal(err)
- } else {
- rows := result.Data.(model.AnalyticsRows)
-
- if rows[0].Value != -1 {
- t.Log(rows.ToJson())
- t.Fatal()
- }
-
- if rows[1].Value != -1 {
- t.Log(rows.ToJson())
- t.Fatal()
- }
- }
-}
-
-func TestAdminResetMfa(t *testing.T) {
- th := Setup().InitBasic().InitSystemAdmin()
- defer th.TearDown()
-
- if _, err := th.BasicClient.AdminResetMfa("12345678901234567890123456"); err == nil {
- t.Fatal("should have failed - not an admin")
- }
-
- if _, err := th.SystemAdminClient.AdminResetMfa(""); err == nil {
- t.Fatal("should have failed - empty user id")
- }
-
- if _, err := th.SystemAdminClient.AdminResetMfa("12345678901234567890123456"); err == nil {
- t.Fatal("should have failed - bad user id")
- }
-
- if _, err := th.SystemAdminClient.AdminResetMfa(th.BasicUser.Id); err == nil {
- t.Fatal("should have failed - not licensed or configured")
- }
-
- // need to add more test cases when enterprise bits can be loaded into tests
-}
-
-func TestAdminResetPassword(t *testing.T) {
- th := Setup().InitSystemAdmin()
- defer th.TearDown()
-
- Client := th.SystemAdminClient
- team := th.SystemAdminTeam
-
- user := &model.User{Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "passwd1"}
- user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
- th.LinkUserToTeam(user, team)
- store.Must(th.App.Srv.Store.User().VerifyEmail(user.Id))
-
- if _, err := Client.AdminResetPassword("", "newpwd1"); err == nil {
- t.Fatal("Should have errored - empty user id")
- }
-
- if _, err := Client.AdminResetPassword("123", "newpwd1"); err == nil {
- t.Fatal("Should have errored - bad user id")
- }
-
- if _, err := Client.AdminResetPassword("12345678901234567890123456", "newpwd1"); err == nil {
- t.Fatal("Should have errored - bad user id")
- }
-
- if _, err := Client.AdminResetPassword("12345678901234567890123456", "newp"); err == nil {
- t.Fatal("Should have errored - password too short")
- }
-
- authData := model.NewId()
- user2 := &model.User{Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", AuthData: &authData, AuthService: "random"}
- user2 = Client.Must(Client.CreateUser(user2, "")).Data.(*model.User)
- th.LinkUserToTeam(user2, team)
- store.Must(th.App.Srv.Store.User().VerifyEmail(user2.Id))
-
- if _, err := Client.AdminResetPassword(user.Id, "newpwd1"); err != nil {
- t.Fatal(err)
- }
-
- Client.Logout()
- Client.Must(Client.LoginById(user.Id, "newpwd1"))
- Client.SetTeamId(team.Id)
-
- if _, err := Client.AdminResetPassword(user.Id, "newpwd1"); err == nil {
- t.Fatal("Should have errored - not system admin")
- }
-}
-
-func TestAdminLdapSyncNow(t *testing.T) {
- th := Setup().InitSystemAdmin()
- defer th.TearDown()
-
- Client := th.SystemAdminClient
-
- if _, err := Client.LdapSyncNow(); err != nil {
- t.Fatal("Returned Failure")
- }
-}
-
-// Needs more work
-func TestGetRecentlyActiveUsers(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- if userMap, err := th.BasicClient.GetRecentlyActiveUsers(th.BasicTeam.Id); err != nil {
- t.Fatal(err)
- } else if len(userMap.Data.(map[string]*model.User)) >= 2 {
- t.Fatal("should have been at least 2")
- }
-}
-
-func TestDisableAPIv3(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- Client := th.BasicClient
-
- enableAPIv3 := *th.App.Config().ServiceSettings.EnableAPIv3
- defer func() {
- th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableAPIv3 = enableAPIv3 })
- }()
- th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableAPIv3 = false })
-
- _, err := Client.GetUser(th.BasicUser.Id, "")
-
- if err.StatusCode != http.StatusNotImplemented {
- t.Fatal("wrong error code")
- }
-
- if err.Id != "api.context.v3_disabled.app_error" {
- t.Fatal("wrong error message")
- }
-}
diff --git a/api/api.go b/api/api.go
deleted file mode 100644
index 2b226bbeb..000000000
--- a/api/api.go
+++ /dev/null
@@ -1,131 +0,0 @@
-// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-package api
-
-import (
- "net/http"
-
- "github.com/gorilla/mux"
- "github.com/mattermost/mattermost-server/app"
- "github.com/mattermost/mattermost-server/mlog"
- "github.com/mattermost/mattermost-server/model"
-
- _ "github.com/nicksnyder/go-i18n/i18n"
-)
-
-type Routes struct {
- Root *mux.Router // ''
- ApiRoot *mux.Router // 'api/v3'
-
- Users *mux.Router // 'api/v3/users'
- NeedUser *mux.Router // 'api/v3/users/{user_id:[A-Za-z0-9]+}'
-
- Teams *mux.Router // 'api/v3/teams'
- NeedTeam *mux.Router // 'api/v3/teams/{team_id:[A-Za-z0-9]+}'
-
- Channels *mux.Router // 'api/v3/teams/{team_id:[A-Za-z0-9]+}/channels'
- NeedChannel *mux.Router // 'api/v3/teams/{team_id:[A-Za-z0-9]+}/channels/{channel_id:[A-Za-z0-9]+}'
- NeedChannelName *mux.Router // 'api/v3/teams/{team_id:[A-Za-z0-9]+}/channels/name/{channel_name:[A-Za-z0-9_-]+}'
-
- Posts *mux.Router // 'api/v3/teams/{team_id:[A-Za-z0-9]+}/channels/{channel_id:[A-Za-z0-9]+}/posts'
- NeedPost *mux.Router // 'api/v3/teams/{team_id:[A-Za-z0-9]+}/channels/{channel_id:[A-Za-z0-9]+}/posts/{post_id:[A-Za-z0-9]+}'
-
- Commands *mux.Router // 'api/v3/teams/{team_id:[A-Za-z0-9]+}/commands'
- Hooks *mux.Router // 'api/v3/teams/{team_id:[A-Za-z0-9]+}/hooks'
-
- TeamFiles *mux.Router // 'api/v3/teams/{team_id:[A-Za-z0-9]+}/files'
- Files *mux.Router // 'api/v3/files'
- NeedFile *mux.Router // 'api/v3/files/{file_id:[A-Za-z0-9]+}'
-
- OAuth *mux.Router // 'api/v3/oauth'
-
- Admin *mux.Router // 'api/v3/admin'
-
- General *mux.Router // 'api/v3/general'
-
- Preferences *mux.Router // 'api/v3/preferences'
-
- License *mux.Router // 'api/v3/license'
-
- Public *mux.Router // 'api/v3/public'
-
- Emoji *mux.Router // 'api/v3/emoji'
-
- Webrtc *mux.Router // 'api/v3/webrtc'
-}
-
-type API struct {
- App *app.App
- BaseRoutes *Routes
-}
-
-func Init(a *app.App, root *mux.Router) *API {
- api := &API{
- App: a,
- BaseRoutes: &Routes{},
- }
- api.BaseRoutes.Root = root
- api.BaseRoutes.ApiRoot = root.PathPrefix(model.API_URL_SUFFIX_V3).Subrouter()
- api.BaseRoutes.Users = api.BaseRoutes.ApiRoot.PathPrefix("/users").Subrouter()
- api.BaseRoutes.NeedUser = api.BaseRoutes.Users.PathPrefix("/{user_id:[A-Za-z0-9]+}").Subrouter()
- api.BaseRoutes.Teams = api.BaseRoutes.ApiRoot.PathPrefix("/teams").Subrouter()
- api.BaseRoutes.NeedTeam = api.BaseRoutes.Teams.PathPrefix("/{team_id:[A-Za-z0-9]+}").Subrouter()
- api.BaseRoutes.Channels = api.BaseRoutes.NeedTeam.PathPrefix("/channels").Subrouter()
- api.BaseRoutes.NeedChannel = api.BaseRoutes.Channels.PathPrefix("/{channel_id:[A-Za-z0-9]+}").Subrouter()
- api.BaseRoutes.NeedChannelName = api.BaseRoutes.Channels.PathPrefix("/name/{channel_name:[A-Za-z0-9_-]+}").Subrouter()
- api.BaseRoutes.Posts = api.BaseRoutes.NeedChannel.PathPrefix("/posts").Subrouter()
- api.BaseRoutes.NeedPost = api.BaseRoutes.Posts.PathPrefix("/{post_id:[A-Za-z0-9]+}").Subrouter()
- api.BaseRoutes.Commands = api.BaseRoutes.NeedTeam.PathPrefix("/commands").Subrouter()
- api.BaseRoutes.TeamFiles = api.BaseRoutes.NeedTeam.PathPrefix("/files").Subrouter()
- api.BaseRoutes.Files = api.BaseRoutes.ApiRoot.PathPrefix("/files").Subrouter()
- api.BaseRoutes.NeedFile = api.BaseRoutes.Files.PathPrefix("/{file_id:[A-Za-z0-9]+}").Subrouter()
- api.BaseRoutes.Hooks = api.BaseRoutes.NeedTeam.PathPrefix("/hooks").Subrouter()
- api.BaseRoutes.OAuth = api.BaseRoutes.ApiRoot.PathPrefix("/oauth").Subrouter()
- api.BaseRoutes.Admin = api.BaseRoutes.ApiRoot.PathPrefix("/admin").Subrouter()
- api.BaseRoutes.General = api.BaseRoutes.ApiRoot.PathPrefix("/general").Subrouter()
- api.BaseRoutes.Preferences = api.BaseRoutes.ApiRoot.PathPrefix("/preferences").Subrouter()
- api.BaseRoutes.License = api.BaseRoutes.ApiRoot.PathPrefix("/license").Subrouter()
- api.BaseRoutes.Public = api.BaseRoutes.ApiRoot.PathPrefix("/public").Subrouter()
- api.BaseRoutes.Emoji = api.BaseRoutes.ApiRoot.PathPrefix("/emoji").Subrouter()
- api.BaseRoutes.Webrtc = api.BaseRoutes.ApiRoot.PathPrefix("/webrtc").Subrouter()
-
- api.InitUser()
- api.InitTeam()
- api.InitChannel()
- api.InitPost()
- api.InitWebSocket()
- api.InitFile()
- api.InitCommand()
- api.InitAdmin()
- api.InitGeneral()
- api.InitOAuth()
- api.InitWebhook()
- api.InitPreference()
- api.InitLicense()
- api.InitEmoji()
- api.InitStatus()
- api.InitWebrtc()
- api.InitReaction()
-
- // 404 on any api route before web.go has a chance to serve it
- root.Handle("/api/{anything:.*}", http.HandlerFunc(api.Handle404))
-
- a.InitEmailBatching()
-
- if *a.Config().ServiceSettings.EnableAPIv3 {
- mlog.Info("API version 3 is scheduled for deprecation. Please see https://api.mattermost.com for details.")
- }
-
- return api
-}
-
-func (api *API) Handle404(w http.ResponseWriter, r *http.Request) {
- Handle404(api.App, w, r)
-}
-
-func ReturnStatusOK(w http.ResponseWriter) {
- m := make(map[string]string)
- m[model.STATUS] = model.STATUS_OK
- w.Write([]byte(model.MapToJson(m)))
-}
diff --git a/api/api_test.go b/api/api_test.go
deleted file mode 100644
index a4ddf6a37..000000000
--- a/api/api_test.go
+++ /dev/null
@@ -1,52 +0,0 @@
-// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-package api
-
-import (
- "flag"
- "os"
- "testing"
-
- "github.com/mattermost/mattermost-server/mlog"
- "github.com/mattermost/mattermost-server/store/storetest"
- "github.com/mattermost/mattermost-server/utils"
-)
-
-func TestMain(m *testing.M) {
- flag.Parse()
-
- // Setup a global logger to catch tests logging outside of app context
- // The global logger will be stomped by apps initalizing but that's fine for testing. Ideally this won't happen.
- mlog.InitGlobalLogger(mlog.NewLogger(&mlog.LoggerConfiguration{
- EnableConsole: true,
- ConsoleJson: true,
- ConsoleLevel: "error",
- EnableFile: false,
- }))
-
- utils.TranslationsPreInit()
-
- // In the case where a dev just wants to run a single test, it's faster to just use the default
- // store.
- if filter := flag.Lookup("test.run").Value.String(); filter != "" && filter != "." {
- mlog.Info("-test.run used, not creating temporary containers")
- os.Exit(m.Run())
- }
-
- status := 0
-
- container, settings, err := storetest.NewMySQLContainer()
- if err != nil {
- panic(err)
- }
-
- UseTestStore(container, settings)
-
- defer func() {
- StopTestStore()
- os.Exit(status)
- }()
-
- status = m.Run()
-}
diff --git a/api/apitestlib.go b/api/apitestlib.go
deleted file mode 100644
index 20dbc4073..000000000
--- a/api/apitestlib.go
+++ /dev/null
@@ -1,508 +0,0 @@
-// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-package api
-
-import (
- "fmt"
- "io"
- "io/ioutil"
- "net"
- "os"
- "strings"
- "time"
-
- "github.com/mattermost/mattermost-server/api4"
- "github.com/mattermost/mattermost-server/app"
- "github.com/mattermost/mattermost-server/mlog"
- "github.com/mattermost/mattermost-server/model"
- "github.com/mattermost/mattermost-server/store"
- "github.com/mattermost/mattermost-server/store/sqlstore"
- "github.com/mattermost/mattermost-server/store/storetest"
- "github.com/mattermost/mattermost-server/utils"
- "github.com/mattermost/mattermost-server/wsapi"
-)
-
-type TestHelper struct {
- App *app.App
- tempConfigPath string
-
- BasicClient *model.Client
- BasicTeam *model.Team
- BasicUser *model.User
- BasicUser2 *model.User
- BasicChannel *model.Channel
- BasicPost *model.Post
- PinnedPost *model.Post
-
- SystemAdminClient *model.Client
- SystemAdminTeam *model.Team
- SystemAdminUser *model.User
- SystemAdminChannel *model.Channel
-}
-
-type persistentTestStore struct {
- store.Store
-}
-
-func (*persistentTestStore) Close() {}
-
-var testStoreContainer *storetest.RunningContainer
-var testStore *persistentTestStore
-
-// UseTestStore sets the container and corresponding settings to use for tests. Once the tests are
-// complete (e.g. at the end of your TestMain implementation), you should call StopTestStore.
-func UseTestStore(container *storetest.RunningContainer, settings *model.SqlSettings) {
- testStoreContainer = container
- testStore = &persistentTestStore{store.NewLayeredStore(sqlstore.NewSqlSupplier(*settings, nil), nil, nil)}
-}
-
-func StopTestStore() {
- if testStoreContainer != nil {
- testStoreContainer.Stop()
- testStoreContainer = nil
- }
-}
-
-func setupTestHelper(enterprise bool) *TestHelper {
- permConfig, err := os.Open(utils.FindConfigFile("config.json"))
- if err != nil {
- panic(err)
- }
- defer permConfig.Close()
- tempConfig, err := ioutil.TempFile("", "")
- if err != nil {
- panic(err)
- }
- _, err = io.Copy(tempConfig, permConfig)
- tempConfig.Close()
- if err != nil {
- panic(err)
- }
-
- options := []app.Option{app.ConfigFile(tempConfig.Name()), app.DisableConfigWatch}
- if testStore != nil {
- options = append(options, app.StoreOverride(testStore))
- }
-
- a, err := app.New(options...)
- if err != nil {
- panic(err)
- }
-
- th := &TestHelper{
- App: a,
- tempConfigPath: tempConfig.Name(),
- }
-
- th.App.UpdateConfig(func(cfg *model.Config) {
- *cfg.TeamSettings.MaxUsersPerTeam = 50
- *cfg.RateLimitSettings.Enable = false
- cfg.EmailSettings.SendEmailNotifications = true
- *cfg.ServiceSettings.EnableAPIv3 = true
- })
- prevListenAddress := *th.App.Config().ServiceSettings.ListenAddress
- if testStore != nil {
- th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.ListenAddress = ":0" })
- }
- serverErr := th.App.StartServer()
- if serverErr != nil {
- panic(serverErr)
- }
-
- th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.ListenAddress = prevListenAddress })
- api4.Init(th.App, th.App.Srv.Router, false)
- Init(th.App, th.App.Srv.Router)
- wsapi.Init(th.App, th.App.Srv.WebSocketRouter)
- th.App.Srv.Store.MarkSystemRanUnitTests()
- th.App.DoAdvancedPermissionsMigration()
-
- th.App.UpdateConfig(func(cfg *model.Config) { *cfg.TeamSettings.EnableOpenServer = true })
-
- if enterprise {
- th.App.SetLicense(model.NewTestLicense())
- } else {
- th.App.SetLicense(nil)
- }
-
- return th
-}
-
-func SetupEnterprise() *TestHelper {
- return setupTestHelper(true)
-}
-
-func Setup() *TestHelper {
- return setupTestHelper(false)
-}
-
-func (me *TestHelper) InitBasic() *TestHelper {
- me.waitForConnectivity()
-
- me.BasicClient = me.CreateClient()
- me.BasicUser = me.CreateUser(me.BasicClient)
- me.App.UpdateUserRoles(me.BasicUser.Id, model.SYSTEM_USER_ROLE_ID, false)
- me.LoginBasic()
- me.BasicTeam = me.CreateTeam(me.BasicClient)
- me.LinkUserToTeam(me.BasicUser, me.BasicTeam)
- me.UpdateUserToNonTeamAdmin(me.BasicUser, me.BasicTeam)
- me.BasicUser2 = me.CreateUser(me.BasicClient)
- me.LinkUserToTeam(me.BasicUser2, me.BasicTeam)
- me.BasicClient.SetTeamId(me.BasicTeam.Id)
- me.BasicChannel = me.CreateChannel(me.BasicClient, me.BasicTeam)
- me.BasicPost = me.CreatePost(me.BasicClient, me.BasicChannel)
-
- pinnedPostChannel := me.CreateChannel(me.BasicClient, me.BasicTeam)
- me.PinnedPost = me.CreatePinnedPost(me.BasicClient, pinnedPostChannel)
-
- return me
-}
-
-func (me *TestHelper) InitSystemAdmin() *TestHelper {
- me.waitForConnectivity()
-
- me.SystemAdminClient = me.CreateClient()
- me.SystemAdminUser = me.CreateUser(me.SystemAdminClient)
- me.SystemAdminUser.Password = "Password1"
- me.LoginSystemAdmin()
- me.SystemAdminTeam = me.CreateTeam(me.SystemAdminClient)
- me.LinkUserToTeam(me.SystemAdminUser, me.SystemAdminTeam)
- me.SystemAdminClient.SetTeamId(me.SystemAdminTeam.Id)
- me.App.UpdateUserRoles(me.SystemAdminUser.Id, model.SYSTEM_USER_ROLE_ID+" "+model.SYSTEM_ADMIN_ROLE_ID, false)
- me.SystemAdminChannel = me.CreateChannel(me.SystemAdminClient, me.SystemAdminTeam)
-
- return me
-}
-
-func (me *TestHelper) waitForConnectivity() {
- for i := 0; i < 1000; i++ {
- conn, err := net.Dial("tcp", fmt.Sprintf("localhost:%v", me.App.Srv.ListenAddr.Port))
- if err == nil {
- conn.Close()
- return
- }
- time.Sleep(time.Millisecond * 20)
- }
- panic("unable to connect")
-}
-
-func (me *TestHelper) CreateClient() *model.Client {
- return model.NewClient(fmt.Sprintf("http://localhost:%v", me.App.Srv.ListenAddr.Port))
-}
-
-func (me *TestHelper) CreateWebSocketClient() (*model.WebSocketClient, *model.AppError) {
- return model.NewWebSocketClient(fmt.Sprintf("ws://localhost:%v", me.App.Srv.ListenAddr.Port), me.BasicClient.AuthToken)
-}
-
-func (me *TestHelper) CreateTeam(client *model.Client) *model.Team {
- id := model.NewId()
- team := &model.Team{
- DisplayName: "dn_" + id,
- Name: GenerateTestTeamName(),
- Email: me.GenerateTestEmail(),
- Type: model.TEAM_OPEN,
- }
-
- utils.DisableDebugLogForTest()
- r := client.Must(client.CreateTeam(team)).Data.(*model.Team)
- utils.EnableDebugLogForTest()
- return r
-}
-
-func (me *TestHelper) CreateUser(client *model.Client) *model.User {
- id := model.NewId()
-
- user := &model.User{
- Email: me.GenerateTestEmail(),
- Username: "un_" + id,
- Nickname: "nn_" + id,
- Password: "Password1",
- }
-
- utils.DisableDebugLogForTest()
- ruser := client.Must(client.CreateUser(user, "")).Data.(*model.User)
- ruser.Password = "Password1"
- store.Must(me.App.Srv.Store.User().VerifyEmail(ruser.Id))
- utils.EnableDebugLogForTest()
- return ruser
-}
-
-func (me *TestHelper) LinkUserToTeam(user *model.User, team *model.Team) {
- utils.DisableDebugLogForTest()
-
- err := me.App.JoinUserToTeam(team, user, "")
- if err != nil {
- mlog.Error(err.Error())
-
- time.Sleep(time.Second)
- panic(err)
- }
-
- utils.EnableDebugLogForTest()
-}
-
-func (me *TestHelper) UpdateUserToTeamAdmin(user *model.User, team *model.Team) {
- utils.DisableDebugLogForTest()
-
- tm := &model.TeamMember{TeamId: team.Id, UserId: user.Id, Roles: model.TEAM_USER_ROLE_ID + " " + model.TEAM_ADMIN_ROLE_ID}
- if tmr := <-me.App.Srv.Store.Team().UpdateMember(tm); tmr.Err != nil {
- utils.EnableDebugLogForTest()
- mlog.Error(tmr.Err.Error())
-
- time.Sleep(time.Second)
- panic(tmr.Err)
- }
- utils.EnableDebugLogForTest()
-}
-
-func (me *TestHelper) UpdateUserToNonTeamAdmin(user *model.User, team *model.Team) {
- utils.DisableDebugLogForTest()
-
- tm := &model.TeamMember{TeamId: team.Id, UserId: user.Id, Roles: model.TEAM_USER_ROLE_ID}
- if tmr := <-me.App.Srv.Store.Team().UpdateMember(tm); tmr.Err != nil {
- utils.EnableDebugLogForTest()
- mlog.Error(tmr.Err.Error())
-
- time.Sleep(time.Second)
- panic(tmr.Err)
- }
- utils.EnableDebugLogForTest()
-}
-
-func (me *TestHelper) MakeUserChannelAdmin(user *model.User, channel *model.Channel) {
- utils.DisableDebugLogForTest()
-
- if cmr := <-me.App.Srv.Store.Channel().GetMember(channel.Id, user.Id); cmr.Err == nil {
- cm := cmr.Data.(*model.ChannelMember)
- cm.Roles = "channel_admin channel_user"
- if sr := <-me.App.Srv.Store.Channel().UpdateMember(cm); sr.Err != nil {
- utils.EnableDebugLogForTest()
- panic(sr.Err)
- }
- } else {
- utils.EnableDebugLogForTest()
- panic(cmr.Err)
- }
-
- utils.EnableDebugLogForTest()
-}
-
-func (me *TestHelper) MakeUserChannelUser(user *model.User, channel *model.Channel) {
- utils.DisableDebugLogForTest()
-
- if cmr := <-me.App.Srv.Store.Channel().GetMember(channel.Id, user.Id); cmr.Err == nil {
- cm := cmr.Data.(*model.ChannelMember)
- cm.Roles = "channel_user"
- if sr := <-me.App.Srv.Store.Channel().UpdateMember(cm); sr.Err != nil {
- utils.EnableDebugLogForTest()
- panic(sr.Err)
- }
- } else {
- utils.EnableDebugLogForTest()
- panic(cmr.Err)
- }
-
- utils.EnableDebugLogForTest()
-}
-
-func (me *TestHelper) CreateChannel(client *model.Client, team *model.Team) *model.Channel {
- return me.createChannel(client, team, model.CHANNEL_OPEN)
-}
-
-func (me *TestHelper) CreatePrivateChannel(client *model.Client, team *model.Team) *model.Channel {
- return me.createChannel(client, team, model.CHANNEL_PRIVATE)
-}
-
-func (me *TestHelper) createChannel(client *model.Client, team *model.Team, channelType string) *model.Channel {
- id := model.NewId()
-
- channel := &model.Channel{
- DisplayName: "dn_" + id,
- Name: "name_" + id,
- Type: channelType,
- TeamId: team.Id,
- }
-
- utils.DisableDebugLogForTest()
- r := client.Must(client.CreateChannel(channel)).Data.(*model.Channel)
- utils.EnableDebugLogForTest()
- return r
-}
-
-func (me *TestHelper) CreatePost(client *model.Client, channel *model.Channel) *model.Post {
- id := model.NewId()
-
- post := &model.Post{
- ChannelId: channel.Id,
- Message: "message_" + id,
- }
-
- utils.DisableDebugLogForTest()
- r := client.Must(client.CreatePost(post)).Data.(*model.Post)
- utils.EnableDebugLogForTest()
- return r
-}
-
-func (me *TestHelper) CreatePinnedPost(client *model.Client, channel *model.Channel) *model.Post {
- id := model.NewId()
-
- post := &model.Post{
- ChannelId: channel.Id,
- Message: "message_" + id,
- IsPinned: true,
- }
-
- utils.DisableDebugLogForTest()
- r := client.Must(client.CreatePost(post)).Data.(*model.Post)
- utils.EnableDebugLogForTest()
- return r
-}
-
-func (me *TestHelper) LoginBasic() {
- utils.DisableDebugLogForTest()
- me.BasicClient.Must(me.BasicClient.Login(me.BasicUser.Email, me.BasicUser.Password))
- utils.EnableDebugLogForTest()
-}
-
-func (me *TestHelper) LoginBasic2() {
- utils.DisableDebugLogForTest()
- me.BasicClient.Must(me.BasicClient.Login(me.BasicUser2.Email, me.BasicUser2.Password))
- utils.EnableDebugLogForTest()
-}
-
-func (me *TestHelper) LoginSystemAdmin() {
- utils.DisableDebugLogForTest()
- me.SystemAdminClient.Must(me.SystemAdminClient.Login(me.SystemAdminUser.Email, me.SystemAdminUser.Password))
- utils.EnableDebugLogForTest()
-}
-
-func (me *TestHelper) GenerateTestEmail() string {
- if me.App.Config().EmailSettings.SMTPServer != "dockerhost" && os.Getenv("CI_INBUCKET_PORT") == "" {
- return strings.ToLower("success+" + model.NewId() + "@simulator.amazonses.com")
- }
- return strings.ToLower(model.NewId() + "@dockerhost")
-}
-
-func GenerateTestTeamName() string {
- return "faketeam" + model.NewRandomString(6)
-}
-
-func (me *TestHelper) TearDown() {
- me.App.Shutdown()
- os.Remove(me.tempConfigPath)
- if err := recover(); err != nil {
- StopTestStore()
- panic(err)
- }
-}
-
-func (me *TestHelper) SaveDefaultRolePermissions() map[string][]string {
- utils.DisableDebugLogForTest()
-
- results := make(map[string][]string)
-
- for _, roleName := range []string{
- "system_user",
- "system_admin",
- "team_user",
- "team_admin",
- "channel_user",
- "channel_admin",
- } {
- role, err1 := me.App.GetRoleByName(roleName)
- if err1 != nil {
- utils.EnableDebugLogForTest()
- panic(err1)
- }
-
- results[roleName] = role.Permissions
- }
-
- utils.EnableDebugLogForTest()
- return results
-}
-
-func (me *TestHelper) RestoreDefaultRolePermissions(data map[string][]string) {
- utils.DisableDebugLogForTest()
-
- for roleName, permissions := range data {
- role, err1 := me.App.GetRoleByName(roleName)
- if err1 != nil {
- utils.EnableDebugLogForTest()
- panic(err1)
- }
-
- if strings.Join(role.Permissions, " ") == strings.Join(permissions, " ") {
- continue
- }
-
- role.Permissions = permissions
-
- _, err2 := me.App.UpdateRole(role)
- if err2 != nil {
- utils.EnableDebugLogForTest()
- panic(err2)
- }
- }
-
- utils.EnableDebugLogForTest()
-}
-
-func (me *TestHelper) RemovePermissionFromRole(permission string, roleName string) {
- utils.DisableDebugLogForTest()
-
- role, err1 := me.App.GetRoleByName(roleName)
- if err1 != nil {
- utils.EnableDebugLogForTest()
- panic(err1)
- }
-
- var newPermissions []string
- for _, p := range role.Permissions {
- if p != permission {
- newPermissions = append(newPermissions, p)
- }
- }
-
- if strings.Join(role.Permissions, " ") == strings.Join(newPermissions, " ") {
- utils.EnableDebugLogForTest()
- return
- }
-
- role.Permissions = newPermissions
-
- _, err2 := me.App.UpdateRole(role)
- if err2 != nil {
- utils.EnableDebugLogForTest()
- panic(err2)
- }
-
- utils.EnableDebugLogForTest()
-}
-
-func (me *TestHelper) AddPermissionToRole(permission string, roleName string) {
- utils.DisableDebugLogForTest()
-
- role, err1 := me.App.GetRoleByName(roleName)
- if err1 != nil {
- utils.EnableDebugLogForTest()
- panic(err1)
- }
-
- for _, existingPermission := range role.Permissions {
- if existingPermission == permission {
- utils.EnableDebugLogForTest()
- return
- }
- }
-
- role.Permissions = append(role.Permissions, permission)
-
- _, err2 := me.App.UpdateRole(role)
- if err2 != nil {
- utils.EnableDebugLogForTest()
- panic(err2)
- }
-
- utils.EnableDebugLogForTest()
-}
diff --git a/api/channel.go b/api/channel.go
deleted file mode 100644
index 9c465412c..000000000
--- a/api/channel.go
+++ /dev/null
@@ -1,843 +0,0 @@
-// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-package api
-
-import (
- "fmt"
- "net/http"
- "strconv"
-
- "github.com/gorilla/mux"
- "github.com/mattermost/mattermost-server/mlog"
- "github.com/mattermost/mattermost-server/model"
-)
-
-func (api *API) InitChannel() {
- api.BaseRoutes.Channels.Handle("/", api.ApiUserRequired(getChannels)).Methods("GET")
- api.BaseRoutes.Channels.Handle("/more/{offset:[0-9]+}/{limit:[0-9]+}", api.ApiUserRequired(getMoreChannelsPage)).Methods("GET")
- api.BaseRoutes.Channels.Handle("/more/search", api.ApiUserRequired(searchMoreChannels)).Methods("POST")
- api.BaseRoutes.Channels.Handle("/counts", api.ApiUserRequired(getChannelCounts)).Methods("GET")
- api.BaseRoutes.Channels.Handle("/members", api.ApiUserRequired(getMyChannelMembers)).Methods("GET")
- api.BaseRoutes.Channels.Handle("/create", api.ApiUserRequired(createChannel)).Methods("POST")
- api.BaseRoutes.Channels.Handle("/view", api.ApiUserRequired(viewChannel)).Methods("POST")
- api.BaseRoutes.Channels.Handle("/create_direct", api.ApiUserRequired(createDirectChannel)).Methods("POST")
- api.BaseRoutes.Channels.Handle("/create_group", api.ApiUserRequired(createGroupChannel)).Methods("POST")
- api.BaseRoutes.Channels.Handle("/update", api.ApiUserRequired(updateChannel)).Methods("POST")
- api.BaseRoutes.Channels.Handle("/update_header", api.ApiUserRequired(updateChannelHeader)).Methods("POST")
- api.BaseRoutes.Channels.Handle("/update_purpose", api.ApiUserRequired(updateChannelPurpose)).Methods("POST")
- api.BaseRoutes.Channels.Handle("/update_notify_props", api.ApiUserRequired(updateNotifyProps)).Methods("POST")
- api.BaseRoutes.Channels.Handle("/autocomplete", api.ApiUserRequired(autocompleteChannels)).Methods("GET")
- api.BaseRoutes.Channels.Handle("/name/{channel_name:[A-Za-z0-9_-]+}", api.ApiUserRequired(getChannelByName)).Methods("GET")
-
- api.BaseRoutes.NeedChannelName.Handle("/join", api.ApiUserRequired(join)).Methods("POST")
-
- api.BaseRoutes.NeedChannel.Handle("/", api.ApiUserRequired(getChannel)).Methods("GET")
- api.BaseRoutes.NeedChannel.Handle("/stats", api.ApiUserRequired(getChannelStats)).Methods("GET")
- api.BaseRoutes.NeedChannel.Handle("/members/{user_id:[A-Za-z0-9]+}", api.ApiUserRequired(getChannelMember)).Methods("GET")
- api.BaseRoutes.NeedChannel.Handle("/members/ids", api.ApiUserRequired(getChannelMembersByIds)).Methods("POST")
- api.BaseRoutes.NeedChannel.Handle("/pinned", api.ApiUserRequired(getPinnedPosts)).Methods("GET")
- api.BaseRoutes.NeedChannel.Handle("/join", api.ApiUserRequired(join)).Methods("POST")
- api.BaseRoutes.NeedChannel.Handle("/leave", api.ApiUserRequired(leave)).Methods("POST")
- api.BaseRoutes.NeedChannel.Handle("/delete", api.ApiUserRequired(deleteChannel)).Methods("POST")
- api.BaseRoutes.NeedChannel.Handle("/add", api.ApiUserRequired(addMember)).Methods("POST")
- api.BaseRoutes.NeedChannel.Handle("/remove", api.ApiUserRequired(removeMember)).Methods("POST")
- api.BaseRoutes.NeedChannel.Handle("/update_member_roles", api.ApiUserRequired(updateChannelMemberRoles)).Methods("POST")
-}
-
-func createChannel(c *Context, w http.ResponseWriter, r *http.Request) {
- channel := model.ChannelFromJson(r.Body)
- if channel == nil {
- c.SetInvalidParam("createChannel", "channel")
- return
- }
-
- if len(channel.TeamId) == 0 {
- channel.TeamId = c.TeamId
- }
-
- if channel.Type == model.CHANNEL_OPEN && !c.App.SessionHasPermissionToTeam(c.Session, channel.TeamId, model.PERMISSION_CREATE_PUBLIC_CHANNEL) {
- c.SetPermissionError(model.PERMISSION_CREATE_PUBLIC_CHANNEL)
- return
- }
-
- if channel.Type == model.CHANNEL_PRIVATE && !c.App.SessionHasPermissionToTeam(c.Session, channel.TeamId, model.PERMISSION_CREATE_PRIVATE_CHANNEL) {
- c.SetPermissionError(model.PERMISSION_CREATE_PRIVATE_CHANNEL)
- return
- }
-
- if sc, err := c.App.CreateChannelWithUser(channel, c.Session.UserId); err != nil {
- c.Err = err
- return
- } else {
- c.LogAudit("name=" + channel.Name)
- w.Write([]byte(sc.ToJson()))
- }
-}
-
-func createDirectChannel(c *Context, w http.ResponseWriter, r *http.Request) {
- if !c.App.SessionHasPermissionTo(c.Session, model.PERMISSION_CREATE_DIRECT_CHANNEL) {
- c.SetPermissionError(model.PERMISSION_CREATE_DIRECT_CHANNEL)
- return
- }
-
- data := model.MapFromJson(r.Body)
-
- userId := data["user_id"]
- if len(userId) != 26 {
- c.SetInvalidParam("createDirectChannel", "user_id")
- return
- }
-
- if sc, err := c.App.CreateDirectChannel(c.Session.UserId, userId); err != nil {
- c.Err = err
- return
- } else {
- w.Write([]byte(sc.ToJson()))
- }
-}
-
-func createGroupChannel(c *Context, w http.ResponseWriter, r *http.Request) {
- if !c.App.SessionHasPermissionTo(c.Session, model.PERMISSION_CREATE_GROUP_CHANNEL) {
- c.SetPermissionError(model.PERMISSION_CREATE_GROUP_CHANNEL)
- return
- }
-
- userIds := model.ArrayFromJson(r.Body)
- if len(userIds) == 0 {
- c.SetInvalidParam("createGroupChannel", "user_ids")
- return
- }
-
- found := false
- for _, id := range userIds {
- if id == c.Session.UserId {
- found = true
- break
- }
- }
-
- if !found {
- userIds = append(userIds, c.Session.UserId)
- }
-
- if sc, err := c.App.CreateGroupChannel(userIds, c.Session.UserId); err != nil {
- c.Err = err
- return
- } else {
- w.Write([]byte(sc.ToJson()))
- }
-}
-
-func CanManageChannel(c *Context, channel *model.Channel) bool {
- if channel.Type == model.CHANNEL_OPEN && !c.App.SessionHasPermissionToChannel(c.Session, channel.Id, model.PERMISSION_MANAGE_PUBLIC_CHANNEL_PROPERTIES) {
- c.SetPermissionError(model.PERMISSION_MANAGE_PUBLIC_CHANNEL_PROPERTIES)
- return false
- }
-
- if channel.Type == model.CHANNEL_PRIVATE && !c.App.SessionHasPermissionToChannel(c.Session, channel.Id, model.PERMISSION_MANAGE_PRIVATE_CHANNEL_PROPERTIES) {
- c.SetPermissionError(model.PERMISSION_MANAGE_PRIVATE_CHANNEL_PROPERTIES)
- return false
- }
-
- return true
-}
-
-func updateChannel(c *Context, w http.ResponseWriter, r *http.Request) {
-
- channel := model.ChannelFromJson(r.Body)
-
- if channel == nil {
- c.SetInvalidParam("updateChannel", "channel")
- return
- }
-
- var oldChannel *model.Channel
- var err *model.AppError
- if oldChannel, err = c.App.GetChannel(channel.Id); err != nil {
- c.Err = err
- return
- }
-
- if _, err = c.App.GetChannelMember(channel.Id, c.Session.UserId); err != nil {
- c.Err = err
- return
- }
-
- if !CanManageChannel(c, channel) {
- return
- }
-
- if oldChannel.DeleteAt > 0 {
- c.Err = model.NewAppError("updateChannel", "api.channel.update_channel.deleted.app_error", nil, "", http.StatusBadRequest)
- return
- }
-
- if oldChannel.Name == model.DEFAULT_CHANNEL {
- if (len(channel.Name) > 0 && channel.Name != oldChannel.Name) || (len(channel.Type) > 0 && channel.Type != oldChannel.Type) {
- c.Err = model.NewAppError("updateChannel", "api.channel.update_channel.tried.app_error", map[string]interface{}{"Channel": model.DEFAULT_CHANNEL}, "", http.StatusBadRequest)
- return
- }
- }
-
- oldChannel.Header = channel.Header
- oldChannel.Purpose = channel.Purpose
-
- oldChannelDisplayName := oldChannel.DisplayName
-
- if len(channel.DisplayName) > 0 {
- oldChannel.DisplayName = channel.DisplayName
- }
-
- if len(channel.Name) > 0 {
- oldChannel.Name = channel.Name
- }
-
- if len(channel.Type) > 0 {
- oldChannel.Type = channel.Type
- }
-
- if _, err := c.App.UpdateChannel(oldChannel); err != nil {
- c.Err = err
- return
- } else {
- if oldChannelDisplayName != channel.DisplayName {
- if err := c.App.PostUpdateChannelDisplayNameMessage(c.Session.UserId, channel, oldChannelDisplayName, channel.DisplayName); err != nil {
- mlog.Error(err.Error())
- }
- }
- c.LogAudit("name=" + channel.Name)
- w.Write([]byte(oldChannel.ToJson()))
- }
-
-}
-
-func updateChannelHeader(c *Context, w http.ResponseWriter, r *http.Request) {
-
- props := model.MapFromJson(r.Body)
- channelId := props["channel_id"]
- if len(channelId) != 26 {
- c.SetInvalidParam("updateChannelHeader", "channel_id")
- return
- }
-
- channelHeader := props["channel_header"]
- if len(channelHeader) > 1024 {
- c.SetInvalidParam("updateChannelHeader", "channel_header")
- return
- }
-
- var channel *model.Channel
- var err *model.AppError
- if channel, err = c.App.GetChannel(channelId); err != nil {
- c.Err = err
- return
- }
-
- if _, err = c.App.GetChannelMember(channelId, c.Session.UserId); err != nil {
- c.Err = err
- return
- }
-
- if !CanManageChannel(c, channel) {
- return
- }
-
- oldChannelHeader := channel.Header
- channel.Header = channelHeader
-
- if _, err := c.App.UpdateChannel(channel); err != nil {
- c.Err = err
- return
- } else {
- if err := c.App.PostUpdateChannelHeaderMessage(c.Session.UserId, channel, oldChannelHeader, channelHeader); err != nil {
- mlog.Error(err.Error())
- }
- c.LogAudit("name=" + channel.Name)
- w.Write([]byte(channel.ToJson()))
- }
-}
-
-func updateChannelPurpose(c *Context, w http.ResponseWriter, r *http.Request) {
-
- props := model.MapFromJson(r.Body)
- channelId := props["channel_id"]
- if len(channelId) != 26 {
- c.SetInvalidParam("updateChannelPurpose", "channel_id")
- return
- }
-
- channelPurpose := props["channel_purpose"]
- if len(channelPurpose) > 1024 {
- c.SetInvalidParam("updateChannelPurpose", "channel_purpose")
- return
- }
-
- var channel *model.Channel
- var err *model.AppError
- if channel, err = c.App.GetChannel(channelId); err != nil {
- c.Err = err
- return
- }
-
- if _, err = c.App.GetChannelMember(channelId, c.Session.UserId); err != nil {
- c.Err = err
- return
- }
-
- if !CanManageChannel(c, channel) {
- return
- }
-
- oldChannelPurpose := channel.Purpose
- channel.Purpose = channelPurpose
-
- if _, err := c.App.UpdateChannel(channel); err != nil {
- c.Err = err
- return
- } else {
- if err := c.App.PostUpdateChannelPurposeMessage(c.Session.UserId, channel, oldChannelPurpose, channelPurpose); err != nil {
- mlog.Error(err.Error())
- }
- c.LogAudit("name=" + channel.Name)
- w.Write([]byte(channel.ToJson()))
- }
-}
-
-func getChannels(c *Context, w http.ResponseWriter, r *http.Request) {
- if c.TeamId == "" {
- c.Err = model.NewAppError("", "api.context.missing_teamid.app_error", nil, "TeamIdRequired", http.StatusBadRequest)
- return
- }
- // user is already in the team
- // Get's all channels the user is a member of
-
- if channels, err := c.App.GetChannelsForUser(c.TeamId, c.Session.UserId); err != nil {
- if err.Id == "store.sql_channel.get_channels.not_found.app_error" {
- // lets make sure the user is valid
- if _, err := c.App.GetUser(c.Session.UserId); err != nil {
- c.Err = err
- c.RemoveSessionCookie(w, r)
- mlog.Error(fmt.Sprintf("Error in getting users profile for id=%v forcing logout", c.Session.UserId), mlog.String("user_id", c.Session.UserId))
- return
- }
- }
- c.Err = err
- return
- } else if c.HandleEtag(channels.Etag(), "Get Channels", w, r) {
- return
- } else {
- w.Header().Set(model.HEADER_ETAG_SERVER, channels.Etag())
- w.Write([]byte(channels.ToJson()))
- }
-}
-
-func getMoreChannelsPage(c *Context, w http.ResponseWriter, r *http.Request) {
- params := mux.Vars(r)
-
- offset, err := strconv.Atoi(params["offset"])
- if err != nil {
- c.SetInvalidParam("getProfiles", "offset")
- return
- }
-
- limit, err := strconv.Atoi(params["limit"])
- if err != nil {
- c.SetInvalidParam("getProfiles", "limit")
- return
- }
-
- // user is already in the team
- if !c.App.SessionHasPermissionToTeam(c.Session, c.TeamId, model.PERMISSION_LIST_TEAM_CHANNELS) {
- c.SetPermissionError(model.PERMISSION_LIST_TEAM_CHANNELS)
- return
- }
-
- if channels, err := c.App.GetChannelsUserNotIn(c.TeamId, c.Session.UserId, offset, limit); err != nil {
- c.Err = err
- return
- } else {
- w.Header().Set(model.HEADER_ETAG_SERVER, channels.Etag())
- w.Write([]byte(channels.ToJson()))
- }
-}
-
-func getChannelCounts(c *Context, w http.ResponseWriter, r *http.Request) {
-
- // user is already in the team
-
- if counts, err := c.App.GetChannelCounts(c.TeamId, c.Session.UserId); err != nil {
- c.Err = model.NewAppError("getChannelCounts", "api.channel.get_channel_counts.app_error", nil, err.Message, http.StatusInternalServerError)
- return
- } else if c.HandleEtag(counts.Etag(), "Get Channel Counts", w, r) {
- return
- } else {
- w.Header().Set(model.HEADER_ETAG_SERVER, counts.Etag())
- w.Write([]byte(counts.ToJson()))
- }
-}
-
-func join(c *Context, w http.ResponseWriter, r *http.Request) {
-
- params := mux.Vars(r)
- channelId := params["channel_id"]
- channelName := params["channel_name"]
-
- var channel *model.Channel
- var err *model.AppError
- if channelId != "" {
- channel, err = c.App.GetChannel(channelId)
- } else if channelName != "" {
- channel, err = c.App.GetChannelByName(channelName, c.TeamId)
- } else {
- c.SetInvalidParam("join", "channel_id, channel_name")
- return
- }
-
- if err != nil {
- c.Err = err
- return
- }
-
- if channel.Type == model.CHANNEL_OPEN {
- if !c.App.SessionHasPermissionToTeam(c.Session, channel.TeamId, model.PERMISSION_JOIN_PUBLIC_CHANNELS) {
- c.SetPermissionError(model.PERMISSION_JOIN_PUBLIC_CHANNELS)
- return
- }
- }
-
- if err = c.App.JoinChannel(channel, c.Session.UserId); err != nil {
- c.Err = err
- return
- }
-
- w.Write([]byte(channel.ToJson()))
-}
-
-func leave(c *Context, w http.ResponseWriter, r *http.Request) {
-
- params := mux.Vars(r)
- id := params["channel_id"]
-
- err := c.App.LeaveChannel(id, c.Session.UserId)
- if err != nil {
- c.Err = err
- return
- }
-
- result := make(map[string]string)
- result["id"] = id
- w.Write([]byte(model.MapToJson(result)))
-}
-
-func deleteChannel(c *Context, w http.ResponseWriter, r *http.Request) {
-
- params := mux.Vars(r)
- id := params["channel_id"]
-
- var channel *model.Channel
- var err *model.AppError
- if channel, err = c.App.GetChannel(id); err != nil {
- c.Err = err
- return
- }
-
- if channel.Type == model.CHANNEL_OPEN && !c.App.SessionHasPermissionToChannel(c.Session, channel.Id, model.PERMISSION_DELETE_PUBLIC_CHANNEL) {
- c.SetPermissionError(model.PERMISSION_DELETE_PUBLIC_CHANNEL)
- return
- }
-
- if channel.Type == model.CHANNEL_PRIVATE && !c.App.SessionHasPermissionToChannel(c.Session, channel.Id, model.PERMISSION_DELETE_PRIVATE_CHANNEL) {
- c.SetPermissionError(model.PERMISSION_DELETE_PRIVATE_CHANNEL)
- return
- }
-
- err = c.App.DeleteChannel(channel, c.Session.UserId)
- if err != nil {
- c.Err = err
- return
- }
-
- c.LogAudit("name=" + channel.Name)
-
- result := make(map[string]string)
- result["id"] = channel.Id
- w.Write([]byte(model.MapToJson(result)))
-}
-
-func getChannel(c *Context, w http.ResponseWriter, r *http.Request) {
- params := mux.Vars(r)
- id := params["channel_id"]
-
- var channel *model.Channel
- var err *model.AppError
- if channel, err = c.App.GetChannel(id); err != nil {
- c.Err = err
- return
- }
-
- if channel.TeamId != c.TeamId && !channel.IsGroupOrDirect() {
- c.Err = model.NewAppError("getChannel", "api.channel.get_channel.wrong_team.app_error", map[string]interface{}{"ChannelId": id, "TeamId": c.TeamId}, "", http.StatusBadRequest)
- return
- }
-
- var member *model.ChannelMember
- if member, err = c.App.GetChannelMember(id, c.Session.UserId); err != nil {
- c.Err = err
- return
- }
-
- data := &model.ChannelData{}
- data.Channel = channel
- data.Member = member
-
- if c.HandleEtag(data.Etag(), "Get Channel", w, r) {
- return
- } else {
- w.Header().Set(model.HEADER_ETAG_SERVER, data.Etag())
- w.Write([]byte(data.ToJson()))
- }
-}
-
-func getChannelByName(c *Context, w http.ResponseWriter, r *http.Request) {
- params := mux.Vars(r)
- channelName := params["channel_name"]
-
- if channel, err := c.App.GetChannelByName(channelName, c.TeamId); err != nil {
- c.Err = err
- return
- } else {
- if !c.App.SessionHasPermissionToChannel(c.Session, channel.Id, model.PERMISSION_READ_CHANNEL) {
- c.SetPermissionError(model.PERMISSION_READ_CHANNEL)
- return
- }
-
- if channel.TeamId != c.TeamId && !channel.IsGroupOrDirect() {
- c.Err = model.NewAppError("getChannel", "api.channel.get_channel.wrong_team.app_error", map[string]interface{}{"ChannelName": channelName, "TeamId": c.TeamId}, "", http.StatusBadRequest)
- return
- }
-
- if c.HandleEtag(channel.Etag(), "Get Channel By Name", w, r) {
- return
- } else {
- w.Header().Set(model.HEADER_ETAG_SERVER, channel.Etag())
- w.Write([]byte(channel.ToJson()))
- }
- }
-}
-
-func getChannelStats(c *Context, w http.ResponseWriter, r *http.Request) {
- params := mux.Vars(r)
- id := params["channel_id"]
-
- var channel *model.Channel
- var err *model.AppError
- if channel, err = c.App.GetChannel(id); err != nil {
- c.Err = err
- return
- }
-
- if channel.DeleteAt > 0 {
- c.Err = model.NewAppError("getChannelStats", "api.channel.get_channel_extra_info.deleted.app_error", nil, "", http.StatusBadRequest)
- return
- }
-
- if !c.App.SessionHasPermissionToChannel(c.Session, channel.Id, model.PERMISSION_READ_CHANNEL) {
- c.SetPermissionError(model.PERMISSION_READ_CHANNEL)
- return
- }
-
- if memberCount, err := c.App.GetChannelMemberCount(id); err != nil {
- c.Err = err
- return
- } else {
- stats := model.ChannelStats{ChannelId: channel.Id, MemberCount: memberCount}
- w.Write([]byte(stats.ToJson()))
- }
-}
-
-func getChannelMember(c *Context, w http.ResponseWriter, r *http.Request) {
- params := mux.Vars(r)
- channelId := params["channel_id"]
- userId := params["user_id"]
-
- if !c.App.SessionHasPermissionToChannel(c.Session, channelId, model.PERMISSION_READ_CHANNEL) {
- c.SetPermissionError(model.PERMISSION_READ_CHANNEL)
- return
- }
-
- if member, err := c.App.GetChannelMember(channelId, userId); err != nil {
- c.Err = err
- return
- } else {
- w.Write([]byte(member.ToJson()))
- }
-}
-
-func getMyChannelMembers(c *Context, w http.ResponseWriter, r *http.Request) {
- if members, err := c.App.GetChannelMembersForUser(c.TeamId, c.Session.UserId); err != nil {
- c.Err = err
- return
- } else {
- w.Write([]byte(members.ToJson()))
- }
-}
-
-func getPinnedPosts(c *Context, w http.ResponseWriter, r *http.Request) {
- params := mux.Vars(r)
- channelId := params["channel_id"]
-
- if result := <-c.App.Srv.Store.Channel().GetPinnedPosts(channelId); result.Err != nil {
- c.Err = result.Err
- return
- } else {
- posts := result.Data.(*model.PostList)
- w.Write([]byte(posts.ToJson()))
- }
-
-}
-
-func addMember(c *Context, w http.ResponseWriter, r *http.Request) {
- params := mux.Vars(r)
- id := params["channel_id"]
-
- data := model.MapFromJson(r.Body)
- userId := data["user_id"]
-
- if len(userId) != 26 {
- c.SetInvalidParam("addMember", "user_id")
- return
- }
-
- var channel *model.Channel
- var err *model.AppError
- if channel, err = c.App.GetChannel(id); err != nil {
- c.Err = err
- return
- }
-
- if channel.Type == model.CHANNEL_OPEN && !c.App.SessionHasPermissionToChannel(c.Session, channel.Id, model.PERMISSION_MANAGE_PUBLIC_CHANNEL_MEMBERS) {
- c.SetPermissionError(model.PERMISSION_MANAGE_PUBLIC_CHANNEL_MEMBERS)
- return
- }
-
- if channel.Type == model.CHANNEL_PRIVATE && !c.App.SessionHasPermissionToChannel(c.Session, channel.Id, model.PERMISSION_MANAGE_PRIVATE_CHANNEL_MEMBERS) {
- c.SetPermissionError(model.PERMISSION_MANAGE_PRIVATE_CHANNEL_MEMBERS)
- return
- }
-
- var nUser *model.User
- if nUser, err = c.App.GetUser(userId); err != nil {
- c.Err = model.NewAppError("addMember", "api.channel.add_member.find_user.app_error", nil, err.Error(), http.StatusBadRequest)
- return
- }
-
- cm, err := c.App.AddUserToChannel(nUser, channel)
- if err != nil {
- c.Err = err
- return
- }
-
- c.LogAudit("name=" + channel.Name + " user_id=" + userId)
-
- var oUser *model.User
- if oUser, err = c.App.GetUser(c.Session.UserId); err != nil {
- c.Err = model.NewAppError("addMember", "api.channel.add_member.user_adding.app_error", nil, err.Error(), http.StatusInternalServerError)
- return
- }
-
- c.App.Go(func() {
- c.App.PostAddToChannelMessage(oUser, nUser, channel, "")
- })
-
- c.App.UpdateChannelLastViewedAt([]string{id}, oUser.Id)
- w.Write([]byte(cm.ToJson()))
-}
-
-func removeMember(c *Context, w http.ResponseWriter, r *http.Request) {
- params := mux.Vars(r)
- channelId := params["channel_id"]
-
- data := model.MapFromJson(r.Body)
- userIdToRemove := data["user_id"]
-
- if len(userIdToRemove) != 26 {
- c.SetInvalidParam("removeMember", "user_id")
- return
- }
-
- var channel *model.Channel
- var err *model.AppError
- if channel, err = c.App.GetChannel(channelId); err != nil {
- c.Err = err
- return
- }
-
- if channel.Type == model.CHANNEL_OPEN && !c.App.SessionHasPermissionToChannel(c.Session, channel.Id, model.PERMISSION_MANAGE_PUBLIC_CHANNEL_MEMBERS) {
- c.SetPermissionError(model.PERMISSION_MANAGE_PUBLIC_CHANNEL_MEMBERS)
- return
- }
-
- if channel.Type == model.CHANNEL_PRIVATE && !c.App.SessionHasPermissionToChannel(c.Session, channel.Id, model.PERMISSION_MANAGE_PRIVATE_CHANNEL_MEMBERS) {
- c.SetPermissionError(model.PERMISSION_MANAGE_PRIVATE_CHANNEL_MEMBERS)
- return
- }
-
- if err = c.App.RemoveUserFromChannel(userIdToRemove, c.Session.UserId, channel); err != nil {
- c.Err = err
- return
- }
-
- c.LogAudit("name=" + channel.Name + " user_id=" + userIdToRemove)
-
- result := make(map[string]string)
- result["channel_id"] = channel.Id
- result["removed_user_id"] = userIdToRemove
- w.Write([]byte(model.MapToJson(result)))
-}
-
-func updateNotifyProps(c *Context, w http.ResponseWriter, r *http.Request) {
- data := model.MapFromJson(r.Body)
-
- userId := data["user_id"]
- if len(userId) != 26 {
- c.SetInvalidParam("updateNotifyProps", "user_id")
- return
- }
-
- channelId := data["channel_id"]
- if len(channelId) != 26 {
- c.SetInvalidParam("updateNotifyProps", "channel_id")
- return
- }
-
- if !c.App.SessionHasPermissionToUser(c.Session, userId) {
- c.SetPermissionError(model.PERMISSION_EDIT_OTHER_USERS)
- return
- }
-
- member, err := c.App.UpdateChannelMemberNotifyProps(data, channelId, userId)
- if err != nil {
- c.Err = err
- return
- }
-
- w.Write([]byte(model.MapToJson(member.NotifyProps)))
-}
-
-func searchMoreChannels(c *Context, w http.ResponseWriter, r *http.Request) {
- props := model.ChannelSearchFromJson(r.Body)
- if props == nil {
- c.SetInvalidParam("searchMoreChannels", "")
- return
- }
-
- if c.Session.GetTeamByTeamId(c.TeamId) == nil {
- if !c.App.SessionHasPermissionTo(c.Session, model.PERMISSION_MANAGE_SYSTEM) {
- c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM)
- return
- }
- }
-
- if len(props.Term) == 0 {
- c.SetInvalidParam("searchMoreChannels", "term")
- return
- }
-
- if channels, err := c.App.SearchChannelsUserNotIn(c.TeamId, c.Session.UserId, props.Term); err != nil {
- c.Err = err
- return
- } else {
- w.Write([]byte(channels.ToJson()))
- }
-}
-
-func autocompleteChannels(c *Context, w http.ResponseWriter, r *http.Request) {
- term := r.URL.Query().Get("term")
-
- if c.Session.GetTeamByTeamId(c.TeamId) == nil {
- if !c.App.SessionHasPermissionTo(c.Session, model.PERMISSION_MANAGE_SYSTEM) {
- c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM)
- return
- }
- }
-
- if channels, err := c.App.SearchChannels(c.TeamId, term); err != nil {
- c.Err = err
- return
- } else {
- w.Write([]byte(channels.ToJson()))
- }
-
-}
-
-func viewChannel(c *Context, w http.ResponseWriter, r *http.Request) {
- view := model.ChannelViewFromJson(r.Body)
- if view == nil {
- c.SetInvalidParam("viewChannel", "channel_view")
- return
- }
-
- if _, err := c.App.ViewChannel(view, c.Session.UserId, !c.Session.IsMobileApp()); err != nil {
- c.Err = err
- return
- }
-
- ReturnStatusOK(w)
-}
-
-func getChannelMembersByIds(c *Context, w http.ResponseWriter, r *http.Request) {
- params := mux.Vars(r)
- channelId := params["channel_id"]
-
- userIds := model.ArrayFromJson(r.Body)
- if len(userIds) == 0 {
- c.SetInvalidParam("getChannelMembersByIds", "user_ids")
- return
- }
-
- if !c.App.SessionHasPermissionToChannel(c.Session, channelId, model.PERMISSION_READ_CHANNEL) {
- c.SetPermissionError(model.PERMISSION_READ_CHANNEL)
- return
- }
-
- if members, err := c.App.GetChannelMembersByIds(channelId, userIds); err != nil {
- c.Err = err
- return
- } else {
- w.Write([]byte(members.ToJson()))
- }
-}
-
-func updateChannelMemberRoles(c *Context, w http.ResponseWriter, r *http.Request) {
- params := mux.Vars(r)
- channelId := params["channel_id"]
-
- props := model.MapFromJson(r.Body)
-
- userId := props["user_id"]
- if len(userId) != 26 {
- c.SetInvalidParam("updateChannelMemberRoles", "user_id")
- return
- }
-
- if !c.App.SessionHasPermissionToChannel(c.Session, channelId, model.PERMISSION_MANAGE_CHANNEL_ROLES) {
- c.SetPermissionError(model.PERMISSION_MANAGE_CHANNEL_ROLES)
- return
- }
-
- newRoles := props["new_roles"]
- if !(model.IsValidUserRoles(newRoles)) {
- c.SetInvalidParam("updateChannelMemberRoles", "new_roles")
- return
- }
-
- if _, err := c.App.UpdateChannelMemberRoles(channelId, userId, newRoles); err != nil {
- c.Err = err
- return
- }
-
- rdata := map[string]string{}
- rdata["status"] = "ok"
- w.Write([]byte(model.MapToJson(rdata)))
-}
diff --git a/api/channel_test.go b/api/channel_test.go
deleted file mode 100644
index 2642eb9ff..000000000
--- a/api/channel_test.go
+++ /dev/null
@@ -1,2007 +0,0 @@
-// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-package api
-
-import (
- "net/http"
- "strings"
- "testing"
- "time"
-
- "github.com/mattermost/mattermost-server/model"
- "github.com/mattermost/mattermost-server/store"
-)
-
-func TestCreateChannel(t *testing.T) {
- th := Setup().InitBasic().InitSystemAdmin()
- defer th.TearDown()
-
- Client := th.BasicClient
- team := th.BasicTeam
- th.LoginBasic2()
- team2 := th.CreateTeam(th.BasicClient)
- th.LoginBasic()
- th.BasicClient.SetTeamId(team.Id)
-
- channel := model.Channel{DisplayName: "Test API Name", Name: "zz" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
- rchannel, err := Client.CreateChannel(&channel)
- if err != nil {
- t.Fatal(err)
- }
-
- if rchannel.Data.(*model.Channel).Name != channel.Name {
- t.Fatal("full name didn't match")
- }
-
- rget := Client.Must(Client.GetChannels("")).Data.(*model.ChannelList)
- nameMatch := false
- for _, c := range *rget {
- if c.Name == channel.Name {
- nameMatch = true
- }
- }
-
- if !nameMatch {
- t.Fatal("Did not create channel with correct name")
- }
-
- if _, err := Client.CreateChannel(rchannel.Data.(*model.Channel)); err == nil {
- t.Fatal("Cannot create an existing")
- }
-
- savedId := rchannel.Data.(*model.Channel).Id
-
- rchannel.Data.(*model.Channel).Id = ""
- if _, err := Client.CreateChannel(rchannel.Data.(*model.Channel)); err != nil {
- if err.Id != "store.sql_channel.save_channel.exists.app_error" {
- t.Fatal(err)
- }
- }
-
- if _, err := Client.DoApiPost(Client.GetTeamRoute()+"/channels/create", "garbage"); err == nil {
- t.Fatal("should have been an error")
- }
-
- Client.DeleteChannel(savedId)
- if _, err := Client.CreateChannel(rchannel.Data.(*model.Channel)); err != nil {
- if err.Message != "A channel with that URL was previously created" {
- t.Fatal(err)
- }
- }
-
- channel = model.Channel{DisplayName: "Channel on Different Team", Name: "aaaa" + model.NewId() + "abbb", Type: model.CHANNEL_OPEN, TeamId: team2.Id}
-
- if _, err := Client.CreateChannel(&channel); err.StatusCode != http.StatusForbidden {
- t.Fatal(err)
- }
-
- channel = model.Channel{DisplayName: "Channel With No TeamId", Name: "aaaa" + model.NewId() + "abbb", Type: model.CHANNEL_OPEN, TeamId: ""}
-
- if _, err := Client.CreateChannel(&channel); err != nil {
- t.Fatal(err)
- }
-
- channel = model.Channel{DisplayName: "Test API Name", Name: model.NewId() + "__" + model.NewId(), Type: model.CHANNEL_OPEN, TeamId: team.Id}
-
- if _, err := Client.CreateChannel(&channel); err == nil {
- t.Fatal("Should have errored out on invalid '__' character")
- }
-
- channel = model.Channel{DisplayName: "Test API Name", Name: "zz" + model.NewId() + "a", Type: model.CHANNEL_DIRECT, TeamId: team.Id}
-
- if _, err := Client.CreateChannel(&channel); err == nil {
- t.Fatal("Should have errored out on direct channel type")
- }
-
- // Check the appropriate permissions are enforced.
- defaultRolePermissions := th.SaveDefaultRolePermissions()
- defer func() {
- th.RestoreDefaultRolePermissions(defaultRolePermissions)
- }()
-
- th.AddPermissionToRole(model.PERMISSION_CREATE_PUBLIC_CHANNEL.Id, model.TEAM_USER_ROLE_ID)
- th.AddPermissionToRole(model.PERMISSION_CREATE_PRIVATE_CHANNEL.Id, model.TEAM_USER_ROLE_ID)
-
- channel2 := &model.Channel{DisplayName: "Test API Name", Name: "zz" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
- channel3 := &model.Channel{DisplayName: "Test API Name", Name: "zz" + model.NewId() + "a", Type: model.CHANNEL_PRIVATE, TeamId: team.Id}
- if _, err := Client.CreateChannel(channel2); err != nil {
- t.Fatal(err)
- }
- if _, err := Client.CreateChannel(channel3); err != nil {
- t.Fatal(err)
- }
-
- th.RemovePermissionFromRole(model.PERMISSION_CREATE_PUBLIC_CHANNEL.Id, model.TEAM_USER_ROLE_ID)
- th.RemovePermissionFromRole(model.PERMISSION_CREATE_PRIVATE_CHANNEL.Id, model.TEAM_USER_ROLE_ID)
- th.AddPermissionToRole(model.PERMISSION_CREATE_PUBLIC_CHANNEL.Id, model.TEAM_ADMIN_ROLE_ID)
- th.AddPermissionToRole(model.PERMISSION_CREATE_PRIVATE_CHANNEL.Id, model.TEAM_ADMIN_ROLE_ID)
-
- th.LoginBasic2()
- channel2.Name = "zz" + model.NewId() + "a"
- channel3.Name = "zz" + model.NewId() + "a"
- if _, err := Client.CreateChannel(channel2); err == nil {
- t.Fatal("should have errored not team admin")
- }
- if _, err := Client.CreateChannel(channel3); err == nil {
- t.Fatal("should have errored not team admin")
- }
-
- th.UpdateUserToTeamAdmin(th.BasicUser, team)
- Client.Logout()
- th.LoginBasic()
- Client.SetTeamId(team.Id)
-
- if _, err := Client.CreateChannel(channel2); err != nil {
- t.Fatal(err)
- }
- if _, err := Client.CreateChannel(channel3); err != nil {
- t.Fatal(err)
- }
-}
-
-func TestCreateDirectChannel(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- Client := th.BasicClient
- user := th.BasicUser
- user2 := th.BasicUser2
-
- var channel *model.Channel
- if result, err := Client.CreateDirectChannel(th.BasicUser2.Id); err != nil {
- t.Fatal(err)
- } else {
- channel = result.Data.(*model.Channel)
- }
-
- channelName := ""
- if user2.Id > user.Id {
- channelName = user.Id + "__" + user2.Id
- } else {
- channelName = user2.Id + "__" + user.Id
- }
-
- if channel.Name != channelName {
- t.Fatal("channel name didn't match")
- }
-
- if channel.Type != model.CHANNEL_DIRECT {
- t.Fatal("channel type was not direct")
- }
-
- // Don't fail on direct channels already existing and return the original channel again
- if result, err := Client.CreateDirectChannel(th.BasicUser2.Id); err != nil {
- t.Fatal(err)
- } else if result.Data.(*model.Channel).Id != channel.Id {
- t.Fatal("didn't return original direct channel when saving a duplicate")
- }
-
- if _, err := Client.CreateDirectChannel("junk"); err == nil {
- t.Fatal("should have failed with bad user id")
- }
-
- if _, err := Client.CreateDirectChannel("12345678901234567890123456"); err == nil {
- t.Fatal("should have failed with non-existent user")
- }
-}
-
-func TestCreateGroupChannel(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- Client := th.BasicClient
- user := th.BasicUser
- user2 := th.BasicUser2
- user3 := th.CreateUser(Client)
-
- userIds := []string{user.Id, user2.Id, user3.Id}
-
- var channel *model.Channel
- if result, err := Client.CreateGroupChannel(userIds); err != nil {
- t.Fatal(err)
- } else {
- channel = result.Data.(*model.Channel)
- }
-
- if channel.Type != model.CHANNEL_GROUP {
- t.Fatal("channel type was not group")
- }
-
- // Don't fail on group channels already existing and return the original channel again
- if result, err := Client.CreateGroupChannel(userIds); err != nil {
- t.Fatal(err)
- } else if result.Data.(*model.Channel).Id != channel.Id {
- t.Fatal("didn't return original group channel when saving a duplicate")
- }
-
- if _, err := Client.CreateGroupChannel([]string{user.Id}); err == nil {
- t.Fatal("should have failed with not enough users")
- }
-
- if _, err := Client.CreateGroupChannel([]string{}); err == nil {
- t.Fatal("should have failed with not enough users")
- }
-
- if _, err := Client.CreateGroupChannel([]string{user.Id, user2.Id, user3.Id, "junk"}); err == nil {
- t.Fatal("should have failed with non-existent user")
- }
-}
-
-func TestUpdateChannel(t *testing.T) {
- th := Setup().InitBasic().InitSystemAdmin()
- defer th.TearDown()
-
- Client := th.SystemAdminClient
- team := th.SystemAdminTeam
- sysAdminUser := th.SystemAdminUser
- user := th.CreateUser(Client)
- th.LinkUserToTeam(user, team)
- user2 := th.CreateUser(Client)
- th.LinkUserToTeam(user2, team)
-
- Client.Login(user.Email, user.Password)
-
- channel1 := &model.Channel{DisplayName: "A Test API Name", Name: "zz" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
- channel1 = Client.Must(Client.CreateChannel(channel1)).Data.(*model.Channel)
-
- Client.AddChannelMember(channel1.Id, user.Id)
-
- header := "zz" + model.NewId() + "a"
- purpose := "zz" + model.NewId() + "a"
- upChannel1 := &model.Channel{Id: channel1.Id, Header: header, Purpose: purpose}
- upChannel1 = Client.Must(Client.UpdateChannel(upChannel1)).Data.(*model.Channel)
-
- if upChannel1.Header != header {
- t.Fatal("Channel admin failed to update header")
- }
-
- if upChannel1.Purpose != purpose {
- t.Fatal("Channel admin failed to update purpose")
- }
-
- if upChannel1.DisplayName != channel1.DisplayName {
- t.Fatal("Channel admin failed to skip displayName")
- }
-
- rget := Client.Must(Client.GetChannels(""))
- channels := rget.Data.(*model.ChannelList)
- for _, c := range *channels {
- if c.Name == model.DEFAULT_CHANNEL {
- c.Header = "new header"
- c.Name = "pseudo-square"
- if _, err := Client.UpdateChannel(c); err == nil {
- t.Fatal("should have errored on updating default channel name")
- }
- break
- }
- }
-
- Client.Login(user2.Email, user2.Password)
-
- if _, err := Client.UpdateChannel(upChannel1); err == nil {
- t.Fatal("Standard User should have failed to update")
- }
-
- Client.Must(Client.JoinChannel(channel1.Id))
- th.UpdateUserToTeamAdmin(user2, team)
-
- Client.Logout()
- Client.Login(user2.Email, user2.Password)
- Client.SetTeamId(team.Id)
-
- if _, err := Client.UpdateChannel(upChannel1); err != nil {
- t.Fatal(err)
- }
-
- Client.Login(sysAdminUser.Email, sysAdminUser.Password)
- th.LinkUserToTeam(sysAdminUser, team)
- Client.Must(Client.JoinChannel(channel1.Id))
-
- if _, err := Client.UpdateChannel(upChannel1); err != nil {
- t.Fatal(err)
- }
-
- Client.Must(Client.DeleteChannel(channel1.Id))
-
- if _, err := Client.UpdateChannel(upChannel1); err == nil {
- t.Fatal("should have failed - channel deleted")
- }
-
- // Check the appropriate permissions are enforced.
- defaultRolePermissions := th.SaveDefaultRolePermissions()
- defer func() {
- th.RestoreDefaultRolePermissions(defaultRolePermissions)
- }()
-
- th.RemovePermissionFromRole(model.PERMISSION_MANAGE_PRIVATE_CHANNEL_PROPERTIES.Id, model.TEAM_USER_ROLE_ID)
- th.RemovePermissionFromRole(model.PERMISSION_MANAGE_PUBLIC_CHANNEL_PROPERTIES.Id, model.TEAM_USER_ROLE_ID)
-
- th.AddPermissionToRole(model.PERMISSION_MANAGE_PRIVATE_CHANNEL_PROPERTIES.Id, model.CHANNEL_USER_ROLE_ID)
- th.AddPermissionToRole(model.PERMISSION_MANAGE_PUBLIC_CHANNEL_PROPERTIES.Id, model.CHANNEL_USER_ROLE_ID)
-
- channel2 := th.CreateChannel(Client, team)
- channel3 := th.CreatePrivateChannel(Client, team)
-
- th.LinkUserToTeam(th.BasicUser, team)
-
- Client.Must(Client.AddChannelMember(channel2.Id, th.BasicUser.Id))
- Client.Must(Client.AddChannelMember(channel3.Id, th.BasicUser.Id))
-
- Client.Login(th.BasicUser.Email, th.BasicUser.Password)
-
- if _, err := Client.UpdateChannel(channel2); err != nil {
- t.Fatal(err)
- }
- if _, err := Client.UpdateChannel(channel3); err != nil {
- t.Fatal(err)
- }
-
- th.RemovePermissionFromRole(model.PERMISSION_MANAGE_PRIVATE_CHANNEL_PROPERTIES.Id, model.CHANNEL_USER_ROLE_ID)
- th.RemovePermissionFromRole(model.PERMISSION_MANAGE_PUBLIC_CHANNEL_PROPERTIES.Id, model.CHANNEL_USER_ROLE_ID)
- th.AddPermissionToRole(model.PERMISSION_MANAGE_PRIVATE_CHANNEL_PROPERTIES.Id, model.CHANNEL_ADMIN_ROLE_ID)
- th.AddPermissionToRole(model.PERMISSION_MANAGE_PUBLIC_CHANNEL_PROPERTIES.Id, model.CHANNEL_ADMIN_ROLE_ID)
-
- th.MakeUserChannelUser(th.BasicUser, channel2)
- th.MakeUserChannelUser(th.BasicUser, channel3)
- th.App.Srv.Store.Channel().ClearCaches()
-
- if _, err := Client.UpdateChannel(channel2); err == nil {
- t.Fatal("should have errored not channel admin")
- }
- if _, err := Client.UpdateChannel(channel3); err == nil {
- t.Fatal("should have errored not channel admin")
- }
-
- th.MakeUserChannelAdmin(th.BasicUser, channel2)
- th.MakeUserChannelAdmin(th.BasicUser, channel3)
- th.App.Srv.Store.Channel().ClearCaches()
-
- if _, err := Client.UpdateChannel(channel2); err != nil {
- t.Fatal(err)
- }
- if _, err := Client.UpdateChannel(channel3); err != nil {
- t.Fatal(err)
- }
-}
-
-func TestUpdateChannelDisplayName(t *testing.T) {
- th := Setup().InitBasic().InitSystemAdmin()
- defer th.TearDown()
-
- Client := th.SystemAdminClient
- team := th.SystemAdminTeam
- user := th.CreateUser(Client)
- th.LinkUserToTeam(user, team)
-
- Client.Login(user.Email, user.Password)
-
- channel1 := &model.Channel{DisplayName: "A Test API Name", Name: "zz" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
- channel1 = Client.Must(Client.CreateChannel(channel1)).Data.(*model.Channel)
-
- Client.AddChannelMember(channel1.Id, user.Id)
-
- newDisplayName := "a" + channel1.DisplayName + "a"
- channel1.DisplayName = newDisplayName
- channel1 = Client.Must(Client.UpdateChannel(channel1)).Data.(*model.Channel)
-
- time.Sleep(100 * time.Millisecond)
-
- r1 := Client.Must(Client.GetPosts(channel1.Id, 0, 1, "")).Data.(*model.PostList)
- if len(r1.Order) != 1 {
- t.Fatal("Displayname update system message was not found")
- }
-}
-
-func TestUpdateChannelHeader(t *testing.T) {
- th := Setup().InitBasic().InitSystemAdmin()
- defer th.TearDown()
-
- Client := th.BasicClient
- team := th.BasicTeam
-
- channel1 := &model.Channel{DisplayName: "A Test API Name", Name: "zz" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
- channel1 = Client.Must(Client.CreateChannel(channel1)).Data.(*model.Channel)
-
- data := make(map[string]string)
- data["channel_id"] = channel1.Id
- data["channel_header"] = "new header"
-
- var upChannel1 *model.Channel
- if result, err := Client.UpdateChannelHeader(data); err != nil {
- t.Fatal(err)
- } else {
- upChannel1 = result.Data.(*model.Channel)
- }
-
- time.Sleep(100 * time.Millisecond)
-
- r1 := Client.Must(Client.GetPosts(channel1.Id, 0, 1, "")).Data.(*model.PostList)
- if len(r1.Order) != 1 {
- t.Fatal("Header update system message was not found")
- } else if val, ok := r1.Posts[r1.Order[0]].Props["old_header"]; !ok || val != "" {
- t.Fatal("Props should contain old_header with old header value")
- } else if val, ok := r1.Posts[r1.Order[0]].Props["new_header"]; !ok || val != "new header" {
- t.Fatal("Props should contain new_header with new header value")
- }
-
- if upChannel1.Header != data["channel_header"] {
- t.Fatal("Failed to update header")
- }
-
- data["channel_id"] = "junk"
- if _, err := Client.UpdateChannelHeader(data); err == nil {
- t.Fatal("should have errored on junk channel id")
- }
-
- data["channel_id"] = "12345678901234567890123456"
- if _, err := Client.UpdateChannelHeader(data); err == nil {
- t.Fatal("should have errored on non-existent channel id")
- }
-
- data["channel_id"] = channel1.Id
- data["channel_header"] = strings.Repeat("a", 1050)
- if _, err := Client.UpdateChannelHeader(data); err == nil {
- t.Fatal("should have errored on bad channel header")
- }
-
- rchannel := Client.Must(Client.CreateDirectChannel(th.BasicUser2.Id)).Data.(*model.Channel)
- data["channel_id"] = rchannel.Id
- data["channel_header"] = "new header"
- var upChanneld *model.Channel
- if result, err := Client.UpdateChannelHeader(data); err != nil {
- t.Fatal(err)
- } else {
- upChanneld = result.Data.(*model.Channel)
- }
-
- if upChanneld.Header != data["channel_header"] {
- t.Fatal("Failed to update header")
- }
-
- th.LoginBasic2()
-
- data["channel_id"] = channel1.Id
- data["channel_header"] = "new header"
- if _, err := Client.UpdateChannelHeader(data); err == nil {
- t.Fatal("should have errored non-channel member trying to update header")
- }
-
- // Check the appropriate permissions are enforced.
- defaultRolePermissions := th.SaveDefaultRolePermissions()
- defer func() {
- th.RestoreDefaultRolePermissions(defaultRolePermissions)
- }()
-
- th.RemovePermissionFromRole(model.PERMISSION_MANAGE_PRIVATE_CHANNEL_PROPERTIES.Id, model.TEAM_USER_ROLE_ID)
- th.RemovePermissionFromRole(model.PERMISSION_MANAGE_PUBLIC_CHANNEL_PROPERTIES.Id, model.TEAM_USER_ROLE_ID)
-
- th.AddPermissionToRole(model.PERMISSION_MANAGE_PRIVATE_CHANNEL_PROPERTIES.Id, model.CHANNEL_USER_ROLE_ID)
- th.AddPermissionToRole(model.PERMISSION_MANAGE_PUBLIC_CHANNEL_PROPERTIES.Id, model.CHANNEL_USER_ROLE_ID)
-
- th.LoginBasic()
- channel2 := th.CreateChannel(Client, team)
- channel3 := th.CreatePrivateChannel(Client, team)
-
- data2 := make(map[string]string)
- data2["channel_id"] = channel2.Id
- data2["channel_header"] = "new header"
-
- data3 := make(map[string]string)
- data3["channel_id"] = channel3.Id
- data3["channel_header"] = "new header"
-
- Client.Login(th.BasicUser.Email, th.BasicUser.Password)
-
- if _, err := Client.UpdateChannelHeader(data2); err != nil {
- t.Fatal(err)
- }
- if _, err := Client.UpdateChannelHeader(data3); err != nil {
- t.Fatal(err)
- }
-
- th.RemovePermissionFromRole(model.PERMISSION_MANAGE_PRIVATE_CHANNEL_PROPERTIES.Id, model.CHANNEL_USER_ROLE_ID)
- th.RemovePermissionFromRole(model.PERMISSION_MANAGE_PUBLIC_CHANNEL_PROPERTIES.Id, model.CHANNEL_USER_ROLE_ID)
- th.AddPermissionToRole(model.PERMISSION_MANAGE_PRIVATE_CHANNEL_PROPERTIES.Id, model.CHANNEL_ADMIN_ROLE_ID)
- th.AddPermissionToRole(model.PERMISSION_MANAGE_PUBLIC_CHANNEL_PROPERTIES.Id, model.CHANNEL_ADMIN_ROLE_ID)
-
- th.MakeUserChannelUser(th.BasicUser, channel2)
- th.MakeUserChannelUser(th.BasicUser, channel3)
- th.App.Srv.Store.Channel().ClearCaches()
-
- if _, err := Client.UpdateChannelHeader(data2); err == nil {
- t.Fatal("should have errored not channel admin")
- }
- if _, err := Client.UpdateChannelHeader(data3); err == nil {
- t.Fatal("should have errored not channel admin")
- }
-
- th.MakeUserChannelAdmin(th.BasicUser, channel2)
- th.MakeUserChannelAdmin(th.BasicUser, channel3)
- th.App.Srv.Store.Channel().ClearCaches()
-
- if _, err := Client.UpdateChannelHeader(data2); err != nil {
- t.Fatal(err)
- }
- if _, err := Client.UpdateChannelHeader(data3); err != nil {
- t.Fatal(err)
- }
-}
-
-func TestUpdateChannelPurpose(t *testing.T) {
- th := Setup().InitBasic().InitSystemAdmin()
- defer th.TearDown()
-
- Client := th.BasicClient
- team := th.BasicTeam
-
- channel1 := &model.Channel{DisplayName: "A Test API Name", Name: "zz" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
- channel1 = Client.Must(Client.CreateChannel(channel1)).Data.(*model.Channel)
-
- data := make(map[string]string)
- data["channel_id"] = channel1.Id
- data["channel_purpose"] = "new purpose"
-
- var upChannel1 *model.Channel
- if result, err := Client.UpdateChannelPurpose(data); err != nil {
- t.Fatal(err)
- } else {
- upChannel1 = result.Data.(*model.Channel)
- }
-
- time.Sleep(100 * time.Millisecond)
-
- r1 := Client.Must(Client.GetPosts(channel1.Id, 0, 1, "")).Data.(*model.PostList)
- if len(r1.Order) != 1 {
- t.Fatal("Purpose update system message was not found")
- } else if val, ok := r1.Posts[r1.Order[0]].Props["old_purpose"]; !ok || val != "" {
- t.Fatal("Props should contain old_header with old purpose value")
- } else if val, ok := r1.Posts[r1.Order[0]].Props["new_purpose"]; !ok || val != "new purpose" {
- t.Fatal("Props should contain new_header with new purpose value")
- }
-
- if upChannel1.Purpose != data["channel_purpose"] {
- t.Fatal("Failed to update purpose")
- }
-
- data["channel_id"] = "junk"
- if _, err := Client.UpdateChannelPurpose(data); err == nil {
- t.Fatal("should have errored on junk channel id")
- }
-
- data["channel_id"] = "12345678901234567890123456"
- if _, err := Client.UpdateChannelPurpose(data); err == nil {
- t.Fatal("should have errored on non-existent channel id")
- }
-
- data["channel_id"] = channel1.Id
- data["channel_purpose"] = strings.Repeat("a", 350)
- if _, err := Client.UpdateChannelPurpose(data); err == nil {
- t.Fatal("should have errored on bad channel purpose")
- }
-
- th.LoginBasic2()
-
- data["channel_id"] = channel1.Id
- data["channel_purpose"] = "new purpose"
- if _, err := Client.UpdateChannelPurpose(data); err == nil {
- t.Fatal("should have errored non-channel member trying to update purpose")
- }
-
- // Check the appropriate permissions are enforced.
- defaultRolePermissions := th.SaveDefaultRolePermissions()
- defer func() {
- th.RestoreDefaultRolePermissions(defaultRolePermissions)
- }()
-
- th.RemovePermissionFromRole(model.PERMISSION_MANAGE_PRIVATE_CHANNEL_PROPERTIES.Id, model.TEAM_USER_ROLE_ID)
- th.RemovePermissionFromRole(model.PERMISSION_MANAGE_PUBLIC_CHANNEL_PROPERTIES.Id, model.TEAM_USER_ROLE_ID)
-
- th.AddPermissionToRole(model.PERMISSION_MANAGE_PRIVATE_CHANNEL_PROPERTIES.Id, model.CHANNEL_USER_ROLE_ID)
- th.AddPermissionToRole(model.PERMISSION_MANAGE_PUBLIC_CHANNEL_PROPERTIES.Id, model.CHANNEL_USER_ROLE_ID)
-
- th.LoginBasic()
- channel2 := th.CreateChannel(Client, team)
- channel3 := th.CreatePrivateChannel(Client, team)
-
- data2 := make(map[string]string)
- data2["channel_id"] = channel2.Id
- data2["channel_purpose"] = "new purpose"
-
- data3 := make(map[string]string)
- data3["channel_id"] = channel3.Id
- data3["channel_purpose"] = "new purpose"
-
- Client.Login(th.BasicUser.Email, th.BasicUser.Password)
-
- if _, err := Client.UpdateChannelPurpose(data2); err != nil {
- t.Fatal(err)
- }
- if _, err := Client.UpdateChannelPurpose(data3); err != nil {
- t.Fatal(err)
- }
-
- th.RemovePermissionFromRole(model.PERMISSION_MANAGE_PRIVATE_CHANNEL_PROPERTIES.Id, model.CHANNEL_USER_ROLE_ID)
- th.RemovePermissionFromRole(model.PERMISSION_MANAGE_PUBLIC_CHANNEL_PROPERTIES.Id, model.CHANNEL_USER_ROLE_ID)
- th.AddPermissionToRole(model.PERMISSION_MANAGE_PRIVATE_CHANNEL_PROPERTIES.Id, model.CHANNEL_ADMIN_ROLE_ID)
- th.AddPermissionToRole(model.PERMISSION_MANAGE_PUBLIC_CHANNEL_PROPERTIES.Id, model.CHANNEL_ADMIN_ROLE_ID)
-
- th.MakeUserChannelUser(th.BasicUser, channel2)
- th.MakeUserChannelUser(th.BasicUser, channel3)
- th.App.Srv.Store.Channel().ClearCaches()
-
- if _, err := Client.UpdateChannelPurpose(data2); err == nil {
- t.Fatal("should have errored not channel admin")
- }
- if _, err := Client.UpdateChannelPurpose(data3); err == nil {
- t.Fatal("should have errored not channel admin")
- }
-
- th.MakeUserChannelAdmin(th.BasicUser, channel2)
- th.MakeUserChannelAdmin(th.BasicUser, channel3)
- th.App.Srv.Store.Channel().ClearCaches()
-
- if _, err := Client.UpdateChannelPurpose(data2); err != nil {
- t.Fatal(err)
- }
- if _, err := Client.UpdateChannelPurpose(data3); err != nil {
- t.Fatal(err)
- }
-}
-
-func TestGetChannel(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- Client := th.BasicClient
- team := th.BasicTeam
- team2 := th.CreateTeam(Client)
-
- channel1 := &model.Channel{DisplayName: "A Test API Name", Name: "zz" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
- channel1 = Client.Must(Client.CreateChannel(channel1)).Data.(*model.Channel)
-
- channel2 := &model.Channel{DisplayName: "B Test API Name", Name: "zz" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
- channel2 = Client.Must(Client.CreateChannel(channel2)).Data.(*model.Channel)
-
- rget := Client.Must(Client.GetChannels(""))
- channels := rget.Data.(*model.ChannelList)
-
- if (*channels)[0].DisplayName != channel1.DisplayName {
- t.Fatal("full name didn't match")
- }
-
- if (*channels)[1].DisplayName != channel2.DisplayName {
- t.Fatal("full name didn't match")
- }
-
- // test etag caching
- if cache_result, err := Client.GetChannels(rget.Etag); err != nil {
- t.Fatal(err)
- } else if cache_result.Data.(*model.ChannelList) != nil {
- t.Log(cache_result.Data)
- t.Fatal("cache should be empty")
- }
-
- view := model.ChannelView{ChannelId: channel2.Id, PrevChannelId: channel1.Id}
- if _, resp := Client.ViewChannel(view); resp.Error != nil {
- t.Fatal(resp.Error)
- }
-
- if resp, err := Client.GetChannel(channel1.Id, ""); err != nil {
- t.Fatal(err)
- } else {
- data := resp.Data.(*model.ChannelData)
- if data.Channel.DisplayName != channel1.DisplayName {
- t.Fatal("name didn't match")
- }
-
- // test etag caching
- if cache_result, err := Client.GetChannel(channel1.Id, resp.Etag); err != nil {
- t.Fatal(err)
- } else if cache_result.Data.(*model.ChannelData) != nil {
- t.Log(cache_result.Data)
- t.Fatal("cache should be empty")
- }
- }
-
- if _, err := Client.GetChannel("junk", ""); err == nil {
- t.Fatal("should have failed - bad channel id")
- }
-
- th.BasicClient.SetTeamId(team2.Id)
- if _, err := Client.GetChannel(channel2.Id, ""); err == nil {
- t.Fatal("should have failed - wrong team")
- }
-
- //Test if a wrong team id is supplied should return error
- if _, err := Client.CreateDirectChannel(th.BasicUser2.Id); err != nil {
- t.Fatal(err)
- }
-
- th.BasicClient.SetTeamId("nonexitingteamid")
- if _, err := Client.GetChannels(""); err == nil {
- t.Fatal("should have failed - wrong team id")
- }
-}
-
-func TestGetMoreChannelsPage(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- Client := th.BasicClient
- team := th.BasicTeam
-
- channel1 := &model.Channel{DisplayName: "A Test API Name", Name: "zz" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
- channel1 = Client.Must(Client.CreateChannel(channel1)).Data.(*model.Channel)
-
- channel2 := &model.Channel{DisplayName: "B Test API Name", Name: "b" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
- channel2 = Client.Must(Client.CreateChannel(channel2)).Data.(*model.Channel)
-
- channel3 := &model.Channel{DisplayName: "C Test API Name", Name: "c" + model.NewId() + "a", Type: model.CHANNEL_PRIVATE, TeamId: team.Id}
- channel3 = Client.Must(Client.CreateChannel(channel3)).Data.(*model.Channel)
-
- th.LoginBasic2()
-
- if r, err := Client.GetMoreChannelsPage(0, 100); err != nil {
- t.Fatal(err)
- } else {
- channels := r.Data.(*model.ChannelList)
-
- // 1 for BasicChannel, 1 for PinnedPostChannel, 2 for open channels created above
- if len(*channels) != 4 {
- t.Fatal("wrong length")
- }
-
- if (*channels)[0].DisplayName != channel1.DisplayName {
- t.Fatal("full name didn't match")
- }
-
- if (*channels)[1].DisplayName != channel2.DisplayName {
- t.Fatal("full name didn't match")
- }
- }
-
- if r, err := Client.GetMoreChannelsPage(0, 1); err != nil {
- t.Fatal(err)
- } else {
- channels := r.Data.(*model.ChannelList)
-
- if len(*channels) != 1 {
- t.Fatal("wrong length")
- }
-
- if (*channels)[0].DisplayName != channel1.DisplayName {
- t.Fatal("full name didn't match")
- }
- }
-
- if r, err := Client.GetMoreChannelsPage(1, 1); err != nil {
- t.Fatal(err)
- } else {
- channels := r.Data.(*model.ChannelList)
-
- if len(*channels) != 1 {
- t.Fatal("wrong length")
- }
-
- if (*channels)[0].DisplayName != channel2.DisplayName {
- t.Fatal("full name didn't match")
- }
- }
-
- Client.SetTeamId("junk")
- if _, err := Client.GetMoreChannelsPage(0, 1); err == nil {
- t.Fatal("should have failed - bad team id")
- }
-}
-
-func TestGetChannelCounts(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- Client := th.BasicClient
- team := th.BasicTeam
-
- channel1 := &model.Channel{DisplayName: "A Test API Name", Name: "zz" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
- channel1 = Client.Must(Client.CreateChannel(channel1)).Data.(*model.Channel)
-
- channel2 := &model.Channel{DisplayName: "B Test API Name", Name: "zz" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
- channel2 = Client.Must(Client.CreateChannel(channel2)).Data.(*model.Channel)
-
- if result, err := Client.GetChannelCounts(""); err != nil {
- t.Fatal(err)
- } else {
- counts := result.Data.(*model.ChannelCounts)
-
- if len(counts.Counts) != 6 {
- t.Fatal("wrong number of channel counts")
- }
-
- if len(counts.UpdateTimes) != 6 {
- t.Fatal("wrong number of channel update times")
- }
-
- if cache_result, err := Client.GetChannelCounts(result.Etag); err != nil {
- t.Fatal(err)
- } else if cache_result.Data.(*model.ChannelCounts) != nil {
- t.Log(cache_result.Data)
- t.Fatal("result data should be empty")
- }
- }
-
-}
-
-func TestGetMyChannelMembers(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- Client := th.BasicClient
- team := th.BasicTeam
-
- channel1 := &model.Channel{DisplayName: "A Test API Name", Name: "zz" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
- channel1 = Client.Must(Client.CreateChannel(channel1)).Data.(*model.Channel)
-
- channel2 := &model.Channel{DisplayName: "B Test API Name", Name: "zz" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
- channel2 = Client.Must(Client.CreateChannel(channel2)).Data.(*model.Channel)
-
- if result, err := Client.GetMyChannelMembers(); err != nil {
- t.Fatal(err)
- } else {
- members := result.Data.(*model.ChannelMembers)
-
- // town-square, off-topic, basic test channel, pinned post channel, channel1, channel2
- if len(*members) != 6 {
- t.Fatal("wrong number of members", len(*members))
- }
- }
-
-}
-
-func TestJoinChannelById(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- Client := th.BasicClient
- team := th.BasicTeam
-
- channel1 := &model.Channel{DisplayName: "A Test API Name", Name: "zz" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
- channel1 = Client.Must(Client.CreateChannel(channel1)).Data.(*model.Channel)
-
- channel3 := &model.Channel{DisplayName: "B Test API Name", Name: "zz" + model.NewId() + "a", Type: model.CHANNEL_PRIVATE, TeamId: team.Id}
- channel3 = Client.Must(Client.CreateChannel(channel3)).Data.(*model.Channel)
-
- th.LoginBasic2()
-
- Client.Must(Client.JoinChannel(channel1.Id))
-
- if _, err := Client.JoinChannel(channel3.Id); err == nil {
- t.Fatal("shouldn't be able to join secret group")
- }
-
- rchannel := Client.Must(Client.CreateDirectChannel(th.BasicUser.Id)).Data.(*model.Channel)
-
- user3 := th.CreateUser(th.BasicClient)
- th.LinkUserToTeam(user3, team)
- Client.Must(Client.Login(user3.Email, "Password1"))
-
- if _, err := Client.JoinChannel(rchannel.Id); err == nil {
- t.Fatal("shoudn't be able to join direct channel")
- }
-
- th.LoginBasic()
-
- if _, err := Client.JoinChannel(channel1.Id); err != nil {
- t.Fatal("should be able to join public channel that we're a member of")
- }
-
- if _, err := Client.JoinChannel(channel3.Id); err != nil {
- t.Fatal("should be able to join private channel that we're a member of")
- }
-
- if _, err := Client.JoinChannel(rchannel.Id); err != nil {
- t.Fatal("should be able to join direct channel that we're a member of")
- }
-}
-
-func TestJoinChannelByName(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- Client := th.BasicClient
- team := th.BasicTeam
-
- channel1 := &model.Channel{DisplayName: "A Test API Name", Name: "zz" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
- channel1 = Client.Must(Client.CreateChannel(channel1)).Data.(*model.Channel)
-
- channel3 := &model.Channel{DisplayName: "B Test API Name", Name: "zz" + model.NewId() + "a", Type: model.CHANNEL_PRIVATE, TeamId: team.Id}
- channel3 = Client.Must(Client.CreateChannel(channel3)).Data.(*model.Channel)
-
- th.LoginBasic2()
-
- Client.Must(Client.JoinChannelByName(channel1.Name))
-
- if _, err := Client.JoinChannelByName(channel3.Name); err == nil {
- t.Fatal("shouldn't be able to join secret group")
- }
-
- rchannel := Client.Must(Client.CreateDirectChannel(th.BasicUser.Id)).Data.(*model.Channel)
-
- user3 := th.CreateUser(th.BasicClient)
- th.LinkUserToTeam(user3, team)
- Client.Must(Client.Login(user3.Email, "Password1"))
-
- if _, err := Client.JoinChannelByName(rchannel.Name); err == nil {
- t.Fatal("shoudn't be able to join direct channel")
- }
-
- th.LoginBasic()
-
- if _, err := Client.JoinChannelByName(channel1.Name); err != nil {
- t.Fatal("should be able to join public channel that we're a member of")
- }
-
- if _, err := Client.JoinChannelByName(channel3.Name); err != nil {
- t.Fatal("should be able to join private channel that we're a member of")
- }
-
- if _, err := Client.JoinChannelByName(rchannel.Name); err != nil {
- t.Fatal("should be able to join direct channel that we're a member of")
- }
-}
-
-func TestJoinChannelByNameDisabledUser(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- Client := th.BasicClient
- team := th.BasicTeam
-
- channel1 := &model.Channel{DisplayName: "A Test API Name", Name: "zz" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
- channel1 = Client.Must(Client.CreateChannel(channel1)).Data.(*model.Channel)
-
- Client.Must(th.BasicClient.RemoveUserFromTeam(th.BasicTeam.Id, th.BasicUser.Id))
-
- if _, err := th.App.AddUserToChannel(th.BasicUser, channel1); err == nil {
- t.Fatal("shoudn't be able to join channel")
- } else {
- if err.Id != "api.channel.add_user.to.channel.failed.deleted.app_error" {
- t.Fatal("wrong error")
- }
- }
-}
-
-func TestLeaveChannel(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- Client := th.BasicClient
- team := th.BasicTeam
-
- channel1 := &model.Channel{DisplayName: "A Test API Name", Name: "zz" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
- channel1 = Client.Must(Client.CreateChannel(channel1)).Data.(*model.Channel)
-
- channel3 := &model.Channel{DisplayName: "B Test API Name", Name: "zz" + model.NewId() + "a", Type: model.CHANNEL_PRIVATE, TeamId: team.Id}
- channel3 = Client.Must(Client.CreateChannel(channel3)).Data.(*model.Channel)
-
- th.LoginBasic2()
-
- Client.Must(Client.JoinChannel(channel1.Id))
-
- // Cannot leave a the private group if you are the only member
- if _, err := Client.LeaveChannel(channel3.Id); err == nil {
- t.Fatal("should have errored, cannot leave private group if only one member")
- }
-
- rchannel := Client.Must(Client.CreateDirectChannel(th.BasicUser.Id)).Data.(*model.Channel)
-
- if _, err := Client.LeaveChannel(rchannel.Id); err == nil {
- t.Fatal("should have errored, cannot leave direct channel")
- }
-
- rget := Client.Must(Client.GetChannels(""))
- cdata := rget.Data.(*model.ChannelList)
- for _, c := range *cdata {
- if c.Name == model.DEFAULT_CHANNEL {
- if _, err := Client.LeaveChannel(c.Id); err == nil {
- t.Fatal("should have errored on leaving default channel")
- }
- break
- }
- }
-}
-
-func TestDeleteChannel(t *testing.T) {
- th := Setup().InitBasic().InitSystemAdmin()
- defer th.TearDown()
-
- Client := th.SystemAdminClient
- team := th.SystemAdminTeam
- userSystemAdmin := th.SystemAdminUser
- userTeamAdmin := th.CreateUser(Client)
- th.LinkUserToTeam(userTeamAdmin, team)
- user2 := th.CreateUser(Client)
- th.LinkUserToTeam(user2, team)
-
- Client.Login(user2.Email, user2.Password)
-
- channelMadeByCA := &model.Channel{DisplayName: "C Test API Name", Name: "zz" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
- channelMadeByCA = Client.Must(Client.CreateChannel(channelMadeByCA)).Data.(*model.Channel)
-
- Client.AddChannelMember(channelMadeByCA.Id, userTeamAdmin.Id)
-
- Client.Login(userTeamAdmin.Email, "pwd")
-
- channel1 := &model.Channel{DisplayName: "A Test API Name", Name: "zz" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
- channel1 = Client.Must(Client.CreateChannel(channel1)).Data.(*model.Channel)
-
- channel2 := &model.Channel{DisplayName: "B Test API Name", Name: "zz" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
- channel2 = Client.Must(Client.CreateChannel(channel2)).Data.(*model.Channel)
-
- if _, err := Client.DeleteChannel(channel1.Id); err != nil {
- t.Fatal(err)
- }
-
- if _, err := Client.DeleteChannel(channelMadeByCA.Id); err != nil {
- t.Fatal("Team admin failed to delete Channel Admin's channel")
- }
-
- post1 := &model.Post{ChannelId: channel1.Id, Message: "zz" + model.NewId() + "a"}
- if _, err := Client.CreatePost(post1); err == nil {
- t.Fatal("should have failed to post to deleted channel")
- }
-
- userStd := th.CreateUser(Client)
- th.LinkUserToTeam(userStd, team)
- Client.Login(userStd.Email, userStd.Password)
-
- if _, err := Client.JoinChannel(channel1.Id); err == nil {
- t.Fatal("should have failed to join deleted channel")
- }
-
- Client.Must(Client.JoinChannel(channel2.Id))
-
- if _, err := Client.DeleteChannel(channel2.Id); err != nil {
- t.Fatal(err)
- }
-
- rget := Client.Must(Client.GetChannels(""))
- cdata := rget.Data.(*model.ChannelList)
- for _, c := range *cdata {
- if c.Name == model.DEFAULT_CHANNEL {
- if _, err := Client.DeleteChannel(c.Id); err == nil {
- t.Fatal("should have errored on deleting default channel")
- }
- break
- }
- }
-
- th.UpdateUserToTeamAdmin(userStd, team)
-
- Client.Logout()
- Client.Login(userStd.Email, userStd.Password)
- Client.SetTeamId(team.Id)
-
- channel2 = th.CreateChannel(Client, team)
-
- if _, err := Client.DeleteChannel(channel2.Id); err != nil {
- t.Fatal(err)
- }
-
- channel3 := &model.Channel{DisplayName: "B Test API Name", Name: "zz" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
- channel3 = Client.Must(Client.CreateChannel(channel3)).Data.(*model.Channel)
-
- Client.Login(userSystemAdmin.Email, userSystemAdmin.Password)
- Client.Must(Client.JoinChannel(channel3.Id))
-
- if _, err := Client.DeleteChannel(channel3.Id); err != nil {
- t.Fatal(err)
- }
-
- if _, err := Client.DeleteChannel(channel3.Id); err == nil {
- t.Fatal("should have failed - channel already deleted")
- }
-
- // Check the appropriate permissions are enforced.
- defaultRolePermissions := th.SaveDefaultRolePermissions()
- defer func() {
- th.RestoreDefaultRolePermissions(defaultRolePermissions)
- }()
-
- th.AddPermissionToRole(model.PERMISSION_DELETE_PUBLIC_CHANNEL.Id, model.TEAM_USER_ROLE_ID)
- th.AddPermissionToRole(model.PERMISSION_DELETE_PRIVATE_CHANNEL.Id, model.TEAM_USER_ROLE_ID)
-
- th.LoginSystemAdmin()
- th.LinkUserToTeam(th.BasicUser, team)
-
- channel2 = th.CreateChannel(Client, team)
- channel3 = th.CreatePrivateChannel(Client, team)
- channel4 := th.CreateChannel(Client, team)
- Client.Must(Client.AddChannelMember(channel2.Id, th.BasicUser.Id))
- Client.Must(Client.AddChannelMember(channel3.Id, th.BasicUser.Id))
- Client.Must(Client.AddChannelMember(channel4.Id, th.BasicUser.Id))
- Client.Must(Client.LeaveChannel(channel4.Id))
-
- Client.Login(th.BasicUser.Email, th.BasicUser.Password)
-
- if _, err := Client.DeleteChannel(channel2.Id); err != nil {
- t.Fatal(err)
- }
- if _, err := Client.DeleteChannel(channel3.Id); err != nil {
- t.Fatal(err)
- }
-
- th.RemovePermissionFromRole(model.PERMISSION_DELETE_PUBLIC_CHANNEL.Id, model.TEAM_USER_ROLE_ID)
- th.RemovePermissionFromRole(model.PERMISSION_DELETE_PRIVATE_CHANNEL.Id, model.TEAM_USER_ROLE_ID)
- th.AddPermissionToRole(model.PERMISSION_DELETE_PUBLIC_CHANNEL.Id, model.CHANNEL_ADMIN_ROLE_ID)
- th.AddPermissionToRole(model.PERMISSION_DELETE_PRIVATE_CHANNEL.Id, model.CHANNEL_ADMIN_ROLE_ID)
-
- th.LoginSystemAdmin()
-
- channel2 = th.CreateChannel(Client, team)
- channel3 = th.CreatePrivateChannel(Client, team)
- Client.Must(Client.AddChannelMember(channel2.Id, th.BasicUser.Id))
- Client.Must(Client.AddChannelMember(channel3.Id, th.BasicUser.Id))
-
- Client.Login(th.BasicUser.Email, th.BasicUser.Password)
-
- if _, err := Client.DeleteChannel(channel2.Id); err == nil {
- t.Fatal("should have errored not channel admin")
- }
- if _, err := Client.DeleteChannel(channel3.Id); err == nil {
- t.Fatal("should have errored not channel admin")
- }
-
- th.MakeUserChannelAdmin(th.BasicUser, channel2)
- th.MakeUserChannelAdmin(th.BasicUser, channel3)
- th.App.Srv.Store.Channel().ClearCaches()
-
- if _, err := Client.DeleteChannel(channel2.Id); err != nil {
- t.Fatal(err)
- }
- if _, err := Client.DeleteChannel(channel3.Id); err != nil {
- t.Fatal(err)
- }
-
- th.LoginSystemAdmin()
-
- channel2 = th.CreateChannel(Client, team)
- channel3 = th.CreatePrivateChannel(Client, team)
- Client.Must(Client.AddChannelMember(channel2.Id, th.BasicUser.Id))
- Client.Must(Client.AddChannelMember(channel3.Id, th.BasicUser.Id))
-
- Client.Login(th.BasicUser.Email, th.BasicUser.Password)
-
- if _, err := Client.DeleteChannel(channel2.Id); err == nil {
- t.Fatal("should have errored not system admin")
- }
- if _, err := Client.DeleteChannel(channel3.Id); err == nil {
- t.Fatal("should have errored not system admin")
- }
-
- if _, err := Client.DeleteChannel(channel4.Id); err == nil {
- t.Fatal("Should not be able to delete channel, even though only one user is left")
- }
-
- th.LoginSystemAdmin()
-
- if _, err := Client.DeleteChannel(channel2.Id); err != nil {
- t.Fatal(err)
- }
- if _, err := Client.DeleteChannel(channel3.Id); err != nil {
- t.Fatal(err)
- }
-}
-
-func TestGetChannelStats(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- Client := th.BasicClient
- team := th.BasicTeam
-
- channel1 := &model.Channel{DisplayName: "A Test API Name", Name: "zz" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
- channel1 = Client.Must(Client.CreateChannel(channel1)).Data.(*model.Channel)
-
- rget := Client.Must(Client.GetChannelStats(channel1.Id, ""))
- data := rget.Data.(*model.ChannelStats)
- if data.ChannelId != channel1.Id {
- t.Fatal("couldnt't get extra info")
- } else if data.MemberCount != 1 {
- t.Fatal("got incorrect member count")
- }
-}
-
-func TestAddChannelMember(t *testing.T) {
- th := Setup().InitBasic().InitSystemAdmin()
- defer th.TearDown()
-
- Client := th.BasicClient
- team := th.BasicTeam
- user1 := th.BasicUser
- user2 := th.BasicUser2
- user3 := th.CreateUser(Client)
-
- channel1 := &model.Channel{DisplayName: "A Test API Name", Name: "zz" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
- channel1 = Client.Must(Client.CreateChannel(channel1)).Data.(*model.Channel)
-
- if _, err := Client.AddChannelMember(channel1.Id, user2.Id); err != nil {
- t.Fatal(err)
- }
-
- if _, err := Client.AddChannelMember(channel1.Id, "dsgsdg"); err == nil {
- t.Fatal("Should have errored, bad user id")
- }
-
- if _, err := Client.AddChannelMember(channel1.Id, "12345678901234567890123456"); err == nil {
- t.Fatal("Should have errored, bad user id")
- }
-
- if _, err := Client.AddChannelMember(channel1.Id, user2.Id); err != nil {
- t.Fatal(err)
- }
-
- if _, err := Client.AddChannelMember("sgdsgsdg", user2.Id); err == nil {
- t.Fatal("Should have errored, bad channel id")
- }
-
- channel2 := &model.Channel{DisplayName: "A Test API Name", Name: "zz" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
- channel2 = Client.Must(Client.CreateChannel(channel2)).Data.(*model.Channel)
-
- th.LoginBasic2()
-
- if _, err := Client.AddChannelMember(channel2.Id, user2.Id); err == nil {
- t.Fatal("Should have errored, user not in channel")
- }
-
- th.LoginBasic()
-
- Client.Must(Client.DeleteChannel(channel2.Id))
-
- if _, err := Client.AddChannelMember(channel2.Id, user2.Id); err == nil {
- t.Fatal("Should have errored, channel deleted")
- }
-
- if _, err := Client.AddChannelMember(channel1.Id, user3.Id); err == nil {
- t.Fatal("Should have errored, user not on team")
- }
-
- // Check the appropriate permissions are enforced.
- defaultRolePermissions := th.SaveDefaultRolePermissions()
- defer func() {
- th.RestoreDefaultRolePermissions(defaultRolePermissions)
- }()
-
- th.AddPermissionToRole(model.PERMISSION_MANAGE_PUBLIC_CHANNEL_MEMBERS.Id, model.CHANNEL_USER_ROLE_ID)
- th.AddPermissionToRole(model.PERMISSION_MANAGE_PRIVATE_CHANNEL_MEMBERS.Id, model.CHANNEL_USER_ROLE_ID)
-
- // Check that a regular channel user can add other users.
- channel4 := &model.Channel{DisplayName: "A Test API Name", Name: "zz" + model.NewId() + "a", Type: model.CHANNEL_PRIVATE, TeamId: team.Id}
- channel4 = Client.Must(th.SystemAdminClient.CreateChannel(channel4)).Data.(*model.Channel)
- Client.Must(th.SystemAdminClient.AddChannelMember(channel4.Id, user1.Id))
- if _, err := Client.AddChannelMember(channel4.Id, user2.Id); err != nil {
- t.Fatal(err)
- }
-
- th.RemovePermissionFromRole(model.PERMISSION_MANAGE_PUBLIC_CHANNEL_MEMBERS.Id, model.CHANNEL_USER_ROLE_ID)
- th.RemovePermissionFromRole(model.PERMISSION_MANAGE_PRIVATE_CHANNEL_MEMBERS.Id, model.CHANNEL_USER_ROLE_ID)
- th.AddPermissionToRole(model.PERMISSION_MANAGE_PUBLIC_CHANNEL_MEMBERS.Id, model.CHANNEL_ADMIN_ROLE_ID)
- th.AddPermissionToRole(model.PERMISSION_MANAGE_PRIVATE_CHANNEL_MEMBERS.Id, model.CHANNEL_ADMIN_ROLE_ID)
-
- channel5 := &model.Channel{DisplayName: "A Test API Name", Name: "zz" + model.NewId() + "a", Type: model.CHANNEL_PRIVATE, TeamId: team.Id}
- channel5 = Client.Must(th.SystemAdminClient.CreateChannel(channel5)).Data.(*model.Channel)
- Client.Must(th.SystemAdminClient.AddChannelMember(channel5.Id, user1.Id))
- if _, err := Client.AddChannelMember(channel5.Id, user2.Id); err == nil {
- t.Fatal("Should have failed due to permissions")
- }
-
- th.MakeUserChannelAdmin(user1, channel5)
- th.App.InvalidateAllCaches()
-
- if _, err := Client.AddChannelMember(channel5.Id, user2.Id); err != nil {
- t.Fatal(err)
- }
-}
-
-func TestRemoveChannelMember(t *testing.T) {
- th := Setup().InitBasic().InitSystemAdmin()
- defer th.TearDown()
-
- Client := th.BasicClient
- team := th.BasicTeam
- user1 := th.BasicUser
- user2 := th.BasicUser2
- th.UpdateUserToTeamAdmin(user2, team)
-
- channelMadeByCA := &model.Channel{DisplayName: "A Test API Name", Name: "zz" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
- channelMadeByCA = Client.Must(Client.CreateChannel(channelMadeByCA)).Data.(*model.Channel)
-
- Client.Must(Client.AddChannelMember(channelMadeByCA.Id, user2.Id))
-
- th.LoginBasic2()
-
- channel1 := &model.Channel{DisplayName: "A Test API Name", Name: "zz" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
- channel1 = Client.Must(Client.CreateChannel(channel1)).Data.(*model.Channel)
-
- userStd := th.CreateUser(th.BasicClient)
- th.LinkUserToTeam(userStd, team)
-
- Client.Must(Client.AddChannelMember(channel1.Id, userStd.Id))
-
- Client.Must(Client.AddChannelMember(channelMadeByCA.Id, userStd.Id))
-
- if _, err := Client.RemoveChannelMember(channel1.Id, "dsgsdg"); err == nil {
- t.Fatal("Should have errored, bad user id")
- }
-
- if _, err := Client.RemoveChannelMember("sgdsgsdg", userStd.Id); err == nil {
- t.Fatal("Should have errored, bad channel id")
- }
-
- if _, err := Client.RemoveChannelMember(channel1.Id, userStd.Id); err != nil {
- t.Fatal(err)
- }
-
- if _, err := Client.RemoveChannelMember(channelMadeByCA.Id, userStd.Id); err != nil {
- t.Fatal("Team Admin failed to remove member from Channel Admin's channel")
- }
-
- channel2 := &model.Channel{DisplayName: "A Test API Name", Name: "zz" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
- channel2 = Client.Must(Client.CreateChannel(channel2)).Data.(*model.Channel)
-
- Client.Login(userStd.Email, userStd.Password)
-
- if _, err := Client.RemoveChannelMember(channel2.Id, userStd.Id); err == nil {
- t.Fatal("Should have errored, user not channel admin")
- }
-
- th.LoginBasic2()
- Client.Must(Client.AddChannelMember(channel2.Id, userStd.Id))
-
- Client.Must(Client.DeleteChannel(channel2.Id))
-
- if _, err := Client.RemoveChannelMember(channel2.Id, userStd.Id); err == nil {
- t.Fatal("Should have errored, channel deleted")
- }
-
- townSquare := Client.Must(Client.GetChannelByName("town-square")).Data.(*model.Channel)
-
- if _, err := Client.RemoveChannelMember(townSquare.Id, userStd.Id); err == nil {
- t.Fatal("should have errored, channel is default")
- }
-
- th.LoginBasic()
-
- // Check the appropriate permissions are enforced.
- defaultRolePermissions := th.SaveDefaultRolePermissions()
- defer func() {
- th.RestoreDefaultRolePermissions(defaultRolePermissions)
- }()
-
- th.AddPermissionToRole(model.PERMISSION_MANAGE_PUBLIC_CHANNEL_MEMBERS.Id, model.CHANNEL_USER_ROLE_ID)
- th.AddPermissionToRole(model.PERMISSION_MANAGE_PRIVATE_CHANNEL_MEMBERS.Id, model.CHANNEL_USER_ROLE_ID)
-
- // Check that a regular channel user can remove other users.
- channel4 := &model.Channel{DisplayName: "A Test API Name", Name: "zz" + model.NewId() + "a", Type: model.CHANNEL_PRIVATE, TeamId: team.Id}
- channel4 = Client.Must(th.SystemAdminClient.CreateChannel(channel4)).Data.(*model.Channel)
- Client.Must(th.SystemAdminClient.AddChannelMember(channel4.Id, user1.Id))
- Client.Must(th.SystemAdminClient.AddChannelMember(channel4.Id, user2.Id))
- if _, err := Client.RemoveChannelMember(channel4.Id, user2.Id); err != nil {
- t.Fatal(err)
- }
-
- th.RemovePermissionFromRole(model.PERMISSION_MANAGE_PUBLIC_CHANNEL_MEMBERS.Id, model.CHANNEL_USER_ROLE_ID)
- th.RemovePermissionFromRole(model.PERMISSION_MANAGE_PRIVATE_CHANNEL_MEMBERS.Id, model.CHANNEL_USER_ROLE_ID)
- th.AddPermissionToRole(model.PERMISSION_MANAGE_PUBLIC_CHANNEL_MEMBERS.Id, model.CHANNEL_ADMIN_ROLE_ID)
- th.AddPermissionToRole(model.PERMISSION_MANAGE_PRIVATE_CHANNEL_MEMBERS.Id, model.CHANNEL_ADMIN_ROLE_ID)
-
- channel5 := &model.Channel{DisplayName: "A Test API Name", Name: "zz" + model.NewId() + "a", Type: model.CHANNEL_PRIVATE, TeamId: team.Id}
- channel5 = Client.Must(th.SystemAdminClient.CreateChannel(channel5)).Data.(*model.Channel)
- Client.Must(th.SystemAdminClient.AddChannelMember(channel5.Id, user1.Id))
- Client.Must(th.SystemAdminClient.AddChannelMember(channel5.Id, user2.Id))
- if _, err := Client.RemoveChannelMember(channel5.Id, user2.Id); err == nil {
- t.Fatal("Should have failed due to permissions")
- }
-
- th.MakeUserChannelAdmin(user1, channel5)
- th.App.InvalidateAllCaches()
-
- if _, err := Client.RemoveChannelMember(channel5.Id, user2.Id); err != nil {
- t.Fatal(err)
- }
-}
-
-func TestUpdateNotifyProps(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- Client := th.BasicClient
- team := th.BasicTeam
- user := th.BasicUser
- user2 := th.BasicUser2
-
- channel1 := &model.Channel{DisplayName: "A Test API Name", Name: "zz" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
- channel1 = Client.Must(Client.CreateChannel(channel1)).Data.(*model.Channel)
-
- data := make(map[string]string)
- data["channel_id"] = channel1.Id
- data["user_id"] = user.Id
- data[model.DESKTOP_NOTIFY_PROP] = model.CHANNEL_NOTIFY_MENTION
-
- //timeBeforeUpdate := model.GetMillis()
- time.Sleep(100 * time.Millisecond)
-
- // test updating desktop
- if result, err := Client.UpdateNotifyProps(data); err != nil {
- t.Fatal(err)
- } else if notifyProps := result.Data.(map[string]string); notifyProps[model.DESKTOP_NOTIFY_PROP] != model.CHANNEL_NOTIFY_MENTION {
- t.Fatal("NotifyProps[\"desktop\"] did not update properly")
- } else if notifyProps[model.MARK_UNREAD_NOTIFY_PROP] != model.CHANNEL_MARK_UNREAD_ALL {
- t.Fatalf("NotifyProps[\"mark_unread\"] changed to %v", notifyProps[model.MARK_UNREAD_NOTIFY_PROP])
- }
-
- // test an empty update
- delete(data, model.DESKTOP_NOTIFY_PROP)
-
- if result, err := Client.UpdateNotifyProps(data); err != nil {
- t.Fatal(err)
- } else if notifyProps := result.Data.(map[string]string); notifyProps[model.MARK_UNREAD_NOTIFY_PROP] != model.CHANNEL_MARK_UNREAD_ALL {
- t.Fatalf("NotifyProps[\"mark_unread\"] changed to %v", notifyProps[model.MARK_UNREAD_NOTIFY_PROP])
- } else if notifyProps[model.DESKTOP_NOTIFY_PROP] != model.CHANNEL_NOTIFY_MENTION {
- t.Fatalf("NotifyProps[\"desktop\"] changed to %v", notifyProps[model.DESKTOP_NOTIFY_PROP])
- }
-
- // test updating mark unread
- data[model.MARK_UNREAD_NOTIFY_PROP] = model.CHANNEL_MARK_UNREAD_MENTION
-
- if result, err := Client.UpdateNotifyProps(data); err != nil {
- t.Fatal(err)
- } else if notifyProps := result.Data.(map[string]string); notifyProps[model.MARK_UNREAD_NOTIFY_PROP] != model.CHANNEL_MARK_UNREAD_MENTION {
- t.Fatal("NotifyProps[\"mark_unread\"] did not update properly")
- } else if notifyProps[model.DESKTOP_NOTIFY_PROP] != model.CHANNEL_NOTIFY_MENTION {
- t.Fatalf("NotifyProps[\"desktop\"] changed to %v", notifyProps[model.DESKTOP_NOTIFY_PROP])
- }
-
- // test updating both
- data[model.DESKTOP_NOTIFY_PROP] = model.CHANNEL_NOTIFY_NONE
- data[model.MARK_UNREAD_NOTIFY_PROP] = model.CHANNEL_MARK_UNREAD_MENTION
-
- if result, err := Client.UpdateNotifyProps(data); err != nil {
- t.Fatal(err)
- } else if notifyProps := result.Data.(map[string]string); notifyProps[model.DESKTOP_NOTIFY_PROP] != model.CHANNEL_NOTIFY_NONE {
- t.Fatal("NotifyProps[\"desktop\"] did not update properly")
- } else if notifyProps[model.MARK_UNREAD_NOTIFY_PROP] != model.CHANNEL_MARK_UNREAD_MENTION {
- t.Fatal("NotifyProps[\"mark_unread\"] did not update properly")
- }
-
- // test updating push notification preferences
- delete(data, model.DESKTOP_NOTIFY_PROP)
- delete(data, model.MARK_UNREAD_NOTIFY_PROP)
- data[model.PUSH_NOTIFY_PROP] = model.CHANNEL_NOTIFY_MENTION
- if result, err := Client.UpdateNotifyProps(data); err != nil {
- t.Fatal(err)
- } else if notifyProps := result.Data.(map[string]string); notifyProps[model.PUSH_NOTIFY_PROP] != model.CHANNEL_NOTIFY_MENTION {
- t.Fatal("NotifyProps[\"push\"] did not update properly")
- }
-
- // test updating email preferences
- delete(data, model.PUSH_NOTIFY_PROP)
- data[model.EMAIL_NOTIFY_PROP] = "true"
- if result, err := Client.UpdateNotifyProps(data); err != nil {
- t.Fatal(err)
- } else if notifyProps := result.Data.(map[string]string); notifyProps[model.EMAIL_NOTIFY_PROP] != "true" {
- t.Fatal("NotifyProps[\"email\"] did not update properly")
- }
-
- // test error cases
- data["user_id"] = "junk"
- if _, err := Client.UpdateNotifyProps(data); err == nil {
- t.Fatal("Should have errored - bad user id")
- }
-
- data["user_id"] = "12345678901234567890123456"
- if _, err := Client.UpdateNotifyProps(data); err == nil {
- t.Fatal("Should have errored - bad user id")
- }
-
- data["user_id"] = user.Id
- data["channel_id"] = "junk"
- if _, err := Client.UpdateNotifyProps(data); err == nil {
- t.Fatal("Should have errored - bad channel id")
- }
-
- data["channel_id"] = "12345678901234567890123456"
- if _, err := Client.UpdateNotifyProps(data); err == nil {
- t.Fatal("Should have errored - bad channel id")
- }
-
- data[model.DESKTOP_NOTIFY_PROP] = "junk"
- data[model.MARK_UNREAD_NOTIFY_PROP] = model.CHANNEL_MARK_UNREAD_ALL
- if _, err := Client.UpdateNotifyProps(data); err == nil {
- t.Fatal("Should have errored - bad desktop notify level")
- }
-
- data[model.DESKTOP_NOTIFY_PROP] = model.CHANNEL_NOTIFY_ALL
- data[model.MARK_UNREAD_NOTIFY_PROP] = "junk"
- if _, err := Client.UpdateNotifyProps(data); err == nil {
- t.Fatal("Should have errored - bad mark unread level")
- }
-
- data[model.DESKTOP_NOTIFY_PROP] = model.CHANNEL_NOTIFY_ALL
- data[model.MARK_UNREAD_NOTIFY_PROP] = model.CHANNEL_MARK_UNREAD_ALL
- data[model.PUSH_NOTIFY_PROP] = "junk"
- data[model.EMAIL_NOTIFY_PROP] = "true"
- if _, err := Client.UpdateNotifyProps(data); err == nil {
- t.Fatal("Should have errored - bad push level")
- }
-
- data[model.PUSH_NOTIFY_PROP] = model.CHANNEL_NOTIFY_ALL
- data[model.EMAIL_NOTIFY_PROP] = "junk"
- if _, err := Client.UpdateNotifyProps(data); err == nil {
- t.Fatal("Should have errored - bad email notification option")
- }
-
- th.LoginBasic2()
-
- data["channel_id"] = channel1.Id
- data["user_id"] = user2.Id
- data[model.DESKTOP_NOTIFY_PROP] = model.CHANNEL_NOTIFY_MENTION
- data[model.MARK_UNREAD_NOTIFY_PROP] = model.CHANNEL_MARK_UNREAD_MENTION
- if _, err := Client.UpdateNotifyProps(data); err == nil {
- t.Fatal("Should have errored - user not in channel")
- }
-}
-
-func TestFuzzyChannel(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- Client := th.BasicClient
- team := th.BasicTeam
-
- // Strings that should pass as acceptable channel names
- var fuzzyStringsPass = []string{
- "*", "?", ".", "}{][)(><", "{}[]()<>",
-
- "qahwah ( قهوة)",
- "שָׁלוֹם עֲלֵיכֶם",
- "Ramen チャーシュー chāshū",
- "言而无信",
- "Ṫ͌ó̍ ̍͂̓̍̍̀i̊ͯ͒",
- "&amp; &lt; &qu",
-
- "' or '1'='1' -- ",
- "' or '1'='1' ({ ",
- "' or '1'='1' /* ",
- "1;DROP TABLE users",
-
- "<b><i><u><strong><em>",
-
- "sue@thatmightbe",
- "sue@thatmightbe.",
- "sue@thatmightbe.c",
- "sue@thatmightbe.co",
- "su+san@thatmightbe.com",
- "a@b.中国",
- "1@2.am",
- "a@b.co.uk",
- "a@b.cancerresearch",
- "local@[127.0.0.1]",
- }
-
- for i := 0; i < len(fuzzyStringsPass); i++ {
- channel := model.Channel{DisplayName: fuzzyStringsPass[i], Name: "zz" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
-
- _, err := Client.CreateChannel(&channel)
- if err != nil {
- t.Fatal(err)
- }
- }
-}
-
-func TestGetChannelMember(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- Client := th.BasicClient
- team := th.BasicTeam
-
- channel1 := &model.Channel{DisplayName: "A Test API Name", Name: "zz" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
- channel1 = Client.Must(Client.CreateChannel(channel1)).Data.(*model.Channel)
-
- if result, err := Client.GetChannelMember(channel1.Id, th.BasicUser.Id); err != nil {
- t.Fatal(err)
- } else {
- cm := result.Data.(*model.ChannelMember)
-
- if cm.UserId != th.BasicUser.Id {
- t.Fatal("user ids didn't match")
- }
- if cm.ChannelId != channel1.Id {
- t.Fatal("channel ids didn't match")
- }
- }
-
- if _, err := Client.GetChannelMember(channel1.Id, th.BasicUser2.Id); err == nil {
- t.Fatal("should have failed - user not in channel")
- }
-
- if _, err := Client.GetChannelMember("junk", th.BasicUser2.Id); err == nil {
- t.Fatal("should have failed - bad channel id")
- }
-
- if _, err := Client.GetChannelMember(channel1.Id, "junk"); err == nil {
- t.Fatal("should have failed - bad user id")
- }
-
- if _, err := Client.GetChannelMember("junk", "junk"); err == nil {
- t.Fatal("should have failed - bad channel and user id")
- }
-}
-
-func TestSearchMoreChannels(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- Client := th.BasicClient
- team := th.BasicTeam
-
- channel1 := &model.Channel{DisplayName: "TestAPINameA", Name: "zz" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
- channel1 = Client.Must(Client.CreateChannel(channel1)).Data.(*model.Channel)
-
- channel2 := &model.Channel{DisplayName: "TestAPINameB", Name: "b" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
- channel2 = Client.Must(Client.CreateChannel(channel2)).Data.(*model.Channel)
-
- th.LoginBasic2()
-
- if result, err := Client.SearchMoreChannels(model.ChannelSearch{Term: "TestAPIName"}); err != nil {
- t.Fatal(err)
- } else {
- channels := result.Data.(*model.ChannelList)
-
- if (*channels)[0].DisplayName != channel1.DisplayName {
- t.Fatal("full name didn't match")
- }
-
- if (*channels)[1].DisplayName != channel2.DisplayName {
- t.Fatal("full name didn't match")
- }
- }
-
- if result, err := Client.SearchMoreChannels(model.ChannelSearch{Term: "TestAPINameA"}); err != nil {
- t.Fatal(err)
- } else {
- channels := result.Data.(*model.ChannelList)
-
- if (*channels)[0].DisplayName != channel1.DisplayName {
- t.Fatal("full name didn't match")
- }
- }
-
- if result, err := Client.SearchMoreChannels(model.ChannelSearch{Term: "TestAPINameB"}); err != nil {
- t.Fatal(err)
- } else {
- channels := result.Data.(*model.ChannelList)
-
- if (*channels)[0].DisplayName != channel2.DisplayName {
- t.Fatal("full name didn't match")
- }
- }
-
- if result, err := Client.SearchMoreChannels(model.ChannelSearch{Term: channel1.Name}); err != nil {
- t.Fatal(err)
- } else {
- channels := result.Data.(*model.ChannelList)
-
- if (*channels)[0].DisplayName != channel1.DisplayName {
- t.Fatal("full name didn't match")
- }
- }
-
- if _, err := Client.SearchMoreChannels(model.ChannelSearch{Term: ""}); err == nil {
- t.Fatal("should have errored - empty term")
- }
-
- if result, err := Client.SearchMoreChannels(model.ChannelSearch{Term: "blargh"}); err != nil {
- t.Fatal(err)
- } else {
- channels := result.Data.(*model.ChannelList)
-
- if len(*channels) != 0 {
- t.Fatal("should have no channels")
- }
- }
-
- Client.SetTeamId("junk")
- if _, err := Client.SearchMoreChannels(model.ChannelSearch{Term: "blargh"}); err == nil {
- t.Fatal("should have errored - bad team id")
- }
-}
-
-func TestAutocompleteChannels(t *testing.T) {
- th := Setup().InitBasic().InitSystemAdmin()
- defer th.TearDown()
-
- Client := th.BasicClient
- team := th.BasicTeam
-
- channel1 := &model.Channel{DisplayName: "TestAPINameA", Name: "zz" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
- channel1 = Client.Must(Client.CreateChannel(channel1)).Data.(*model.Channel)
-
- channel2 := &model.Channel{DisplayName: "TestAPINameB", Name: "b" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
- channel2 = Client.Must(Client.CreateChannel(channel2)).Data.(*model.Channel)
-
- channel3 := &model.Channel{DisplayName: "BadChannelC", Name: "c" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: model.NewId()}
- if _, err := th.SystemAdminClient.CreateChannel(channel3); err == nil {
- t.Fatal("channel must have valid team id")
- }
-
- channel4 := &model.Channel{DisplayName: "BadChannelD", Name: "d" + model.NewId() + "a", Type: model.CHANNEL_PRIVATE, TeamId: team.Id}
- channel4 = Client.Must(Client.CreateChannel(channel4)).Data.(*model.Channel)
-
- if result, err := Client.AutocompleteChannels("TestAPIName"); err != nil {
- t.Fatal(err)
- } else {
- channels := result.Data.(*model.ChannelList)
-
- if (*channels)[0].DisplayName != channel1.DisplayName {
- t.Fatal("full name didn't match")
- }
-
- if (*channels)[1].DisplayName != channel2.DisplayName {
- t.Fatal("full name didn't match")
- }
- }
-
- if result, err := Client.AutocompleteChannels(channel1.Name); err != nil {
- t.Fatal(err)
- } else {
- channels := result.Data.(*model.ChannelList)
-
- if (*channels)[0].DisplayName != channel1.DisplayName {
- t.Fatal("full name didn't match")
- }
- }
-
- if result, err := Client.AutocompleteChannels("BadChannelC"); err != nil {
- t.Fatal(err)
- } else {
- channels := result.Data.(*model.ChannelList)
-
- if len(*channels) != 0 {
- t.Fatal("should have been empty")
- }
- }
-
- if result, err := Client.AutocompleteChannels("BadChannelD"); err != nil {
- t.Fatal(err)
- } else {
- channels := result.Data.(*model.ChannelList)
-
- if len(*channels) != 0 {
- t.Fatal("should have been empty")
- }
- }
-
- Client.SetTeamId("junk")
-
- if _, err := Client.AutocompleteChannels("BadChannelD"); err == nil {
- t.Fatal("should have failed - bad team id")
- }
-}
-
-func TestGetChannelByName(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- Client := th.BasicClient
-
- if result, err := Client.GetChannelByName(th.BasicChannel.Name); err != nil {
- t.Fatal("Failed to get channel")
- } else {
- channel := result.Data.(*model.Channel)
- if channel.Name != th.BasicChannel.Name {
- t.Fatal("channel names did not match")
- }
- }
-
- if _, err := Client.GetChannelByName("InvalidChannelName"); err == nil {
- t.Fatal("Failed to get team")
- }
-
- Client.Must(Client.Logout())
-
- user2 := &model.User{Email: "success+" + model.NewId() + "@simulator.amazonses.com", Nickname: "Jabba the Hutt", Password: "passwd1"}
- user2 = Client.Must(Client.CreateUser(user2, "")).Data.(*model.User)
- store.Must(th.App.Srv.Store.User().VerifyEmail(user2.Id))
-
- Client.SetTeamId(th.BasicTeam.Id)
-
- Client.Login(user2.Email, "passwd1")
-
- if _, err := Client.GetChannelByName(th.BasicChannel.Name); err == nil {
- t.Fatal("Should fail due to not enough permissions")
- }
-}
-
-func TestViewChannel(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- Client := th.BasicClient
-
- view := model.ChannelView{
- ChannelId: th.BasicChannel.Id,
- }
-
- if _, resp := Client.ViewChannel(view); resp.Error != nil {
- t.Fatal(resp.Error)
- }
-
- view.PrevChannelId = th.BasicChannel.Id
-
- if _, resp := Client.ViewChannel(view); resp.Error != nil {
- t.Fatal(resp.Error)
- }
-
- view.PrevChannelId = ""
-
- if _, resp := Client.ViewChannel(view); resp.Error != nil {
- t.Fatal(resp.Error)
- }
-
- view.PrevChannelId = "junk"
-
- if _, resp := Client.ViewChannel(view); resp.Error != nil {
- t.Fatal(resp.Error)
- }
-
- rdata := Client.Must(Client.GetChannel(th.BasicChannel.Id, "")).Data.(*model.ChannelData)
-
- if rdata.Channel.TotalMsgCount != rdata.Member.MsgCount {
- t.Log(rdata.Channel.Id)
- t.Log(rdata.Member.UserId)
- t.Log(rdata.Channel.TotalMsgCount)
- t.Log(rdata.Member.MsgCount)
- t.Fatal("message counts don't match")
- }
-
- if _, err := Client.DoApiPost(Client.GetTeamRoute()+"/channels/view", "garbage"); err == nil {
- t.Fatal("should have been an error")
- }
-}
-
-func TestGetChannelMembersByIds(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- if _, err := th.App.AddUserToChannel(th.BasicUser2, th.BasicChannel); err != nil {
- t.Fatal("Could not add second user to channel")
- }
-
- if result, err := th.BasicClient.GetChannelMembersByIds(th.BasicChannel.Id, []string{th.BasicUser.Id}); err != nil {
- t.Fatal(err)
- } else {
- member := (*result.Data.(*model.ChannelMembers))[0]
- if member.UserId != th.BasicUser.Id {
- t.Fatal("user id did not match")
- }
- if member.ChannelId != th.BasicChannel.Id {
- t.Fatal("team id did not match")
- }
- }
-
- if result, err := th.BasicClient.GetChannelMembersByIds(th.BasicChannel.Id, []string{th.BasicUser.Id, th.BasicUser2.Id, model.NewId()}); err != nil {
- t.Fatal(err)
- } else {
- members := result.Data.(*model.ChannelMembers)
- if len(*members) != 2 {
- t.Fatal("length should have been 2, got ", len(*members))
- }
- }
-
- if _, err := th.BasicClient.GetChannelMembersByIds("junk", []string{th.BasicUser.Id}); err == nil {
- t.Fatal("should have errored - bad team id")
- }
-
- if _, err := th.BasicClient.GetChannelMembersByIds(th.BasicChannel.Id, []string{}); err == nil {
- t.Fatal("should have errored - empty user ids")
- }
-}
-
-func TestUpdateChannelRoles(t *testing.T) {
- th := Setup().InitSystemAdmin().InitBasic()
- defer th.TearDown()
-
- th.SystemAdminClient.SetTeamId(th.BasicTeam.Id)
- th.LinkUserToTeam(th.SystemAdminUser, th.BasicTeam)
-
- const CHANNEL_ADMIN = "channel_admin channel_user"
- const CHANNEL_MEMBER = "channel_user"
-
- // User 1 creates a channel, making them channel admin by default.
- createChannel := model.Channel{
- DisplayName: "Test API Name",
- Name: "zz" + model.NewId() + "a",
- Type: model.CHANNEL_OPEN,
- TeamId: th.BasicTeam.Id,
- }
-
- rchannel, err := th.BasicClient.CreateChannel(&createChannel)
- if err != nil {
- t.Fatal("Failed to create channel:", err)
- }
- channel := rchannel.Data.(*model.Channel)
-
- // User 1 adds User 2 to the channel, making them a channel member by default.
- if _, err := th.BasicClient.AddChannelMember(channel.Id, th.BasicUser2.Id); err != nil {
- t.Fatal("Failed to add user 2 to the channel:", err)
- }
-
- // System Admin can demote User 1 (channel admin).
- if data, meta := th.SystemAdminClient.UpdateChannelRoles(channel.Id, th.BasicUser.Id, CHANNEL_MEMBER); data == nil {
- t.Fatal("System Admin failed to demote channel admin to channel member:", meta)
- }
-
- // User 1 (channel_member) cannot promote user 2 (channel_member).
- if data, meta := th.BasicClient.UpdateChannelRoles(channel.Id, th.BasicUser2.Id, CHANNEL_ADMIN); data != nil {
- t.Fatal("Channel member should not be able to promote another channel member to channel admin:", meta)
- }
-
- // System Admin can promote user 1 (channel member).
- if data, meta := th.SystemAdminClient.UpdateChannelRoles(channel.Id, th.BasicUser.Id, CHANNEL_ADMIN); data == nil {
- t.Fatal("System Admin failed to promote channel member to channel admin:", meta)
- }
-
- // User 1 (channel_admin) can promote User 2 (channel member).
- if data, meta := th.BasicClient.UpdateChannelRoles(channel.Id, th.BasicUser2.Id, CHANNEL_ADMIN); data == nil {
- t.Fatal("Channel admin failed to promote channel member to channel admin:", meta)
- }
-
- // User 1 (channel admin) can demote User 2 (channel admin).
- if data, meta := th.BasicClient.UpdateChannelRoles(channel.Id, th.BasicUser2.Id, CHANNEL_MEMBER); data == nil {
- t.Fatal("Channel admin failed to demote channel admin to channel member:", meta)
- }
-
- // User 1 (channel admin) can demote itself.
- if data, meta := th.BasicClient.UpdateChannelRoles(channel.Id, th.BasicUser.Id, CHANNEL_MEMBER); data == nil {
- t.Fatal("Channel admin failed to demote itself to channel member:", meta)
- }
-
- // Promote User2 again for next test.
- if data, meta := th.SystemAdminClient.UpdateChannelRoles(channel.Id, th.BasicUser2.Id, CHANNEL_ADMIN); data == nil {
- t.Fatal("System Admin failed to promote channel member to channel admin:", meta)
- }
-
- // User 1 (channel member) cannot demote user 2 (channel admin).
- if data, meta := th.BasicClient.UpdateChannelRoles(channel.Id, th.BasicUser2.Id, CHANNEL_MEMBER); data != nil {
- t.Fatal("Channel member should not be able to demote another channel admin to channel member:", meta)
- }
-
- // User 1 (channel member) cannot promote itself.
- if data, meta := th.BasicClient.UpdateChannelRoles(channel.Id, th.BasicUser.Id, CHANNEL_ADMIN); data != nil {
- t.Fatal("Channel member should not be able to promote itself to channel admin:", meta)
- }
-}
-
-func TestGetPinnedPosts(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- Client := th.BasicClient
-
- post1 := th.BasicPost
- r1 := Client.Must(Client.GetPinnedPosts(post1.ChannelId)).Data.(*model.PostList)
- if len(r1.Order) != 0 {
- t.Fatal("should not have gotten a pinned post")
- }
-
- post2 := th.PinnedPost
- r2 := Client.Must(Client.GetPinnedPosts(post2.ChannelId)).Data.(*model.PostList)
- if len(r2.Order) == 0 {
- t.Fatal("should have gotten a pinned post")
- }
-
- if _, ok := r2.Posts[post2.Id]; !ok {
- t.Fatal("missing pinned post")
- }
-}
diff --git a/api/command.go b/api/command.go
deleted file mode 100644
index bbc7fbebd..000000000
--- a/api/command.go
+++ /dev/null
@@ -1,286 +0,0 @@
-// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-package api
-
-import (
- "io/ioutil"
- "net/http"
- "strings"
-
- "github.com/mattermost/mattermost-server/model"
-)
-
-func (api *API) InitCommand() {
- api.BaseRoutes.Commands.Handle("/execute", api.ApiUserRequired(executeCommand)).Methods("POST")
- api.BaseRoutes.Commands.Handle("/list", api.ApiUserRequired(listCommands)).Methods("GET")
-
- api.BaseRoutes.Commands.Handle("/create", api.ApiUserRequired(createCommand)).Methods("POST")
- api.BaseRoutes.Commands.Handle("/update", api.ApiUserRequired(updateCommand)).Methods("POST")
- api.BaseRoutes.Commands.Handle("/list_team_commands", api.ApiUserRequired(listTeamCommands)).Methods("GET")
- api.BaseRoutes.Commands.Handle("/regen_token", api.ApiUserRequired(regenCommandToken)).Methods("POST")
- api.BaseRoutes.Commands.Handle("/delete", api.ApiUserRequired(deleteCommand)).Methods("POST")
-
- api.BaseRoutes.Teams.Handle("/command_test", api.ApiAppHandler(testCommand)).Methods("POST")
- api.BaseRoutes.Teams.Handle("/command_test", api.ApiAppHandler(testCommand)).Methods("GET")
- api.BaseRoutes.Teams.Handle("/command_test_e", api.ApiAppHandler(testEphemeralCommand)).Methods("POST")
- api.BaseRoutes.Teams.Handle("/command_test_e", api.ApiAppHandler(testEphemeralCommand)).Methods("GET")
-}
-
-func listCommands(c *Context, w http.ResponseWriter, r *http.Request) {
- commands, err := c.App.ListAutocompleteCommands(c.TeamId, c.T)
- if err != nil {
- c.Err = err
- return
- }
-
- w.Write([]byte(model.CommandListToJson(commands)))
-}
-
-func executeCommand(c *Context, w http.ResponseWriter, r *http.Request) {
- commandArgs := model.CommandArgsFromJson(r.Body)
- if commandArgs == nil {
- c.SetInvalidParam("executeCommand", "command_args")
- return
- }
-
- if len(commandArgs.Command) <= 1 || strings.Index(commandArgs.Command, "/") != 0 {
- c.Err = model.NewAppError("executeCommand", "api.command.execute_command.start.app_error", nil, "", http.StatusBadRequest)
- return
- }
-
- if len(commandArgs.ChannelId) > 0 {
- if !c.App.SessionHasPermissionToChannel(c.Session, commandArgs.ChannelId, model.PERMISSION_USE_SLASH_COMMANDS) {
- c.SetPermissionError(model.PERMISSION_USE_SLASH_COMMANDS)
- return
- }
- }
-
- commandArgs.TeamId = c.TeamId
- commandArgs.UserId = c.Session.UserId
- commandArgs.T = c.T
- commandArgs.Session = c.Session
- commandArgs.SiteURL = c.GetSiteURLHeader()
-
- response, err := c.App.ExecuteCommand(commandArgs)
- if err != nil {
- c.Err = err
- return
- }
-
- w.Write([]byte(response.ToJson()))
-}
-
-func createCommand(c *Context, w http.ResponseWriter, r *http.Request) {
- cmd := model.CommandFromJson(r.Body)
-
- if cmd == nil {
- c.SetInvalidParam("createCommand", "command")
- return
- }
-
- c.LogAudit("attempt")
-
- if !c.App.SessionHasPermissionToTeam(c.Session, c.TeamId, model.PERMISSION_MANAGE_SLASH_COMMANDS) {
- c.SetPermissionError(model.PERMISSION_MANAGE_SLASH_COMMANDS)
- return
- }
-
- cmd.CreatorId = c.Session.UserId
- cmd.TeamId = c.TeamId
-
- rcmd, err := c.App.CreateCommand(cmd)
- if err != nil {
- c.Err = err
- return
- }
-
- c.LogAudit("success")
- w.Write([]byte(rcmd.ToJson()))
-}
-
-func updateCommand(c *Context, w http.ResponseWriter, r *http.Request) {
- cmd := model.CommandFromJson(r.Body)
-
- if cmd == nil {
- c.SetInvalidParam("updateCommand", "command")
- return
- }
-
- c.LogAudit("attempt")
-
- oldCmd, err := c.App.GetCommand(cmd.Id)
- if err != nil {
- c.Err = err
- return
- }
-
- if c.TeamId != oldCmd.TeamId {
- c.Err = model.NewAppError("updateCommand", "api.command.team_mismatch.app_error", nil, "user_id="+c.Session.UserId, http.StatusBadRequest)
- return
- }
-
- if !c.App.SessionHasPermissionToTeam(c.Session, oldCmd.TeamId, model.PERMISSION_MANAGE_SLASH_COMMANDS) {
- c.LogAudit("fail - inappropriate permissions")
- c.SetPermissionError(model.PERMISSION_MANAGE_SLASH_COMMANDS)
- return
- }
-
- if c.Session.UserId != oldCmd.CreatorId && !c.App.SessionHasPermissionToTeam(c.Session, c.TeamId, model.PERMISSION_MANAGE_OTHERS_SLASH_COMMANDS) {
- c.LogAudit("fail - inappropriate permissions")
- c.SetPermissionError(model.PERMISSION_MANAGE_OTHERS_SLASH_COMMANDS)
- return
- }
-
- rcmd, err := c.App.UpdateCommand(oldCmd, cmd)
- if err != nil {
- c.Err = err
- return
- }
-
- c.LogAudit("success")
-
- w.Write([]byte(rcmd.ToJson()))
-}
-
-func listTeamCommands(c *Context, w http.ResponseWriter, r *http.Request) {
- if !c.App.SessionHasPermissionToTeam(c.Session, c.TeamId, model.PERMISSION_MANAGE_SLASH_COMMANDS) {
- c.SetPermissionError(model.PERMISSION_MANAGE_SLASH_COMMANDS)
- return
- }
-
- cmds, err := c.App.ListTeamCommands(c.TeamId)
- if err != nil {
- c.Err = err
- return
- }
-
- w.Write([]byte(model.CommandListToJson(cmds)))
-}
-
-func regenCommandToken(c *Context, w http.ResponseWriter, r *http.Request) {
- props := model.MapFromJson(r.Body)
-
- id := props["id"]
- if len(id) == 0 {
- c.SetInvalidParam("regenCommandToken", "id")
- return
- }
-
- c.LogAudit("attempt")
-
- cmd, err := c.App.GetCommand(id)
- if err != nil {
- c.Err = err
- return
- }
-
- if c.TeamId != cmd.TeamId {
- c.Err = model.NewAppError("regenCommandToken", "api.command.team_mismatch.app_error", nil, "user_id="+c.Session.UserId, http.StatusBadRequest)
- return
- }
-
- if !c.App.SessionHasPermissionToTeam(c.Session, cmd.TeamId, model.PERMISSION_MANAGE_SLASH_COMMANDS) {
- c.LogAudit("fail - inappropriate permissions")
- c.SetPermissionError(model.PERMISSION_MANAGE_SLASH_COMMANDS)
- return
- }
-
- if c.Session.UserId != cmd.CreatorId && !c.App.SessionHasPermissionToTeam(c.Session, cmd.TeamId, model.PERMISSION_MANAGE_OTHERS_SLASH_COMMANDS) {
- c.LogAudit("fail - inappropriate permissions")
- c.SetPermissionError(model.PERMISSION_MANAGE_OTHERS_SLASH_COMMANDS)
- return
- }
-
- rcmd, err := c.App.RegenCommandToken(cmd)
- if err != nil {
- c.Err = err
- return
- }
-
- w.Write([]byte(rcmd.ToJson()))
-}
-
-func deleteCommand(c *Context, w http.ResponseWriter, r *http.Request) {
- props := model.MapFromJson(r.Body)
-
- id := props["id"]
- if len(id) == 0 {
- c.SetInvalidParam("deleteCommand", "id")
- return
- }
-
- c.LogAudit("attempt")
-
- cmd, err := c.App.GetCommand(id)
- if err != nil {
- c.Err = err
- return
- }
-
- if c.TeamId != cmd.TeamId {
- c.Err = model.NewAppError("deleteCommand", "api.command.team_mismatch.app_error", nil, "user_id="+c.Session.UserId, http.StatusBadRequest)
- return
- }
-
- if !c.App.SessionHasPermissionToTeam(c.Session, cmd.TeamId, model.PERMISSION_MANAGE_SLASH_COMMANDS) {
- c.SetPermissionError(model.PERMISSION_MANAGE_SLASH_COMMANDS)
- c.LogAudit("fail - inappropriate permissions")
- return
- }
-
- if c.Session.UserId != cmd.CreatorId && !c.App.SessionHasPermissionToTeam(c.Session, cmd.TeamId, model.PERMISSION_MANAGE_OTHERS_SLASH_COMMANDS) {
- c.SetPermissionError(model.PERMISSION_MANAGE_OTHERS_SLASH_COMMANDS)
- c.LogAudit("fail - inappropriate permissions")
- return
- }
-
- err = c.App.DeleteCommand(cmd.Id)
- if err != nil {
- c.Err = err
- return
- }
-
- c.LogAudit("success")
- w.Write([]byte(model.MapToJson(props)))
-}
-
-func testCommand(c *Context, w http.ResponseWriter, r *http.Request) {
- r.ParseForm()
-
- msg := ""
- if r.Method == "POST" {
- msg = msg + "\ntoken=" + r.FormValue("token")
- msg = msg + "\nteam_domain=" + r.FormValue("team_domain")
- } else {
- body, _ := ioutil.ReadAll(r.Body)
- msg = string(body)
- }
-
- rc := &model.CommandResponse{
- Text: "test command response " + msg,
- ResponseType: model.COMMAND_RESPONSE_TYPE_IN_CHANNEL,
- }
-
- w.Write([]byte(rc.ToJson()))
-}
-
-func testEphemeralCommand(c *Context, w http.ResponseWriter, r *http.Request) {
- r.ParseForm()
-
- msg := ""
- if r.Method == "POST" {
- msg = msg + "\ntoken=" + r.FormValue("token")
- msg = msg + "\nteam_domain=" + r.FormValue("team_domain")
- } else {
- body, _ := ioutil.ReadAll(r.Body)
- msg = string(body)
- }
-
- rc := &model.CommandResponse{
- Text: "test command response " + msg,
- ResponseType: model.COMMAND_RESPONSE_TYPE_EPHEMERAL,
- }
-
- w.Write([]byte(rc.ToJson()))
-}
diff --git a/api/command_echo_test.go b/api/command_echo_test.go
deleted file mode 100644
index 7a8697c19..000000000
--- a/api/command_echo_test.go
+++ /dev/null
@@ -1,36 +0,0 @@
-// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-package api
-
-import (
- "testing"
- "time"
-
- "github.com/mattermost/mattermost-server/model"
-)
-
-func TestEchoCommand(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- Client := th.BasicClient
- channel1 := th.BasicChannel
-
- echoTestString := "/echo test"
-
- if r1 := Client.Must(Client.Command(channel1.Id, echoTestString)).Data.(*model.CommandResponse); r1 == nil {
- t.Fatal("Echo command failed to execute")
- }
-
- if r1 := Client.Must(Client.Command(channel1.Id, "/echo ")).Data.(*model.CommandResponse); r1 == nil {
- t.Fatal("Echo command failed to execute")
- }
-
- time.Sleep(100 * time.Millisecond)
-
- p1 := Client.Must(Client.GetPosts(channel1.Id, 0, 2, "")).Data.(*model.PostList)
- if len(p1.Order) != 2 {
- t.Fatal("Echo command failed to send")
- }
-}
diff --git a/api/command_expand_collapse_test.go b/api/command_expand_collapse_test.go
deleted file mode 100644
index 96f92c58f..000000000
--- a/api/command_expand_collapse_test.go
+++ /dev/null
@@ -1,51 +0,0 @@
-// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-package api
-
-import (
- "testing"
- "time"
-
- "github.com/mattermost/mattermost-server/model"
-)
-
-func TestExpandCommand(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- Client := th.BasicClient
- channel := th.BasicChannel
-
- r1 := Client.Must(Client.Command(channel.Id, "/expand")).Data.(*model.CommandResponse)
- if r1 == nil {
- t.Fatal("Command failed to execute")
- }
-
- time.Sleep(100 * time.Millisecond)
-
- p1 := Client.Must(Client.GetPreference(model.PREFERENCE_CATEGORY_DISPLAY_SETTINGS, model.PREFERENCE_NAME_COLLAPSE_SETTING)).Data.(*model.Preference)
- if p1.Value != "false" {
- t.Fatal("preference not updated correctly")
- }
-}
-
-func TestCollapseCommand(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- Client := th.BasicClient
- channel := th.BasicChannel
-
- r1 := Client.Must(Client.Command(channel.Id, "/collapse")).Data.(*model.CommandResponse)
- if r1 == nil {
- t.Fatal("Command failed to execute")
- }
-
- time.Sleep(100 * time.Millisecond)
-
- p1 := Client.Must(Client.GetPreference(model.PREFERENCE_CATEGORY_DISPLAY_SETTINGS, model.PREFERENCE_NAME_COLLAPSE_SETTING)).Data.(*model.Preference)
- if p1.Value != "true" {
- t.Fatal("preference not updated correctly")
- }
-}
diff --git a/api/command_groupmsg_test.go b/api/command_groupmsg_test.go
deleted file mode 100644
index fcb9953ad..000000000
--- a/api/command_groupmsg_test.go
+++ /dev/null
@@ -1,58 +0,0 @@
-// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-package api
-
-import (
- "strings"
- "testing"
-
- "github.com/mattermost/mattermost-server/model"
-)
-
-func TestGroupmsgCommands(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- Client := th.BasicClient
- team := th.BasicTeam
- user1 := th.BasicUser
- user2 := th.BasicUser2
- user3 := th.CreateUser(th.BasicClient)
- user4 := th.CreateUser(th.BasicClient)
- user5 := th.CreateUser(th.BasicClient)
- user6 := th.CreateUser(th.BasicClient)
- user7 := th.CreateUser(th.BasicClient)
- user8 := th.CreateUser(th.BasicClient)
- user9 := th.CreateUser(th.BasicClient)
- th.LinkUserToTeam(user3, team)
- th.LinkUserToTeam(user4, team)
-
- rs1 := Client.Must(Client.Command("", "/groupmsg "+user2.Username+","+user3.Username)).Data.(*model.CommandResponse)
-
- group1 := model.GetGroupNameFromUserIds([]string{user1.Id, user2.Id, user3.Id})
-
- if !strings.HasSuffix(rs1.GotoLocation, "/"+team.Name+"/channels/"+group1) {
- t.Fatal("failed to create group channel")
- }
-
- rs2 := Client.Must(Client.Command("", "/groupmsg "+user3.Username+","+user4.Username+" foobar")).Data.(*model.CommandResponse)
- group2 := model.GetGroupNameFromUserIds([]string{user1.Id, user3.Id, user4.Id})
-
- if !strings.HasSuffix(rs2.GotoLocation, "/"+team.Name+"/channels/"+group2) {
- t.Fatal("failed to create second direct channel")
- }
- if result := Client.Must(Client.SearchPosts("foobar", false)).Data.(*model.PostList); len(result.Order) == 0 {
- t.Fatal("post did not get sent to direct message")
- }
-
- rs3 := Client.Must(Client.Command("", "/groupmsg "+user2.Username+","+user3.Username)).Data.(*model.CommandResponse)
- if !strings.HasSuffix(rs3.GotoLocation, "/"+team.Name+"/channels/"+group1) {
- t.Fatal("failed to go back to existing group channel")
- }
-
- Client.Must(Client.Command("", "/groupmsg "+user2.Username+" foobar"))
- Client.Must(Client.Command("", "/groupmsg "+user2.Username+","+user3.Username+","+user4.Username+","+user5.Username+","+user6.Username+","+user7.Username+","+user8.Username+","+user9.Username+" foobar"))
- Client.Must(Client.Command("", "/groupmsg junk foobar"))
- Client.Must(Client.Command("", "/groupmsg junk,junk2 foobar"))
-}
diff --git a/api/command_help_test.go b/api/command_help_test.go
deleted file mode 100644
index 181298d7e..000000000
--- a/api/command_help_test.go
+++ /dev/null
@@ -1,37 +0,0 @@
-// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-package api
-
-import (
- "testing"
-
- "github.com/mattermost/mattermost-server/model"
-)
-
-func TestHelpCommand(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- Client := th.BasicClient
- channel := th.BasicChannel
-
- HelpLink := *th.App.Config().SupportSettings.HelpLink
- defer func() {
- th.App.UpdateConfig(func(cfg *model.Config) { *cfg.SupportSettings.HelpLink = HelpLink })
- }()
-
- th.App.UpdateConfig(func(cfg *model.Config) { *cfg.SupportSettings.HelpLink = "" })
- rs1 := Client.Must(Client.Command(channel.Id, "/help ")).Data.(*model.CommandResponse)
- if rs1.GotoLocation != model.SUPPORT_SETTINGS_DEFAULT_HELP_LINK {
- t.Fatal("failed to default help link")
- }
-
- th.App.UpdateConfig(func(cfg *model.Config) {
- *cfg.SupportSettings.HelpLink = "https://docs.mattermost.com/guides/user.html"
- })
- rs2 := Client.Must(Client.Command(channel.Id, "/help ")).Data.(*model.CommandResponse)
- if rs2.GotoLocation != "https://docs.mattermost.com/guides/user.html" {
- t.Fatal("failed to help link")
- }
-}
diff --git a/api/command_invite_people_test.go b/api/command_invite_people_test.go
deleted file mode 100644
index 950e2c2a8..000000000
--- a/api/command_invite_people_test.go
+++ /dev/null
@@ -1,33 +0,0 @@
-// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-package api
-
-import (
- "testing"
-
- "github.com/mattermost/mattermost-server/model"
-)
-
-func TestInvitePeopleCommand(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- Client := th.BasicClient
- channel := th.BasicChannel
-
- r1 := Client.Must(Client.Command(channel.Id, "/invite_people test@example.com")).Data.(*model.CommandResponse)
- if r1 == nil {
- t.Fatal("Command failed to execute")
- }
-
- r2 := Client.Must(Client.Command(channel.Id, "/invite_people test1@example.com test2@example.com")).Data.(*model.CommandResponse)
- if r2 == nil {
- t.Fatal("Command failed to execute")
- }
-
- r3 := Client.Must(Client.Command(channel.Id, "/invite_people")).Data.(*model.CommandResponse)
- if r3 == nil {
- t.Fatal("Command failed to execute")
- }
-}
diff --git a/api/command_join_test.go b/api/command_join_test.go
deleted file mode 100644
index 7926f9bf6..000000000
--- a/api/command_join_test.go
+++ /dev/null
@@ -1,61 +0,0 @@
-// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-package api
-
-import (
- "strings"
- "testing"
-
- "github.com/mattermost/mattermost-server/model"
-)
-
-// also used to test /open (see command_open_test.go)
-func testJoinCommands(t *testing.T, alias string) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- Client := th.BasicClient
- team := th.BasicTeam
- user2 := th.BasicUser2
-
- channel0 := &model.Channel{DisplayName: "00", Name: "00" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
- channel0 = Client.Must(Client.CreateChannel(channel0)).Data.(*model.Channel)
-
- channel1 := &model.Channel{DisplayName: "AA", Name: "aa" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
- channel1 = Client.Must(Client.CreateChannel(channel1)).Data.(*model.Channel)
- Client.Must(Client.LeaveChannel(channel1.Id))
-
- channel2 := &model.Channel{DisplayName: "BB", Name: "bb" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
- channel2 = Client.Must(Client.CreateChannel(channel2)).Data.(*model.Channel)
- Client.Must(Client.LeaveChannel(channel2.Id))
-
- channel3 := Client.Must(Client.CreateDirectChannel(user2.Id)).Data.(*model.Channel)
-
- rs5 := Client.Must(Client.Command(channel0.Id, "/"+alias+" "+channel2.Name)).Data.(*model.CommandResponse)
- if !strings.HasSuffix(rs5.GotoLocation, "/"+team.Name+"/channels/"+channel2.Name) {
- t.Fatal("failed to join channel")
- }
-
- rs6 := Client.Must(Client.Command(channel0.Id, "/"+alias+" "+channel3.Name)).Data.(*model.CommandResponse)
- if strings.HasSuffix(rs6.GotoLocation, "/"+team.Name+"/channels/"+channel3.Name) {
- t.Fatal("should not have joined direct message channel")
- }
-
- c1 := Client.Must(Client.GetChannels("")).Data.(*model.ChannelList)
-
- found := false
- for _, c := range *c1 {
- if c.Id == channel2.Id {
- found = true
- }
- }
-
- if !found {
- t.Fatal("did not join channel")
- }
-}
-
-func TestJoinCommands(t *testing.T) {
- testJoinCommands(t, "join")
-}
diff --git a/api/command_leave_test.go b/api/command_leave_test.go
deleted file mode 100644
index 17855c851..000000000
--- a/api/command_leave_test.go
+++ /dev/null
@@ -1,68 +0,0 @@
-// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-package api
-
-import (
- "strings"
- "testing"
-
- "github.com/mattermost/mattermost-server/model"
-)
-
-func TestLeaveCommands(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- Client := th.BasicClient
- team := th.BasicTeam
- user2 := th.BasicUser2
-
- channel1 := &model.Channel{DisplayName: "AA", Name: "aa" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
- channel1 = Client.Must(Client.CreateChannel(channel1)).Data.(*model.Channel)
- Client.Must(Client.JoinChannel(channel1.Id))
-
- channel2 := &model.Channel{DisplayName: "BB", Name: "bb" + model.NewId() + "a", Type: model.CHANNEL_PRIVATE, TeamId: team.Id}
- channel2 = Client.Must(Client.CreateChannel(channel2)).Data.(*model.Channel)
- Client.Must(Client.JoinChannel(channel2.Id))
- Client.Must(Client.AddChannelMember(channel2.Id, user2.Id))
-
- channel3 := Client.Must(Client.CreateDirectChannel(user2.Id)).Data.(*model.Channel)
-
- rs1 := Client.Must(Client.Command(channel1.Id, "/leave")).Data.(*model.CommandResponse)
- if !strings.HasSuffix(rs1.GotoLocation, "/"+team.Name+"/channels/"+model.DEFAULT_CHANNEL) {
- t.Fatal("failed to leave open channel 1")
- }
-
- rs2 := Client.Must(Client.Command(channel2.Id, "/leave")).Data.(*model.CommandResponse)
- if !strings.HasSuffix(rs2.GotoLocation, "/"+team.Name+"/channels/"+model.DEFAULT_CHANNEL) {
- t.Fatal("failed to leave private channel 1")
- }
-
- rs3 := Client.Must(Client.Command(channel3.Id, "/leave")).Data.(*model.CommandResponse)
- if strings.HasSuffix(rs3.GotoLocation, "/"+team.Name+"/channels/"+model.DEFAULT_CHANNEL) {
- t.Fatal("should not have left direct message channel")
- }
-
- cdata := Client.Must(Client.GetChannels("")).Data.(*model.ChannelList)
-
- found := false
- for _, c := range *cdata {
- if c.Id == channel1.Id || c.Id == channel2.Id {
- found = true
- }
- }
-
- if found {
- t.Fatal("did not leave right channels")
- }
-
- for _, c := range *cdata {
- if c.Name == model.DEFAULT_CHANNEL {
- if _, err := Client.LeaveChannel(c.Id); err == nil {
- t.Fatal("should have errored on leaving default channel")
- }
- break
- }
- }
-}
diff --git a/api/command_loadtest_test.go b/api/command_loadtest_test.go
deleted file mode 100644
index 570b8a09b..000000000
--- a/api/command_loadtest_test.go
+++ /dev/null
@@ -1,97 +0,0 @@
-// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-package api
-
-import (
- "strings"
- "testing"
- "time"
-
- "github.com/mattermost/mattermost-server/model"
-)
-
-func TestLoadTestHelpCommands(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- Client := th.BasicClient
- channel := th.BasicChannel
-
- th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableTesting = true })
-
- rs := Client.Must(Client.Command(channel.Id, "/test help")).Data.(*model.CommandResponse)
- if !strings.Contains(rs.Text, "Mattermost testing commands to help") {
- t.Fatal(rs.Text)
- }
-
- time.Sleep(2 * time.Second)
-}
-
-func TestLoadTestSetupCommands(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- Client := th.BasicClient
- channel := th.BasicChannel
-
- th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableTesting = true })
-
- rs := Client.Must(Client.Command(channel.Id, "/test setup fuzz 1 1 1")).Data.(*model.CommandResponse)
- if rs.Text != "Created environment" {
- t.Fatal(rs.Text)
- }
-
- time.Sleep(2 * time.Second)
-}
-
-func TestLoadTestUsersCommands(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- Client := th.BasicClient
- channel := th.BasicChannel
-
- th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableTesting = true })
-
- rs := Client.Must(Client.Command(channel.Id, "/test users fuzz 1 2")).Data.(*model.CommandResponse)
- if rs.Text != "Added users" {
- t.Fatal(rs.Text)
- }
-
- time.Sleep(2 * time.Second)
-}
-
-func TestLoadTestChannelsCommands(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- Client := th.BasicClient
- channel := th.BasicChannel
-
- th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableTesting = true })
-
- rs := Client.Must(Client.Command(channel.Id, "/test channels fuzz 1 2")).Data.(*model.CommandResponse)
- if rs.Text != "Added channels" {
- t.Fatal(rs.Text)
- }
-
- time.Sleep(2 * time.Second)
-}
-
-func TestLoadTestPostsCommands(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- Client := th.BasicClient
- channel := th.BasicChannel
-
- th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableTesting = true })
-
- rs := Client.Must(Client.Command(channel.Id, "/test posts fuzz 2 3 2")).Data.(*model.CommandResponse)
- if rs.Text != "Added posts" {
- t.Fatal(rs.Text)
- }
-
- time.Sleep(2 * time.Second)
-}
diff --git a/api/command_logout_test.go b/api/command_logout_test.go
deleted file mode 100644
index cbd75dd93..000000000
--- a/api/command_logout_test.go
+++ /dev/null
@@ -1,15 +0,0 @@
-// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-package api
-
-import (
- "testing"
-)
-
-func TestLogoutTestCommand(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- th.BasicClient.Must(th.BasicClient.Command(th.BasicChannel.Id, "/logout"))
-}
diff --git a/api/command_me_test.go b/api/command_me_test.go
deleted file mode 100644
index 63718ca68..000000000
--- a/api/command_me_test.go
+++ /dev/null
@@ -1,38 +0,0 @@
-// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-package api
-
-import (
- "testing"
- "time"
-
- "github.com/mattermost/mattermost-server/model"
-)
-
-func TestMeCommand(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- Client := th.BasicClient
- channel := th.BasicChannel
-
- testString := "/me hello"
-
- r1 := Client.Must(Client.Command(channel.Id, testString)).Data.(*model.CommandResponse)
- if r1 == nil {
- t.Fatal("Command failed to execute")
- }
-
- time.Sleep(100 * time.Millisecond)
-
- p1 := Client.Must(Client.GetPosts(channel.Id, 0, 2, "")).Data.(*model.PostList)
- if len(p1.Order) != 2 {
- t.Fatal("Command failed to send")
- } else {
- if p1.Posts[p1.Order[0]].Message != `*hello*` {
- t.Log(p1.Posts[p1.Order[0]].Message)
- t.Fatal("invalid shrug response")
- }
- }
-}
diff --git a/api/command_msg_test.go b/api/command_msg_test.go
deleted file mode 100644
index 07cce149c..000000000
--- a/api/command_msg_test.go
+++ /dev/null
@@ -1,47 +0,0 @@
-// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-package api
-
-import (
- "strings"
- "testing"
-
- "github.com/mattermost/mattermost-server/model"
-)
-
-func TestMsgCommands(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- Client := th.BasicClient
- team := th.BasicTeam
- user1 := th.BasicUser
- user2 := th.BasicUser2
- user3 := th.CreateUser(th.BasicClient)
- th.LinkUserToTeam(user3, team)
-
- Client.Must(Client.CreateDirectChannel(user2.Id))
- Client.Must(Client.CreateDirectChannel(user3.Id))
-
- rs1 := Client.Must(Client.Command("", "/msg "+user2.Username)).Data.(*model.CommandResponse)
- if !strings.HasSuffix(rs1.GotoLocation, "/"+team.Name+"/channels/"+user1.Id+"__"+user2.Id) && !strings.HasSuffix(rs1.GotoLocation, "/"+team.Name+"/channels/"+user2.Id+"__"+user1.Id) {
- t.Fatal("failed to create direct channel")
- }
-
- rs2 := Client.Must(Client.Command("", "/msg "+user3.Username+" foobar")).Data.(*model.CommandResponse)
- if !strings.HasSuffix(rs2.GotoLocation, "/"+team.Name+"/channels/"+user1.Id+"__"+user3.Id) && !strings.HasSuffix(rs2.GotoLocation, "/"+team.Name+"/channels/"+user3.Id+"__"+user1.Id) {
- t.Fatal("failed to create second direct channel")
- }
- if result := Client.Must(Client.SearchPosts("foobar", false)).Data.(*model.PostList); len(result.Order) == 0 {
- t.Fatalf("post did not get sent to direct message")
- }
-
- rs3 := Client.Must(Client.Command("", "/msg "+user2.Username)).Data.(*model.CommandResponse)
- if !strings.HasSuffix(rs3.GotoLocation, "/"+team.Name+"/channels/"+user1.Id+"__"+user2.Id) && !strings.HasSuffix(rs3.GotoLocation, "/"+team.Name+"/channels/"+user2.Id+"__"+user1.Id) {
- t.Fatal("failed to go back to existing direct channel")
- }
-
- Client.Must(Client.Command("", "/msg "+th.BasicUser.Username+" foobar"))
- Client.Must(Client.Command("", "/msg junk foobar"))
-}
diff --git a/api/command_open_test.go b/api/command_open_test.go
deleted file mode 100644
index 61e3861d8..000000000
--- a/api/command_open_test.go
+++ /dev/null
@@ -1,12 +0,0 @@
-// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-package api
-
-import (
- "testing"
-)
-
-func TestOpenCommands(t *testing.T) {
- testJoinCommands(t, "open")
-}
diff --git a/api/command_search_test.go b/api/command_search_test.go
deleted file mode 100644
index a7f187d36..000000000
--- a/api/command_search_test.go
+++ /dev/null
@@ -1,15 +0,0 @@
-// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-package api
-
-import (
- "testing"
-)
-
-func TestSearchCommand(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- th.BasicClient.Must(th.BasicClient.Command(th.BasicChannel.Id, "/search"))
-}
diff --git a/api/command_settings_test.go b/api/command_settings_test.go
deleted file mode 100644
index af137ce97..000000000
--- a/api/command_settings_test.go
+++ /dev/null
@@ -1,15 +0,0 @@
-// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-package api
-
-import (
- "testing"
-)
-
-func TestSettingsCommand(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- th.BasicClient.Must(th.BasicClient.Command(th.BasicChannel.Id, "/settings"))
-}
diff --git a/api/command_shortcuts_test.go b/api/command_shortcuts_test.go
deleted file mode 100644
index e6ff17910..000000000
--- a/api/command_shortcuts_test.go
+++ /dev/null
@@ -1,15 +0,0 @@
-// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-package api
-
-import (
- "testing"
-)
-
-func TestShortcutsCommand(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- th.BasicClient.Must(th.BasicClient.Command(th.BasicChannel.Id, "/shortcuts"))
-}
diff --git a/api/command_shrug_test.go b/api/command_shrug_test.go
deleted file mode 100644
index 9b453a48d..000000000
--- a/api/command_shrug_test.go
+++ /dev/null
@@ -1,38 +0,0 @@
-// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-package api
-
-import (
- "testing"
- "time"
-
- "github.com/mattermost/mattermost-server/model"
-)
-
-func TestShrugCommand(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- Client := th.BasicClient
- channel := th.BasicChannel
-
- testString := "/shrug"
-
- r1 := Client.Must(Client.Command(channel.Id, testString)).Data.(*model.CommandResponse)
- if r1 == nil {
- t.Fatal("Command failed to execute")
- }
-
- time.Sleep(100 * time.Millisecond)
-
- p1 := Client.Must(Client.GetPosts(channel.Id, 0, 2, "")).Data.(*model.PostList)
- if len(p1.Order) != 2 {
- t.Fatal("Command failed to send")
- } else {
- if p1.Posts[p1.Order[0]].Message != `¯\\\_(ツ)\_/¯` {
- t.Log(p1.Posts[p1.Order[0]].Message)
- t.Fatal("invalid shrug response")
- }
- }
-}
diff --git a/api/command_statuses_test.go b/api/command_statuses_test.go
deleted file mode 100644
index 0ac651636..000000000
--- a/api/command_statuses_test.go
+++ /dev/null
@@ -1,42 +0,0 @@
-// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-package api
-
-import (
- "testing"
- "time"
-
- "github.com/mattermost/mattermost-server/model"
-)
-
-func TestStatusCommands(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- commandAndTest(t, th, "away")
- commandAndTest(t, th, "offline")
- commandAndTest(t, th, "online")
-}
-
-func commandAndTest(t *testing.T, th *TestHelper, status string) {
- Client := th.BasicClient
- channel := th.BasicChannel
- user := th.BasicUser
-
- r1 := Client.Must(Client.Command(channel.Id, "/"+status)).Data.(*model.CommandResponse)
- if r1 == nil {
- t.Fatal("Command failed to execute")
- }
-
- time.Sleep(1000 * time.Millisecond)
-
- statuses := Client.Must(Client.GetStatuses()).Data.(map[string]string)
-
- if status == "offline" {
- status = ""
- }
- if statuses[user.Id] != status {
- t.Fatal("Error setting status " + status)
- }
-}
diff --git a/api/command_test.go b/api/command_test.go
deleted file mode 100644
index 7f9c6dcff..000000000
--- a/api/command_test.go
+++ /dev/null
@@ -1,310 +0,0 @@
-// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-package api
-
-import (
- "fmt"
- "strings"
- "testing"
- "time"
-
- "github.com/mattermost/mattermost-server/model"
-)
-
-func TestListCommands(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- Client := th.BasicClient
-
- if results, err := Client.ListCommands(); err != nil {
- t.Fatal(err)
- } else {
- commands := results.Data.([]*model.Command)
- foundEcho := false
-
- for _, command := range commands {
- if command.Trigger == "echo" {
- foundEcho = true
- }
- }
-
- if !foundEcho {
- t.Fatal("Couldn't find echo command")
- }
- }
-}
-
-func TestCreateCommand(t *testing.T) {
- th := Setup().InitBasic().InitSystemAdmin()
- defer th.TearDown()
-
- Client := th.BasicClient
- user := th.SystemAdminUser
- team := th.SystemAdminTeam
-
- enableCommands := *th.App.Config().ServiceSettings.EnableCommands
- defer func() {
- th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableCommands = &enableCommands })
- }()
- th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableCommands = true })
-
- cmd1 := &model.Command{
- CreatorId: user.Id,
- TeamId: team.Id,
- URL: "http://nowhere.com",
- Method: model.COMMAND_METHOD_POST,
- Trigger: "trigger"}
-
- if _, err := Client.CreateCommand(cmd1); err == nil {
- t.Fatal("should have failed because not admin")
- }
-
- Client = th.SystemAdminClient
-
- cmd2 := &model.Command{
- CreatorId: user.Id,
- TeamId: team.Id,
- URL: "http://nowhere.com",
- Method: model.COMMAND_METHOD_POST,
- Trigger: "trigger"}
-
- var rcmd *model.Command
- if result, err := Client.CreateCommand(cmd2); err != nil {
- t.Fatal(err)
- } else {
- rcmd = result.Data.(*model.Command)
- }
-
- if rcmd.CreatorId != user.Id {
- t.Fatal("user ids didn't match")
- }
-
- if rcmd.TeamId != team.Id {
- t.Fatal("team ids didn't match")
- }
-
- cmd3 := &model.Command{
- CreatorId: "123",
- TeamId: "456",
- URL: "http://nowhere.com",
- Method: model.COMMAND_METHOD_POST,
- Trigger: "trigger"}
- if _, err := Client.CreateCommand(cmd3); err == nil {
- t.Fatal("trigger cannot be duplicated")
- }
-
- cmd4 := cmd3
- if _, err := Client.CreateCommand(cmd4); err == nil {
- t.Fatal("command cannot be duplicated")
- }
-}
-
-func TestListTeamCommands(t *testing.T) {
- th := Setup().InitSystemAdmin()
- defer th.TearDown()
-
- Client := th.SystemAdminClient
-
- enableCommands := *th.App.Config().ServiceSettings.EnableCommands
- defer func() {
- th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableCommands = &enableCommands })
- }()
- th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableCommands = true })
-
- cmd1 := &model.Command{URL: "http://nowhere.com", Method: model.COMMAND_METHOD_POST, Trigger: "trigger"}
- cmd1 = Client.Must(Client.CreateCommand(cmd1)).Data.(*model.Command)
-
- if result, err := Client.ListTeamCommands(); err != nil {
- t.Fatal(err)
- } else {
- cmds := result.Data.([]*model.Command)
-
- if len(cmds) != 1 {
- t.Fatal("incorrect number of cmd")
- }
- }
-}
-
-func TestUpdateCommand(t *testing.T) {
- th := Setup().InitSystemAdmin()
- defer th.TearDown()
-
- Client := th.SystemAdminClient
- user := th.SystemAdminUser
- team := th.SystemAdminTeam
-
- enableCommands := *th.App.Config().ServiceSettings.EnableCommands
- defer func() {
- th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableCommands = &enableCommands })
- }()
- th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableCommands = true })
-
- cmd1 := &model.Command{
- CreatorId: user.Id,
- TeamId: team.Id,
- URL: "http://nowhere.com",
- Method: model.COMMAND_METHOD_POST,
- Trigger: "trigger"}
-
- cmd1 = Client.Must(Client.CreateCommand(cmd1)).Data.(*model.Command)
-
- cmd2 := &model.Command{
- CreatorId: user.Id,
- TeamId: team.Id,
- URL: "http://nowhere.com",
- Method: model.COMMAND_METHOD_POST,
- Trigger: "trigger2",
- Token: cmd1.Token,
- Id: cmd1.Id}
-
- if result, err := Client.UpdateCommand(cmd2); err != nil {
- t.Fatal(err)
- } else {
- if result.Data.(*model.Command).Trigger == cmd1.Trigger {
- t.Fatal("update didn't work properly")
- }
- }
-}
-
-func TestRegenToken(t *testing.T) {
- th := Setup().InitSystemAdmin()
- defer th.TearDown()
-
- Client := th.SystemAdminClient
-
- enableCommands := *th.App.Config().ServiceSettings.EnableCommands
- defer func() {
- th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableCommands = &enableCommands })
- }()
- th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableCommands = true })
-
- cmd := &model.Command{URL: "http://nowhere.com", Method: model.COMMAND_METHOD_POST, Trigger: "trigger"}
- cmd = Client.Must(Client.CreateCommand(cmd)).Data.(*model.Command)
-
- data := make(map[string]string)
- data["id"] = cmd.Id
-
- if result, err := Client.RegenCommandToken(data); err != nil {
- t.Fatal(err)
- } else {
- if result.Data.(*model.Command).Token == cmd.Token {
- t.Fatal("regen didn't work properly")
- }
- }
-}
-
-func TestDeleteCommand(t *testing.T) {
- th := Setup().InitBasic().InitSystemAdmin()
- defer th.TearDown()
-
- Client := th.SystemAdminClient
-
- enableCommands := *th.App.Config().ServiceSettings.EnableCommands
- defer func() {
- th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableCommands = enableCommands })
- }()
- th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableCommands = true })
-
- cmd := &model.Command{URL: "http://nowhere.com", Method: model.COMMAND_METHOD_POST, Trigger: "trigger"}
- cmd = Client.Must(Client.CreateCommand(cmd)).Data.(*model.Command)
-
- data := make(map[string]string)
- data["id"] = cmd.Id
-
- if _, err := Client.DeleteCommand(data); err != nil {
- t.Fatal(err)
- }
-
- cmds := Client.Must(Client.ListTeamCommands()).Data.([]*model.Command)
- if len(cmds) != 0 {
- t.Fatal("delete didn't work properly")
- }
-
- cmd2 := &model.Command{URL: "http://nowhere.com", Method: model.COMMAND_METHOD_POST, Trigger: "trigger2"}
- cmd2 = Client.Must(Client.CreateCommand(cmd2)).Data.(*model.Command)
-
- data2 := make(map[string]string)
- data2["id"] = cmd2.Id
- if _, err := th.BasicClient.DeleteCommand(data2); err == nil {
- t.Fatal("Should have errored. Your not allowed to delete other's commands")
- }
-
- cmds2 := Client.Must(Client.ListTeamCommands()).Data.([]*model.Command)
- if len(cmds2) != 1 {
- t.Fatal("Client was able to delete command without permission.")
- }
-}
-
-func TestTestCommand(t *testing.T) {
- th := Setup().InitSystemAdmin()
- defer th.TearDown()
-
- Client := th.SystemAdminClient
- channel1 := th.SystemAdminChannel
-
- enableCommands := *th.App.Config().ServiceSettings.EnableCommands
- allowedInternalConnections := *th.App.Config().ServiceSettings.AllowedUntrustedInternalConnections
- defer func() {
- th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableCommands = &enableCommands })
- th.App.UpdateConfig(func(cfg *model.Config) {
- cfg.ServiceSettings.AllowedUntrustedInternalConnections = &allowedInternalConnections
- })
- }()
- th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableCommands = true })
- th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.AllowedUntrustedInternalConnections = "localhost" })
-
- cmd1 := &model.Command{
- URL: fmt.Sprintf("http://localhost:%v", th.App.Srv.ListenAddr.Port) + model.API_URL_SUFFIX_V3 + "/teams/command_test",
- Method: model.COMMAND_METHOD_POST,
- Trigger: "testcommand",
- }
-
- cmd1 = Client.Must(Client.CreateCommand(cmd1)).Data.(*model.Command)
-
- r1 := Client.Must(Client.Command(channel1.Id, "/testcommand")).Data.(*model.CommandResponse)
- if r1 == nil {
- t.Fatal("Test command failed to execute")
- }
-
- time.Sleep(100 * time.Millisecond)
-
- p1 := Client.Must(Client.GetPosts(channel1.Id, 0, 10, "")).Data.(*model.PostList)
- // including system 'joined' message
- if len(p1.Order) != 2 {
- t.Fatal("Test command response failed to send")
- }
-
- cmdPosted := false
- for _, post := range p1.Posts {
- if strings.Contains(post.Message, "test command response") {
- cmdPosted = true
- break
- }
- }
-
- if !cmdPosted {
- t.Fatal("Test command response failed to post")
- }
-
- cmd2 := &model.Command{
- URL: fmt.Sprintf("http://localhost:%v", th.App.Srv.ListenAddr.Port) + model.API_URL_SUFFIX_V3 + "/teams/command_test",
- Method: model.COMMAND_METHOD_GET,
- Trigger: "test2",
- }
-
- cmd2 = Client.Must(Client.CreateCommand(cmd2)).Data.(*model.Command)
-
- r2 := Client.Must(Client.Command(channel1.Id, "/test2")).Data.(*model.CommandResponse)
- if r2 == nil {
- t.Fatal("Test2 command failed to execute")
- }
-
- time.Sleep(100 * time.Millisecond)
-
- p2 := Client.Must(Client.GetPosts(channel1.Id, 0, 10, "")).Data.(*model.PostList)
- if len(p2.Order) != 3 {
- t.Fatal("Test command failed to send")
- }
-}
diff --git a/api/context.go b/api/context.go
deleted file mode 100644
index 8ebb5f73b..000000000
--- a/api/context.go
+++ /dev/null
@@ -1,451 +0,0 @@
-// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-package api
-
-import (
- "fmt"
- "net/http"
- "net/url"
- "strings"
- "sync/atomic"
- "time"
-
- "github.com/gorilla/mux"
- goi18n "github.com/nicksnyder/go-i18n/i18n"
-
- "github.com/mattermost/mattermost-server/app"
- "github.com/mattermost/mattermost-server/mlog"
- "github.com/mattermost/mattermost-server/model"
- "github.com/mattermost/mattermost-server/utils"
-)
-
-type Context struct {
- App *app.App
- Session model.Session
- RequestId string
- IpAddress string
- Path string
- Err *model.AppError
- siteURLHeader string
- teamURLValid bool
- teamURL string
- T goi18n.TranslateFunc
- Locale string
- TeamId string
-}
-
-func (api *API) ApiAppHandler(h func(*Context, http.ResponseWriter, *http.Request)) http.Handler {
- return &handler{api.App, h, false, false, true, false, false, false, false}
-}
-
-func (api *API) AppHandler(h func(*Context, http.ResponseWriter, *http.Request)) http.Handler {
- return &handler{api.App, h, false, false, false, false, false, false, false}
-}
-
-func (api *API) AppHandlerIndependent(h func(*Context, http.ResponseWriter, *http.Request)) http.Handler {
- return &handler{api.App, h, false, false, false, false, true, false, false}
-}
-
-func (api *API) ApiUserRequired(h func(*Context, http.ResponseWriter, *http.Request)) http.Handler {
- return &handler{api.App, h, true, false, true, false, false, false, true}
-}
-
-func (api *API) ApiUserRequiredActivity(h func(*Context, http.ResponseWriter, *http.Request), isUserActivity bool) http.Handler {
- return &handler{api.App, h, true, false, true, isUserActivity, false, false, true}
-}
-
-func (api *API) ApiUserRequiredMfa(h func(*Context, http.ResponseWriter, *http.Request)) http.Handler {
- return &handler{api.App, h, true, false, true, false, false, false, false}
-}
-
-func (api *API) UserRequired(h func(*Context, http.ResponseWriter, *http.Request)) http.Handler {
- return &handler{api.App, h, true, false, false, false, false, false, true}
-}
-
-func (api *API) AppHandlerTrustRequester(h func(*Context, http.ResponseWriter, *http.Request)) http.Handler {
- return &handler{api.App, h, false, false, false, false, false, true, false}
-}
-
-func (api *API) ApiAdminSystemRequired(h func(*Context, http.ResponseWriter, *http.Request)) http.Handler {
- return &handler{api.App, h, true, true, true, false, false, false, true}
-}
-
-func (api *API) ApiAdminSystemRequiredTrustRequester(h func(*Context, http.ResponseWriter, *http.Request)) http.Handler {
- return &handler{api.App, h, true, true, true, false, false, true, true}
-}
-
-func (api *API) ApiAppHandlerTrustRequester(h func(*Context, http.ResponseWriter, *http.Request)) http.Handler {
- return &handler{api.App, h, false, false, true, false, false, true, false}
-}
-
-func (api *API) ApiUserRequiredTrustRequester(h func(*Context, http.ResponseWriter, *http.Request)) http.Handler {
- return &handler{api.App, h, true, false, true, false, false, true, true}
-}
-
-func (api *API) ApiAppHandlerTrustRequesterIndependent(h func(*Context, http.ResponseWriter, *http.Request)) http.Handler {
- return &handler{api.App, h, false, false, true, false, true, true, false}
-}
-
-type handler struct {
- app *app.App
- handleFunc func(*Context, http.ResponseWriter, *http.Request)
- requireUser bool
- requireSystemAdmin bool
- isApi bool
- isUserActivity bool
- isTeamIndependent bool
- trustRequester bool
- requireMfa bool
-}
-
-func (h handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
- now := time.Now()
- mlog.Debug(fmt.Sprintf("%v", r.URL.Path))
-
- c := &Context{}
- c.App = h.app
- c.T, c.Locale = utils.GetTranslationsAndLocale(w, r)
- c.RequestId = model.NewId()
- c.IpAddress = utils.GetIpAddress(r)
- c.TeamId = mux.Vars(r)["team_id"]
-
- if metrics := c.App.Metrics; metrics != nil && h.isApi {
- metrics.IncrementHttpRequest()
- }
-
- token, tokenLocation := app.ParseAuthTokenFromRequest(r)
-
- // CSRF Check
- if tokenLocation == app.TokenLocationCookie && (h.requireSystemAdmin || h.requireUser) && !h.trustRequester {
- if r.Header.Get(model.HEADER_REQUESTED_WITH) != model.HEADER_REQUESTED_WITH_XML {
- c.Err = model.NewAppError("ServeHTTP", "api.context.session_expired.app_error", nil, "token="+token+" Appears to be a CSRF attempt", http.StatusUnauthorized)
- token = ""
- }
- }
-
- c.SetSiteURLHeader(app.GetProtocol(r) + "://" + r.Host)
-
- w.Header().Set(model.HEADER_REQUEST_ID, c.RequestId)
- w.Header().Set(model.HEADER_VERSION_ID, fmt.Sprintf("%v.%v.%v.%v", model.CurrentVersion, model.BuildNumber, c.App.ClientConfigHash(), c.App.License() != nil))
-
- // Instruct the browser not to display us in an iframe unless is the same origin for anti-clickjacking
- if !h.isApi {
- w.Header().Set("X-Frame-Options", "SAMEORIGIN")
- w.Header().Set("Content-Security-Policy", "frame-ancestors 'self'")
- } else {
- // All api response bodies will be JSON formatted by default
- w.Header().Set("Content-Type", "application/json")
-
- if r.Method == "GET" {
- w.Header().Set("Expires", "0")
- }
- }
-
- if len(token) != 0 {
- session, err := c.App.GetSession(token)
-
- if err != nil {
- mlog.Error(fmt.Sprintf("Invalid session err=%v", err.Error()))
- c.RemoveSessionCookie(w, r)
- if h.requireUser || h.requireSystemAdmin {
- c.Err = model.NewAppError("ServeHTTP", "api.context.session_expired.app_error", nil, "token="+token, http.StatusUnauthorized)
- }
- } else if !session.IsOAuth && tokenLocation == app.TokenLocationQueryString {
- c.Err = model.NewAppError("ServeHTTP", "api.context.token_provided.app_error", nil, "token="+token, http.StatusUnauthorized)
- } else {
- c.Session = *session
- }
-
- // Rate limit by UserID
- if c.App.Srv.RateLimiter != nil && c.App.Srv.RateLimiter.UserIdRateLimit(c.Session.UserId, w) {
- return
- }
- }
-
- if h.isApi || h.isTeamIndependent {
- c.setTeamURL(c.GetSiteURLHeader(), false)
- c.Path = r.URL.Path
- } else {
- splitURL := strings.Split(r.URL.Path, "/")
- c.setTeamURL(c.GetSiteURLHeader()+"/"+splitURL[1], true)
- c.Path = "/" + strings.Join(splitURL[2:], "/")
- }
-
- if h.isApi && !*c.App.Config().ServiceSettings.EnableAPIv3 {
- c.Err = model.NewAppError("ServeHTTP", "api.context.v3_disabled.app_error", nil, "", http.StatusNotImplemented)
- }
-
- if c.Err == nil && h.requireUser {
- c.UserRequired()
- }
-
- if c.Err == nil && h.requireMfa {
- c.MfaRequired()
- }
-
- if c.Err == nil && h.requireSystemAdmin {
- c.SystemAdminRequired()
- }
-
- if c.Err == nil && h.isUserActivity && token != "" && len(c.Session.UserId) > 0 {
- c.App.SetStatusOnline(c.Session.UserId, c.Session.Id, false)
- c.App.UpdateLastActivityAtIfNeeded(c.Session)
- }
-
- if c.Err == nil && (h.requireUser || h.requireSystemAdmin) {
- //check if teamId exist
- c.CheckTeamId()
- }
-
- if h.isApi {
- atomic.StoreInt32(model.UsedApiV3, 1)
- }
-
- if c.Err == nil {
- h.handleFunc(c, w, r)
- }
-
- // Handle errors that have occoured
- if c.Err != nil {
- c.Err.Translate(c.T)
- c.Err.RequestId = c.RequestId
- c.LogError(c.Err)
- c.Err.Where = r.URL.Path
-
- // Block out detailed error when not in developer mode
- if !*c.App.Config().ServiceSettings.EnableDeveloper {
- c.Err.DetailedError = ""
- }
-
- if h.isApi {
- w.WriteHeader(c.Err.StatusCode)
- w.Write([]byte(c.Err.ToJson()))
-
- if c.App.Metrics != nil {
- c.App.Metrics.IncrementHttpError()
- }
- } else {
- if c.Err.StatusCode == http.StatusUnauthorized {
- http.Redirect(w, r, c.GetTeamURL()+"/?redirect="+url.QueryEscape(r.URL.Path), http.StatusTemporaryRedirect)
- } else {
- utils.RenderWebAppError(w, r, c.Err, c.App.AsymmetricSigningKey())
- }
- }
-
- }
-
- if h.isApi && c.App.Metrics != nil {
- if r.URL.Path != model.API_URL_SUFFIX_V3+"/users/websocket" {
- elapsed := float64(time.Since(now)) / float64(time.Second)
- c.App.Metrics.ObserveHttpRequestDuration(elapsed)
- }
- }
-}
-
-func (c *Context) LogAudit(extraInfo string) {
- audit := &model.Audit{UserId: c.Session.UserId, IpAddress: c.IpAddress, Action: c.Path, ExtraInfo: extraInfo, SessionId: c.Session.Id}
- if r := <-c.App.Srv.Store.Audit().Save(audit); r.Err != nil {
- c.LogError(r.Err)
- }
-}
-
-func (c *Context) LogAuditWithUserId(userId, extraInfo string) {
-
- if len(c.Session.UserId) > 0 {
- extraInfo = strings.TrimSpace(extraInfo + " session_user=" + c.Session.UserId)
- }
-
- audit := &model.Audit{UserId: userId, IpAddress: c.IpAddress, Action: c.Path, ExtraInfo: extraInfo, SessionId: c.Session.Id}
- if r := <-c.App.Srv.Store.Audit().Save(audit); r.Err != nil {
- c.LogError(r.Err)
- }
-}
-
-func (c *Context) LogError(err *model.AppError) {
-
- // filter out endless reconnects
- if c.Path == "/api/v3/users/websocket" && err.StatusCode == 401 || err.Id == "web.check_browser_compatibility.app_error" {
- c.LogDebug(err)
- } else if err.Id != "api.post.create_post.town_square_read_only" {
- mlog.Error(fmt.Sprintf("%v:%v code=%v rid=%v uid=%v ip=%v %v [details: %v]", c.Path, err.Where, err.StatusCode,
- c.RequestId, c.Session.UserId, c.IpAddress, err.SystemMessage(utils.TDefault), err.DetailedError), mlog.String("user_id", c.Session.UserId))
- }
-}
-
-func (c *Context) LogDebug(err *model.AppError) {
- mlog.Debug(fmt.Sprintf("%v:%v code=%v rid=%v uid=%v ip=%v %v [details: %v]", c.Path, err.Where, err.StatusCode,
- c.RequestId, c.Session.UserId, c.IpAddress, err.SystemMessage(utils.TDefault), err.DetailedError), mlog.String("user_id", c.Session.UserId))
-}
-
-func (c *Context) UserRequired() {
- if !*c.App.Config().ServiceSettings.EnableUserAccessTokens && c.Session.Props[model.SESSION_PROP_TYPE] == model.SESSION_TYPE_USER_ACCESS_TOKEN {
- c.Err = model.NewAppError("", "api.context.session_expired.app_error", nil, "UserAccessToken", http.StatusUnauthorized)
- return
- }
-
- if len(c.Session.UserId) == 0 {
- c.Err = model.NewAppError("", "api.context.session_expired.app_error", nil, "UserRequired", http.StatusUnauthorized)
- return
- }
-}
-
-func (c *Context) MfaRequired() {
- // Must be licensed for MFA and have it configured for enforcement
- if license := c.App.License(); license == nil || !*license.Features.MFA || !*c.App.Config().ServiceSettings.EnableMultifactorAuthentication || !*c.App.Config().ServiceSettings.EnforceMultifactorAuthentication {
- return
- }
-
- // OAuth integrations are excepted
- if c.Session.IsOAuth {
- return
- }
-
- if result := <-c.App.Srv.Store.User().Get(c.Session.UserId); result.Err != nil {
- c.Err = model.NewAppError("", "api.context.session_expired.app_error", nil, "MfaRequired", http.StatusUnauthorized)
- return
- } else {
- user := result.Data.(*model.User)
-
- // Only required for email and ldap accounts
- if user.AuthService != "" &&
- user.AuthService != model.USER_AUTH_SERVICE_EMAIL &&
- user.AuthService != model.USER_AUTH_SERVICE_LDAP {
- return
- }
-
- if !user.MfaActive {
- c.Err = model.NewAppError("", "api.context.mfa_required.app_error", nil, "MfaRequired", http.StatusUnauthorized)
- return
- }
- }
-}
-
-func (c *Context) SystemAdminRequired() {
- if len(c.Session.UserId) == 0 {
- c.Err = model.NewAppError("", "api.context.session_expired.app_error", nil, "SystemAdminRequired", http.StatusUnauthorized)
- return
- } else if !c.IsSystemAdmin() {
- c.Err = model.NewAppError("", "api.context.permissions.app_error", nil, "AdminRequired", http.StatusForbidden)
- return
- }
-}
-
-func (c *Context) IsSystemAdmin() bool {
- return c.App.SessionHasPermissionTo(c.Session, model.PERMISSION_MANAGE_SYSTEM)
-}
-
-func (c *Context) RemoveSessionCookie(w http.ResponseWriter, r *http.Request) {
- cookie := &http.Cookie{
- Name: model.SESSION_COOKIE_TOKEN,
- Value: "",
- Path: "/",
- MaxAge: -1,
- HttpOnly: true,
- }
-
- userCookie := &http.Cookie{
- Name: model.SESSION_COOKIE_USER,
- Value: "",
- Path: "/",
- MaxAge: -1,
- }
-
- http.SetCookie(w, cookie)
- http.SetCookie(w, userCookie)
-}
-
-func (c *Context) SetInvalidParam(where string, name string) {
- c.Err = NewInvalidParamError(where, name)
-}
-
-func NewInvalidParamError(where string, name string) *model.AppError {
- err := model.NewAppError(where, "api.context.invalid_param.app_error", map[string]interface{}{"Name": name}, "", http.StatusBadRequest)
- return err
-}
-
-func (c *Context) SetPermissionError(permission *model.Permission) {
- c.Err = model.NewAppError("Permissions", "api.context.permissions.app_error", nil, "userId="+c.Session.UserId+", "+"permission="+permission.Id, http.StatusForbidden)
-}
-
-func (c *Context) setTeamURL(url string, valid bool) {
- c.teamURL = url
- c.teamURLValid = valid
-}
-
-func (c *Context) SetTeamURLFromSession() {
- if result := <-c.App.Srv.Store.Team().Get(c.TeamId); result.Err == nil {
- c.setTeamURL(c.GetSiteURLHeader()+"/"+result.Data.(*model.Team).Name, true)
- }
-}
-
-func (c *Context) SetSiteURLHeader(url string) {
- c.siteURLHeader = strings.TrimRight(url, "/")
-}
-
-func (c *Context) GetTeamURL() string {
- if !c.teamURLValid {
- c.SetTeamURLFromSession()
- if !c.teamURLValid {
- mlog.Debug("Team URL accessed when not valid. Team URL should not be used in API functions or those that are team independent")
- }
- }
- return c.teamURL
-}
-
-func (c *Context) GetSiteURLHeader() string {
- return c.siteURLHeader
-}
-
-func (c *Context) HandleEtag(etag string, routeName string, w http.ResponseWriter, r *http.Request) bool {
- metrics := c.App.Metrics
- if et := r.Header.Get(model.HEADER_ETAG_CLIENT); len(etag) > 0 {
- if et == etag {
- w.Header().Set(model.HEADER_ETAG_SERVER, etag)
- w.WriteHeader(http.StatusNotModified)
- if metrics != nil {
- metrics.IncrementEtagHitCounter(routeName)
- }
- return true
- }
- }
-
- if metrics != nil {
- metrics.IncrementEtagMissCounter(routeName)
- }
-
- return false
-}
-
-func IsApiCall(r *http.Request) bool {
- return strings.Index(r.URL.Path, "/api/") == 0
-}
-
-func Handle404(a *app.App, w http.ResponseWriter, r *http.Request) {
- err := model.NewAppError("Handle404", "api.context.404.app_error", nil, "", http.StatusNotFound)
-
- mlog.Debug(fmt.Sprintf("%v: code=404 ip=%v", r.URL.Path, utils.GetIpAddress(r)))
-
- if IsApiCall(r) {
- w.WriteHeader(err.StatusCode)
- err.DetailedError = "There doesn't appear to be an api call for the url='" + r.URL.Path + "'. Typo? are you missing a team_id or user_id as part of the url?"
- w.Write([]byte(err.ToJson()))
- } else {
- utils.RenderWebAppError(w, r, err, a.AsymmetricSigningKey())
- }
-}
-
-func (c *Context) CheckTeamId() {
- if c.TeamId != "" && c.Session.GetTeamByTeamId(c.TeamId) == nil {
- if c.App.SessionHasPermissionTo(c.Session, model.PERMISSION_MANAGE_SYSTEM) {
- if result := <-c.App.Srv.Store.Team().Get(c.TeamId); result.Err != nil {
- c.Err = result.Err
- c.Err.StatusCode = http.StatusBadRequest
- return
- }
- } else {
- c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM)
- return
- }
- }
-}
diff --git a/api/context_test.go b/api/context_test.go
deleted file mode 100644
index 95a8459ff..000000000
--- a/api/context_test.go
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-package api
-
-import (
- "testing"
-)
-
-func TestSiteURLHeader(t *testing.T) {
- c := &Context{}
-
- testCases := []struct {
- url string
- want string
- }{
- {"http://mattermost.com/", "http://mattermost.com"},
- {"http://mattermost.com", "http://mattermost.com"},
- }
-
- for _, tc := range testCases {
- c.SetSiteURLHeader(tc.url)
-
- if c.siteURLHeader != tc.want {
- t.Fatalf("expected %s, got %s", tc.want, c.siteURLHeader)
- }
- }
-
-}
diff --git a/api/deprecated_test.go b/api/deprecated_test.go
deleted file mode 100644
index 6943c6918..000000000
--- a/api/deprecated_test.go
+++ /dev/null
@@ -1,4 +0,0 @@
-// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-package api
diff --git a/api/emoji.go b/api/emoji.go
deleted file mode 100644
index b366530ba..000000000
--- a/api/emoji.go
+++ /dev/null
@@ -1,228 +0,0 @@
-// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-package api
-
-import (
- "image"
- "image/draw"
- "image/gif"
- "net/http"
- "strings"
-
- "image/color/palette"
-
- "github.com/disintegration/imaging"
- "github.com/gorilla/mux"
- "github.com/mattermost/mattermost-server/app"
- "github.com/mattermost/mattermost-server/model"
-)
-
-func (api *API) InitEmoji() {
- api.BaseRoutes.Emoji.Handle("/list", api.ApiUserRequired(getEmoji)).Methods("GET")
- api.BaseRoutes.Emoji.Handle("/create", api.ApiUserRequired(createEmoji)).Methods("POST")
- api.BaseRoutes.Emoji.Handle("/delete", api.ApiUserRequired(deleteEmoji)).Methods("POST")
- api.BaseRoutes.Emoji.Handle("/{id:[A-Za-z0-9_]+}", api.ApiUserRequiredTrustRequester(getEmojiImage)).Methods("GET")
-}
-
-func getEmoji(c *Context, w http.ResponseWriter, r *http.Request) {
- if !*c.App.Config().ServiceSettings.EnableCustomEmoji {
- c.Err = model.NewAppError("getEmoji", "api.emoji.disabled.app_error", nil, "", http.StatusNotImplemented)
- return
- }
-
- listEmoji, err := c.App.GetEmojiList(0, 100000, "")
- if err != nil {
- c.Err = err
- return
- } else {
- w.Write([]byte(model.EmojiListToJson(listEmoji)))
- }
-}
-
-func createEmoji(c *Context, w http.ResponseWriter, r *http.Request) {
- if !*c.App.Config().ServiceSettings.EnableCustomEmoji {
- c.Err = model.NewAppError("createEmoji", "api.emoji.disabled.app_error", nil, "", http.StatusNotImplemented)
- return
- }
-
- if emojiInterface := c.App.Emoji; emojiInterface != nil &&
- !emojiInterface.CanUserCreateEmoji(c.Session.Roles, c.Session.TeamMembers) {
- c.Err = model.NewAppError("createEmoji", "api.emoji.create.permissions.app_error", nil, "user_id="+c.Session.UserId, http.StatusUnauthorized)
- return
- }
-
- if len(*c.App.Config().FileSettings.DriverName) == 0 {
- c.Err = model.NewAppError("createEmoji", "api.emoji.storage.app_error", nil, "", http.StatusNotImplemented)
- return
- }
-
- if r.ContentLength > app.MaxEmojiFileSize {
- c.Err = model.NewAppError("createEmoji", "api.emoji.create.too_large.app_error", nil, "", http.StatusRequestEntityTooLarge)
- return
- }
-
- if err := r.ParseMultipartForm(app.MaxEmojiFileSize); err != nil {
- c.Err = model.NewAppError("createEmoji", "api.emoji.create.parse.app_error", nil, err.Error(), http.StatusBadRequest)
- return
- }
-
- m := r.MultipartForm
- props := m.Value
-
- emoji := model.EmojiFromJson(strings.NewReader(props["emoji"][0]))
- if emoji == nil {
- c.SetInvalidParam("createEmoji", "emoji")
- return
- }
-
- // wipe the emoji id so that existing emojis can't get overwritten
- emoji.Id = ""
-
- // do our best to validate the emoji before committing anything to the DB so that we don't have to clean up
- // orphaned files left over when validation fails later on
- emoji.PreSave()
- if err := emoji.IsValid(); err != nil {
- c.Err = err
- c.Err.StatusCode = http.StatusBadRequest
- return
- }
-
- if emoji.CreatorId != c.Session.UserId {
- c.Err = model.NewAppError("createEmoji", "api.emoji.create.other_user.app_error", nil, "", http.StatusUnauthorized)
- return
- }
-
- if result := <-c.App.Srv.Store.Emoji().GetByName(emoji.Name); result.Err == nil && result.Data != nil {
- c.Err = model.NewAppError("createEmoji", "api.emoji.create.duplicate.app_error", nil, "", http.StatusBadRequest)
- return
- }
-
- if imageData := m.File["image"]; len(imageData) == 0 {
- c.SetInvalidParam("createEmoji", "image")
- return
- } else if err := c.App.UploadEmojiImage(emoji.Id, imageData[0]); err != nil {
- c.Err = err
- return
- }
-
- if result := <-c.App.Srv.Store.Emoji().Save(emoji); result.Err != nil {
- c.Err = result.Err
- return
- } else {
- message := model.NewWebSocketEvent(model.WEBSOCKET_EVENT_EMOJI_ADDED, "", "", "", nil)
- message.Add("emoji", result.Data.(*model.Emoji).ToJson())
-
- c.App.Publish(message)
- w.Write([]byte(result.Data.(*model.Emoji).ToJson()))
- }
-}
-
-func deleteEmoji(c *Context, w http.ResponseWriter, r *http.Request) {
- if !*c.App.Config().ServiceSettings.EnableCustomEmoji {
- c.Err = model.NewAppError("deleteEmoji", "api.emoji.disabled.app_error", nil, "", http.StatusNotImplemented)
- return
- }
-
- if len(*c.App.Config().FileSettings.DriverName) == 0 {
- c.Err = model.NewAppError("deleteImage", "api.emoji.storage.app_error", nil, "", http.StatusNotImplemented)
- return
- }
-
- props := model.MapFromJson(r.Body)
-
- id := props["id"]
- if len(id) == 0 {
- c.SetInvalidParam("deleteEmoji", "id")
- return
- }
-
- emoji, err := c.App.GetEmoji(id)
- if err != nil {
- c.Err = err
- return
- }
-
- if c.Session.UserId != emoji.CreatorId && !c.App.SessionHasPermissionTo(c.Session, model.PERMISSION_MANAGE_SYSTEM) {
- c.Err = model.NewAppError("deleteEmoji", "api.emoji.delete.permissions.app_error", nil, "user_id="+c.Session.UserId, http.StatusUnauthorized)
- return
- }
-
- err = c.App.DeleteEmoji(emoji)
- if err != nil {
- c.Err = err
- return
- } else {
- ReturnStatusOK(w)
- }
-}
-
-func getEmojiImage(c *Context, w http.ResponseWriter, r *http.Request) {
- if !*c.App.Config().ServiceSettings.EnableCustomEmoji {
- c.Err = model.NewAppError("getEmojiImage", "api.emoji.disabled.app_error", nil, "", http.StatusNotImplemented)
- return
- }
-
- if len(*c.App.Config().FileSettings.DriverName) == 0 {
- c.Err = model.NewAppError("getEmojiImage", "api.emoji.storage.app_error", nil, "", http.StatusNotImplemented)
- return
- }
-
- params := mux.Vars(r)
-
- id := params["id"]
- if len(id) == 0 {
- c.SetInvalidParam("getEmojiImage", "id")
- return
- }
-
- image, imageType, err := c.App.GetEmojiImage(id)
- if err != nil {
- c.Err = err
- return
- }
-
- w.Header().Set("Content-Type", "image/"+imageType)
- w.Header().Set("Cache-Control", "max-age=2592000, public")
- w.Write(image)
-}
-
-func resizeEmoji(img image.Image, width int, height int) image.Image {
- emojiWidth := float64(width)
- emojiHeight := float64(height)
-
- var emoji image.Image
- if emojiHeight <= app.MaxEmojiHeight && emojiWidth <= app.MaxEmojiWidth {
- emoji = img
- } else {
- emoji = imaging.Fit(img, app.MaxEmojiWidth, app.MaxEmojiHeight, imaging.Lanczos)
- }
- return emoji
-}
-
-func resizeEmojiGif(gifImg *gif.GIF) *gif.GIF {
- // Create a new RGBA image to hold the incremental frames.
- firstFrame := gifImg.Image[0].Bounds()
- b := image.Rect(0, 0, firstFrame.Dx(), firstFrame.Dy())
- img := image.NewRGBA(b)
-
- resizedImage := image.Image(nil)
- // Resize each frame.
- for index, frame := range gifImg.Image {
- bounds := frame.Bounds()
- draw.Draw(img, bounds, frame, bounds.Min, draw.Over)
- resizedImage = resizeEmoji(img, firstFrame.Dx(), firstFrame.Dy())
- gifImg.Image[index] = imageToPaletted(resizedImage)
- }
- // Set new gif width and height
- gifImg.Config.Width = resizedImage.Bounds().Dx()
- gifImg.Config.Height = resizedImage.Bounds().Dy()
- return gifImg
-}
-
-func imageToPaletted(img image.Image) *image.Paletted {
- b := img.Bounds()
- pm := image.NewPaletted(b, palette.Plan9)
- draw.FloydSteinberg.Draw(pm, b, img, image.ZP)
- return pm
-}
diff --git a/api/emoji_test.go b/api/emoji_test.go
deleted file mode 100644
index 108c416e1..000000000
--- a/api/emoji_test.go
+++ /dev/null
@@ -1,437 +0,0 @@
-// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-package api
-
-import (
- "bytes"
- "image"
- "image/gif"
- "testing"
- "time"
-
- "github.com/mattermost/mattermost-server/app"
- "github.com/mattermost/mattermost-server/model"
- "github.com/mattermost/mattermost-server/store"
- "github.com/mattermost/mattermost-server/utils"
-)
-
-func TestGetEmoji(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- Client := th.BasicClient
-
- EnableCustomEmoji := *th.App.Config().ServiceSettings.EnableCustomEmoji
- defer func() {
- th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableCustomEmoji = EnableCustomEmoji })
- }()
- th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableCustomEmoji = true })
-
- emojis := []*model.Emoji{
- {
- CreatorId: model.NewId(),
- Name: model.NewId(),
- },
- {
- CreatorId: model.NewId(),
- Name: model.NewId(),
- },
- {
- CreatorId: model.NewId(),
- Name: model.NewId(),
- },
- }
-
- for i, emoji := range emojis {
- emojis[i] = store.Must(th.App.Srv.Store.Emoji().Save(emoji)).(*model.Emoji)
- }
- defer func() {
- for _, emoji := range emojis {
- store.Must(th.App.Srv.Store.Emoji().Delete(emoji.Id, time.Now().Unix()))
- }
- }()
-
- if returnedEmojis, err := Client.ListEmoji(); err != nil {
- t.Fatal(err)
- } else {
- for _, emoji := range emojis {
- found := false
-
- for _, savedEmoji := range returnedEmojis {
- if emoji.Id == savedEmoji.Id {
- found = true
- break
- }
- }
-
- if !found {
- t.Fatalf("failed to get emoji with id %v", emoji.Id)
- }
- }
- }
-
- deleted := &model.Emoji{
- CreatorId: model.NewId(),
- Name: model.NewId(),
- DeleteAt: 1,
- }
- deleted = store.Must(th.App.Srv.Store.Emoji().Save(deleted)).(*model.Emoji)
-
- if returnedEmojis, err := Client.ListEmoji(); err != nil {
- t.Fatal(err)
- } else {
- found := false
-
- for _, savedEmoji := range returnedEmojis {
- if deleted.Id == savedEmoji.Id {
- found = true
- break
- }
- }
-
- if found {
- t.Fatalf("shouldn't have gotten deleted emoji %v", deleted.Id)
- }
- }
-}
-
-func TestCreateEmoji(t *testing.T) {
- th := Setup().InitBasic().InitSystemAdmin()
- defer th.TearDown()
-
- Client := th.BasicClient
-
- EnableCustomEmoji := *th.App.Config().ServiceSettings.EnableCustomEmoji
- defer func() {
- th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableCustomEmoji = EnableCustomEmoji })
- }()
- th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableCustomEmoji = false })
-
- emoji := &model.Emoji{
- CreatorId: th.BasicUser.Id,
- Name: model.NewId(),
- }
-
- // try to create an emoji when they're disabled
- if _, err := Client.CreateEmoji(emoji, utils.CreateTestGif(t, 10, 10), "image.gif"); err == nil {
- t.Fatal("shouldn't be able to create an emoji when they're disabled")
- }
-
- th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableCustomEmoji = true })
-
- // try to create a valid gif emoji when they're enabled
- if emojiResult, err := Client.CreateEmoji(emoji, utils.CreateTestGif(t, 10, 10), "image.gif"); err != nil {
- t.Fatal(err)
- } else {
- emoji = emojiResult
- }
-
- // try to create an emoji with a duplicate name
- emoji2 := &model.Emoji{
- CreatorId: th.BasicUser.Id,
- Name: emoji.Name,
- }
- if _, err := Client.CreateEmoji(emoji2, utils.CreateTestGif(t, 10, 10), "image.gif"); err == nil {
- t.Fatal("shouldn't be able to create an emoji with a duplicate name")
- }
-
- Client.MustGeneric(Client.DeleteEmoji(emoji.Id))
-
- // try to create a valid animated gif emoji
- emoji = &model.Emoji{
- CreatorId: th.BasicUser.Id,
- Name: model.NewId(),
- }
- if emojiResult, err := Client.CreateEmoji(emoji, utils.CreateTestAnimatedGif(t, 10, 10, 10), "image.gif"); err != nil {
- t.Fatal(err)
- } else {
- emoji = emojiResult
- }
- Client.MustGeneric(Client.DeleteEmoji(emoji.Id))
-
- // try to create a valid jpeg emoji
- emoji = &model.Emoji{
- CreatorId: th.BasicUser.Id,
- Name: model.NewId(),
- }
- if emojiResult, err := Client.CreateEmoji(emoji, utils.CreateTestJpeg(t, 10, 10), "image.jpeg"); err != nil {
- t.Fatal(err)
- } else {
- emoji = emojiResult
- }
- Client.MustGeneric(Client.DeleteEmoji(emoji.Id))
-
- // try to create a valid png emoji
- emoji = &model.Emoji{
- CreatorId: th.BasicUser.Id,
- Name: model.NewId(),
- }
- if emojiResult, err := Client.CreateEmoji(emoji, utils.CreateTestPng(t, 10, 10), "image.png"); err != nil {
- t.Fatal(err)
- } else {
- emoji = emojiResult
- }
- Client.MustGeneric(Client.DeleteEmoji(emoji.Id))
-
- // try to create an emoji that's too wide
- emoji = &model.Emoji{
- CreatorId: th.BasicUser.Id,
- Name: model.NewId(),
- }
- if _, err := Client.CreateEmoji(emoji, utils.CreateTestGif(t, 1000, 10), "image.gif"); err != nil {
- t.Fatal("should be able to create an emoji that's too wide by resizing it")
- }
-
- // try to create an emoji that's too tall
- emoji = &model.Emoji{
- CreatorId: th.BasicUser.Id,
- Name: model.NewId(),
- }
- if _, err := Client.CreateEmoji(emoji, utils.CreateTestGif(t, 10, 1000), "image.gif"); err != nil {
- t.Fatal("should be able to create an emoji that's too tall by resizing it")
- }
-
- // try to create an emoji that's too large
- emoji = &model.Emoji{
- CreatorId: th.BasicUser.Id,
- Name: model.NewId(),
- }
- if _, err := Client.CreateEmoji(emoji, utils.CreateTestAnimatedGif(t, 100, 100, 10000), "image.gif"); err == nil {
- t.Fatal("shouldn't be able to create an emoji that's too large")
- }
-
- // try to create an emoji with data that isn't an image
- emoji = &model.Emoji{
- CreatorId: th.BasicUser.Id,
- Name: model.NewId(),
- }
- if _, err := Client.CreateEmoji(emoji, make([]byte, 100), "image.gif"); err == nil {
- t.Fatal("shouldn't be able to create an emoji with non-image data")
- }
-
- // try to create an emoji as another user
- emoji = &model.Emoji{
- CreatorId: th.BasicUser2.Id,
- Name: model.NewId(),
- }
- if _, err := Client.CreateEmoji(emoji, utils.CreateTestGif(t, 10, 10), "image.gif"); err == nil {
- t.Fatal("shouldn't be able to create an emoji as another user")
- }
-}
-
-func TestDeleteEmoji(t *testing.T) {
- th := Setup().InitBasic().InitSystemAdmin()
- defer th.TearDown()
-
- Client := th.BasicClient
-
- EnableCustomEmoji := *th.App.Config().ServiceSettings.EnableCustomEmoji
- defer func() {
- th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableCustomEmoji = EnableCustomEmoji })
- }()
- th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableCustomEmoji = false })
-
- emoji1 := createTestEmoji(t, th.App, &model.Emoji{
- CreatorId: th.BasicUser.Id,
- Name: model.NewId(),
- }, utils.CreateTestGif(t, 10, 10))
-
- if _, err := Client.DeleteEmoji(emoji1.Id); err == nil {
- t.Fatal("shouldn't have been able to delete an emoji when they're disabled")
- }
-
- th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableCustomEmoji = true })
-
- if deleted, err := Client.DeleteEmoji(emoji1.Id); err != nil {
- t.Fatal(err)
- } else if !deleted {
- t.Fatalf("should be able to delete your own emoji %v", emoji1.Id)
- }
-
- if _, err := Client.DeleteEmoji(emoji1.Id); err == nil {
- t.Fatal("shouldn't be able to delete an already-deleted emoji")
- }
-
- emoji2 := createTestEmoji(t, th.App, &model.Emoji{
- CreatorId: th.BasicUser2.Id,
- Name: model.NewId(),
- }, utils.CreateTestGif(t, 10, 10))
-
- if _, err := Client.DeleteEmoji(emoji2.Id); err == nil {
- t.Fatal("shouldn't be able to delete another user's emoji")
- }
-
- if deleted, err := th.SystemAdminClient.DeleteEmoji(emoji2.Id); err != nil {
- t.Fatal(err)
- } else if !deleted {
- t.Fatalf("system admin should be able to delete anyone's emoji %v", emoji2.Id)
- }
-}
-
-func createTestEmoji(t *testing.T, a *app.App, emoji *model.Emoji, imageData []byte) *model.Emoji {
- emoji = store.Must(a.Srv.Store.Emoji().Save(emoji)).(*model.Emoji)
-
- if _, err := a.WriteFile(bytes.NewReader(imageData), "emoji/"+emoji.Id+"/image"); err != nil {
- store.Must(a.Srv.Store.Emoji().Delete(emoji.Id, time.Now().Unix()))
- t.Fatalf("failed to write image: %v", err.Error())
- }
-
- return emoji
-}
-
-func TestGetEmojiImage(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- Client := th.BasicClient
-
- EnableCustomEmoji := *th.App.Config().ServiceSettings.EnableCustomEmoji
- RestrictCustomEmojiCreation := *th.App.Config().ServiceSettings.RestrictCustomEmojiCreation
- defer func() {
- th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableCustomEmoji = EnableCustomEmoji })
- th.App.UpdateConfig(func(cfg *model.Config) {
- *cfg.ServiceSettings.RestrictCustomEmojiCreation = RestrictCustomEmojiCreation
- })
- }()
- th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableCustomEmoji = true })
- th.App.UpdateConfig(func(cfg *model.Config) {
- *cfg.ServiceSettings.RestrictCustomEmojiCreation = model.RESTRICT_EMOJI_CREATION_ALL
- })
-
- emoji1 := &model.Emoji{
- CreatorId: th.BasicUser.Id,
- Name: model.NewId(),
- }
- emoji1 = Client.MustGeneric(Client.CreateEmoji(emoji1, utils.CreateTestGif(t, 10, 10), "image.gif")).(*model.Emoji)
- defer func() { Client.MustGeneric(Client.DeleteEmoji(emoji1.Id)) }()
-
- th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableCustomEmoji = false })
-
- if _, err := Client.DoApiGet(Client.GetCustomEmojiImageUrl(emoji1.Id), "", ""); err == nil {
- t.Fatal("should've failed to get emoji image when disabled")
- }
-
- th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableCustomEmoji = true })
-
- if resp, err := Client.DoApiGet(Client.GetCustomEmojiImageUrl(emoji1.Id), "", ""); err != nil {
- t.Fatal(err)
- } else if resp.Header.Get("Content-Type") != "image/gif" {
- t.Fatal("should've received a gif")
- } else if _, imageType, err := image.DecodeConfig(resp.Body); err != nil {
- t.Fatalf("unable to identify received image: %v", err.Error())
- } else if imageType != "gif" {
- t.Fatal("should've received gif data")
- }
-
- emoji2 := &model.Emoji{
- CreatorId: th.BasicUser.Id,
- Name: model.NewId(),
- }
- emoji2 = Client.MustGeneric(Client.CreateEmoji(emoji2, utils.CreateTestAnimatedGif(t, 10, 10, 10), "image.gif")).(*model.Emoji)
- defer func() { Client.MustGeneric(Client.DeleteEmoji(emoji2.Id)) }()
-
- if resp, err := Client.DoApiGet(Client.GetCustomEmojiImageUrl(emoji2.Id), "", ""); err != nil {
- t.Fatal(err)
- } else if resp.Header.Get("Content-Type") != "image/gif" {
- t.Fatal("should've received a gif")
- } else if _, imageType, err := image.DecodeConfig(resp.Body); err != nil {
- t.Fatalf("unable to identify received image: %v", err.Error())
- } else if imageType != "gif" {
- t.Fatal("should've received gif data")
- }
-
- emoji3 := &model.Emoji{
- CreatorId: th.BasicUser.Id,
- Name: model.NewId(),
- }
- emoji3 = Client.MustGeneric(Client.CreateEmoji(emoji3, utils.CreateTestJpeg(t, 10, 10), "image.jpeg")).(*model.Emoji)
- defer func() { Client.MustGeneric(Client.DeleteEmoji(emoji3.Id)) }()
-
- if resp, err := Client.DoApiGet(Client.GetCustomEmojiImageUrl(emoji3.Id), "", ""); err != nil {
- t.Fatal(err)
- } else if resp.Header.Get("Content-Type") != "image/jpeg" {
- t.Fatal("should've received a jpeg")
- } else if _, imageType, err := image.DecodeConfig(resp.Body); err != nil {
- t.Fatalf("unable to identify received image: %v", err.Error())
- } else if imageType != "jpeg" {
- t.Fatal("should've received jpeg data")
- }
-
- emoji4 := &model.Emoji{
- CreatorId: th.BasicUser.Id,
- Name: model.NewId(),
- }
- emoji4 = Client.MustGeneric(Client.CreateEmoji(emoji4, utils.CreateTestPng(t, 10, 10), "image.png")).(*model.Emoji)
- defer func() { Client.MustGeneric(Client.DeleteEmoji(emoji4.Id)) }()
-
- if resp, err := Client.DoApiGet(Client.GetCustomEmojiImageUrl(emoji4.Id), "", ""); err != nil {
- t.Fatal(err)
- } else if resp.Header.Get("Content-Type") != "image/png" {
- t.Fatal("should've received a png")
- } else if _, imageType, err := image.DecodeConfig(resp.Body); err != nil {
- t.Fatalf("unable to identify received image: %v", err.Error())
- } else if imageType != "png" {
- t.Fatal("should've received png data")
- }
-
- emoji5 := &model.Emoji{
- CreatorId: th.BasicUser.Id,
- Name: model.NewId(),
- }
- emoji5 = Client.MustGeneric(Client.CreateEmoji(emoji5, utils.CreateTestPng(t, 10, 10), "image.png")).(*model.Emoji)
- Client.MustGeneric(Client.DeleteEmoji(emoji5.Id))
-
- if _, err := Client.DoApiGet(Client.GetCustomEmojiImageUrl(emoji5.Id), "", ""); err == nil {
- t.Fatal("should've failed to get image for deleted emoji")
- }
-}
-
-func TestResizeEmoji(t *testing.T) {
- // try to resize a jpeg image within MaxEmojiWidth and MaxEmojiHeight
- small_img_data := utils.CreateTestJpeg(t, app.MaxEmojiWidth, app.MaxEmojiHeight)
- if small_img, _, err := image.Decode(bytes.NewReader(small_img_data)); err != nil {
- t.Fatal("failed to decode jpeg bytes to image.Image")
- } else {
- resized_img := resizeEmoji(small_img, small_img.Bounds().Dx(), small_img.Bounds().Dy())
- if resized_img.Bounds().Dx() > app.MaxEmojiWidth || resized_img.Bounds().Dy() > app.MaxEmojiHeight {
- t.Fatal("resized jpeg width and height should not be greater than MaxEmojiWidth or MaxEmojiHeight")
- }
- if resized_img != small_img {
- t.Fatal("should've returned small_img itself")
- }
- }
- // try to resize a jpeg image
- jpeg_data := utils.CreateTestJpeg(t, 256, 256)
- if jpeg_img, _, err := image.Decode(bytes.NewReader(jpeg_data)); err != nil {
- t.Fatal("failed to decode jpeg bytes to image.Image")
- } else {
- resized_jpeg := resizeEmoji(jpeg_img, jpeg_img.Bounds().Dx(), jpeg_img.Bounds().Dy())
- if resized_jpeg.Bounds().Dx() > app.MaxEmojiWidth || resized_jpeg.Bounds().Dy() > app.MaxEmojiHeight {
- t.Fatal("resized jpeg width and height should not be greater than MaxEmojiWidth or MaxEmojiHeight")
- }
- }
- // try to resize a png image
- png_data := utils.CreateTestJpeg(t, 256, 256)
- if png_img, _, err := image.Decode(bytes.NewReader(png_data)); err != nil {
- t.Fatal("failed to decode png bytes to image.Image")
- } else {
- resized_png := resizeEmoji(png_img, png_img.Bounds().Dx(), png_img.Bounds().Dy())
- if resized_png.Bounds().Dx() > app.MaxEmojiWidth || resized_png.Bounds().Dy() > app.MaxEmojiHeight {
- t.Fatal("resized png width and height should not be greater than MaxEmojiWidth or MaxEmojiHeight")
- }
- }
- // try to resize an animated gif
- gif_data := utils.CreateTestAnimatedGif(t, 256, 256, 10)
- if gif_img, err := gif.DecodeAll(bytes.NewReader(gif_data)); err != nil {
- t.Fatal("failed to decode gif bytes to gif.GIF")
- } else {
- resized_gif := resizeEmojiGif(gif_img)
- if resized_gif.Config.Width > app.MaxEmojiWidth || resized_gif.Config.Height > app.MaxEmojiHeight {
- t.Fatal("resized gif width and height should not be greater than MaxEmojiWidth or MaxEmojiHeight")
- }
- if len(resized_gif.Image) != len(gif_img.Image) {
- t.Fatal("resized gif should have the same number of frames as original gif")
- }
- }
-}
diff --git a/api/file.go b/api/file.go
deleted file mode 100644
index 63432eda5..000000000
--- a/api/file.go
+++ /dev/null
@@ -1,333 +0,0 @@
-// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-package api
-
-import (
- "net/http"
- "net/url"
- "strconv"
- "strings"
-
- "github.com/gorilla/mux"
- "github.com/mattermost/mattermost-server/app"
- "github.com/mattermost/mattermost-server/model"
- "github.com/mattermost/mattermost-server/utils"
-)
-
-const (
- PREVIEW_IMAGE_TYPE = "image/jpeg"
- THUMBNAIL_IMAGE_TYPE = "image/jpeg"
-)
-
-var UNSAFE_CONTENT_TYPES = [...]string{
- "application/javascript",
- "application/ecmascript",
- "text/javascript",
- "text/ecmascript",
- "application/x-javascript",
- "text/html",
-}
-
-func (api *API) InitFile() {
- api.BaseRoutes.TeamFiles.Handle("/upload", api.ApiUserRequired(uploadFile)).Methods("POST")
-
- api.BaseRoutes.NeedFile.Handle("/get", api.ApiUserRequiredTrustRequester(getFile)).Methods("GET")
- api.BaseRoutes.NeedFile.Handle("/get_thumbnail", api.ApiUserRequiredTrustRequester(getFileThumbnail)).Methods("GET")
- api.BaseRoutes.NeedFile.Handle("/get_preview", api.ApiUserRequiredTrustRequester(getFilePreview)).Methods("GET")
- api.BaseRoutes.NeedFile.Handle("/get_info", api.ApiUserRequired(getFileInfo)).Methods("GET")
- api.BaseRoutes.NeedFile.Handle("/get_public_link", api.ApiUserRequired(getPublicLink)).Methods("GET")
-
- api.BaseRoutes.Public.Handle("/files/{file_id:[A-Za-z0-9]+}/get", api.ApiAppHandlerTrustRequesterIndependent(getPublicFile)).Methods("GET")
- api.BaseRoutes.Public.Handle("/files/get/{team_id:[A-Za-z0-9]+}/{channel_id:[A-Za-z0-9]+}/{user_id:[A-Za-z0-9]+}/{filename:(?:[A-Za-z0-9]+/)?.+(?:\\.[A-Za-z0-9]{3,})?}", api.ApiAppHandlerTrustRequesterIndependent(getPublicFileOld)).Methods("GET")
-}
-
-func uploadFile(c *Context, w http.ResponseWriter, r *http.Request) {
- if !*c.App.Config().FileSettings.EnableFileAttachments {
- c.Err = model.NewAppError("uploadFile", "api.file.attachments.disabled.app_error", nil, "", http.StatusNotImplemented)
- return
- }
-
- if r.ContentLength > *c.App.Config().FileSettings.MaxFileSize {
- c.Err = model.NewAppError("uploadFile", "api.file.upload_file.too_large.app_error", nil, "", http.StatusRequestEntityTooLarge)
- return
- }
-
- if err := r.ParseMultipartForm(*c.App.Config().FileSettings.MaxFileSize); err != nil {
- http.Error(w, err.Error(), http.StatusInternalServerError)
- return
- }
-
- m := r.MultipartForm
-
- props := m.Value
- if len(props["channel_id"]) == 0 {
- c.SetInvalidParam("uploadFile", "channel_id")
- return
- }
- channelId := props["channel_id"][0]
- if len(channelId) == 0 {
- c.SetInvalidParam("uploadFile", "channel_id")
- return
- }
-
- if !c.App.SessionHasPermissionToChannel(c.Session, channelId, model.PERMISSION_UPLOAD_FILE) {
- c.SetPermissionError(model.PERMISSION_UPLOAD_FILE)
- return
- }
-
- resStruct, err := c.App.UploadMultipartFiles(c.TeamId, channelId, c.Session.UserId, m.File["files"], m.Value["client_ids"])
- if err != nil {
- c.Err = err
- return
- }
-
- w.Write([]byte(resStruct.ToJson()))
-}
-
-func getFile(c *Context, w http.ResponseWriter, r *http.Request) {
- info, err := getFileInfoForRequest(c, r, true)
- if err != nil {
- c.Err = err
- return
- }
-
- if data, err := c.App.ReadFile(info.Path); err != nil {
- c.Err = err
- c.Err.StatusCode = http.StatusNotFound
- } else if err := writeFileResponse(info.Name, info.MimeType, data, w, r); err != nil {
- c.Err = err
- return
- }
-}
-
-func getFileThumbnail(c *Context, w http.ResponseWriter, r *http.Request) {
- info, err := getFileInfoForRequest(c, r, true)
- if err != nil {
- c.Err = err
- return
- }
-
- if info.ThumbnailPath == "" {
- c.Err = model.NewAppError("getFileThumbnail", "api.file.get_file_thumbnail.no_thumbnail.app_error", nil, "file_id="+info.Id, http.StatusBadRequest)
- return
- }
-
- if data, err := c.App.ReadFile(info.ThumbnailPath); err != nil {
- c.Err = err
- c.Err.StatusCode = http.StatusNotFound
- } else if err := writeFileResponse(info.Name, THUMBNAIL_IMAGE_TYPE, data, w, r); err != nil {
- c.Err = err
- return
- }
-}
-
-func getFilePreview(c *Context, w http.ResponseWriter, r *http.Request) {
- info, err := getFileInfoForRequest(c, r, true)
- if err != nil {
- c.Err = err
- return
- }
-
- if info.PreviewPath == "" {
- c.Err = model.NewAppError("getFilePreview", "api.file.get_file_preview.no_preview.app_error", nil, "file_id="+info.Id, http.StatusBadRequest)
- return
- }
-
- if data, err := c.App.ReadFile(info.PreviewPath); err != nil {
- c.Err = err
- c.Err.StatusCode = http.StatusNotFound
- } else if err := writeFileResponse(info.Name, PREVIEW_IMAGE_TYPE, data, w, r); err != nil {
- c.Err = err
- return
- }
-}
-
-func getFileInfo(c *Context, w http.ResponseWriter, r *http.Request) {
- info, err := getFileInfoForRequest(c, r, true)
- if err != nil {
- c.Err = err
- return
- }
-
- w.Header().Set("Cache-Control", "max-age=2592000, public")
-
- w.Write([]byte(info.ToJson()))
-}
-
-func getPublicFile(c *Context, w http.ResponseWriter, r *http.Request) {
- if !c.App.Config().FileSettings.EnablePublicLink {
- c.Err = model.NewAppError("getPublicFile", "api.file.get_file.public_disabled.app_error", nil, "", http.StatusNotImplemented)
- return
- }
-
- info, err := getFileInfoForRequest(c, r, false)
- if err != nil {
- c.Err = err
- return
- }
-
- hash := r.URL.Query().Get("h")
-
- if len(hash) > 0 {
- correctHash := app.GeneratePublicLinkHash(info.Id, *c.App.Config().FileSettings.PublicLinkSalt)
-
- if hash != correctHash {
- c.Err = model.NewAppError("getPublicFile", "api.file.get_file.public_invalid.app_error", nil, "", http.StatusBadRequest)
- utils.RenderWebAppError(w, r, c.Err, c.App.AsymmetricSigningKey())
- return
- }
- } else {
- c.Err = model.NewAppError("getPublicFile", "api.file.get_file.public_invalid.app_error", nil, "", http.StatusBadRequest)
- utils.RenderWebAppError(w, r, c.Err, c.App.AsymmetricSigningKey())
- return
- }
-
- if data, err := c.App.ReadFile(info.Path); err != nil {
- c.Err = err
- c.Err.StatusCode = http.StatusNotFound
- } else if err := writeFileResponse(info.Name, info.MimeType, data, w, r); err != nil {
- c.Err = err
- return
- }
-}
-
-func getFileInfoForRequest(c *Context, r *http.Request, requireFileVisible bool) (*model.FileInfo, *model.AppError) {
- if len(*c.App.Config().FileSettings.DriverName) == 0 {
- return nil, model.NewAppError("getFileInfoForRequest", "api.file.get_info_for_request.storage.app_error", nil, "", http.StatusNotImplemented)
- }
-
- params := mux.Vars(r)
-
- fileId := params["file_id"]
- if len(fileId) != 26 {
- return nil, NewInvalidParamError("getFileInfoForRequest", "file_id")
- }
-
- info, err := c.App.GetFileInfo(fileId)
- if err != nil {
- return nil, err
- }
-
- // only let users access files visible in a channel, unless they're the one who uploaded the file
- if info.CreatorId != c.Session.UserId {
- if len(info.PostId) == 0 {
- err := model.NewAppError("getFileInfoForRequest", "api.file.get_file_info_for_request.no_post.app_error", nil, "file_id="+fileId, http.StatusBadRequest)
- return nil, err
- }
-
- if requireFileVisible {
- if !c.App.SessionHasPermissionToChannelByPost(c.Session, info.PostId, model.PERMISSION_READ_CHANNEL) {
- c.SetPermissionError(model.PERMISSION_READ_CHANNEL)
- return nil, c.Err
- }
- }
- }
-
- return info, nil
-}
-
-func getPublicFileOld(c *Context, w http.ResponseWriter, r *http.Request) {
- if len(*c.App.Config().FileSettings.DriverName) == 0 {
- c.Err = model.NewAppError("getPublicFile", "api.file.get_public_file_old.storage.app_error", nil, "", http.StatusNotImplemented)
- return
- } else if !c.App.Config().FileSettings.EnablePublicLink {
- c.Err = model.NewAppError("getPublicFile", "api.file.get_file.public_disabled.app_error", nil, "", http.StatusNotImplemented)
- return
- }
-
- params := mux.Vars(r)
-
- teamId := params["team_id"]
- channelId := params["channel_id"]
- userId := params["user_id"]
- filename := params["filename"]
-
- hash := r.URL.Query().Get("h")
-
- if len(hash) > 0 {
- correctHash := app.GeneratePublicLinkHash(filename, *c.App.Config().FileSettings.PublicLinkSalt)
-
- if hash != correctHash {
- c.Err = model.NewAppError("getPublicFile", "api.file.get_file.public_invalid.app_error", nil, "", http.StatusBadRequest)
- http.Redirect(w, r, c.GetSiteURLHeader()+"/error?message="+utils.T(c.Err.Message), http.StatusTemporaryRedirect)
- return
- }
- } else {
- c.Err = model.NewAppError("getPublicFile", "api.file.get_file.public_invalid.app_error", nil, "", http.StatusBadRequest)
- http.Redirect(w, r, c.GetSiteURLHeader()+"/error?message="+utils.T(c.Err.Message), http.StatusTemporaryRedirect)
- return
- }
-
- path := "teams/" + teamId + "/channels/" + channelId + "/users/" + userId + "/" + filename
-
- var info *model.FileInfo
- if result := <-c.App.Srv.Store.FileInfo().GetByPath(path); result.Err != nil {
- c.Err = result.Err
- return
- } else {
- info = result.Data.(*model.FileInfo)
- }
-
- if len(info.PostId) == 0 {
- c.Err = model.NewAppError("getPublicFileOld", "api.file.get_public_file_old.no_post.app_error", nil, "file_id="+info.Id, http.StatusBadRequest)
- return
- }
-
- if data, err := c.App.ReadFile(info.Path); err != nil {
- c.Err = err
- c.Err.StatusCode = http.StatusNotFound
- } else if err := writeFileResponse(info.Name, info.MimeType, data, w, r); err != nil {
- c.Err = err
- return
- }
-}
-
-func writeFileResponse(filename string, contentType string, bytes []byte, w http.ResponseWriter, r *http.Request) *model.AppError {
- w.Header().Set("Cache-Control", "max-age=2592000, private")
- w.Header().Set("Content-Length", strconv.Itoa(len(bytes)))
- w.Header().Set("X-Content-Type-Options", "nosniff")
-
- if contentType == "" {
- contentType = "application/octet-stream"
- } else {
- for _, unsafeContentType := range UNSAFE_CONTENT_TYPES {
- if strings.HasPrefix(contentType, unsafeContentType) {
- contentType = "text/plain"
- break
- }
- }
- }
-
- w.Header().Set("Content-Type", contentType)
-
- w.Header().Set("Content-Disposition", "attachment;filename=\""+filename+"\"; filename*=UTF-8''"+url.QueryEscape(filename))
-
- // prevent file links from being embedded in iframes
- w.Header().Set("X-Frame-Options", "DENY")
- w.Header().Set("Content-Security-Policy", "Frame-ancestors 'none'")
-
- w.Write(bytes)
-
- return nil
-}
-
-func getPublicLink(c *Context, w http.ResponseWriter, r *http.Request) {
- if !c.App.Config().FileSettings.EnablePublicLink {
- c.Err = model.NewAppError("getPublicLink", "api.file.get_public_link.disabled.app_error", nil, "", http.StatusNotImplemented)
- return
- }
-
- info, err := getFileInfoForRequest(c, r, true)
- if err != nil {
- c.Err = err
- return
- }
-
- if len(info.PostId) == 0 {
- c.Err = model.NewAppError("getPublicLink", "api.file.get_public_link.no_post.app_error", nil, "file_id="+info.Id, http.StatusBadRequest)
- return
- }
-
- w.Write([]byte(model.StringToJson(c.App.GeneratePublicLinkV3(c.GetSiteURLHeader(), info))))
-}
diff --git a/api/file_test.go b/api/file_test.go
deleted file mode 100644
index 7a04674cd..000000000
--- a/api/file_test.go
+++ /dev/null
@@ -1,950 +0,0 @@
-// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-package api
-
-import (
- "bytes"
- "fmt"
- "io"
- "io/ioutil"
- "net/http"
- "os"
- "path/filepath"
- "strings"
- "testing"
- "time"
-
- "github.com/mattermost/mattermost-server/app"
- "github.com/mattermost/mattermost-server/model"
- "github.com/mattermost/mattermost-server/store"
- "github.com/mattermost/mattermost-server/utils"
-
- s3 "github.com/minio/minio-go"
- "github.com/minio/minio-go/pkg/credentials"
-)
-
-func TestUploadFile(t *testing.T) {
- th := Setup().InitBasic().InitSystemAdmin()
- defer th.TearDown()
-
- if *th.App.Config().FileSettings.DriverName == "" {
- t.Logf("skipping because no file driver is enabled")
- return
- }
-
- Client := th.BasicClient
- team := th.BasicTeam
- user := th.BasicUser
- channel := th.BasicChannel
-
- var uploadInfo *model.FileInfo
- var data []byte
- var err error
- if data, err = readTestFile("test.png"); err != nil {
- t.Fatal(err)
- } else if resp, err := Client.UploadPostAttachment(data, channel.Id, "test.png"); err != nil {
- t.Fatal(err)
- } else if len(resp.FileInfos) != 1 {
- t.Fatal("should've returned a single file infos")
- } else {
- uploadInfo = resp.FileInfos[0]
- }
-
- // The returned file info from the upload call will be missing some fields that will be stored in the database
- if uploadInfo.CreatorId != user.Id {
- t.Fatal("file should be assigned to user")
- } else if uploadInfo.PostId != "" {
- t.Fatal("file shouldn't have a post")
- } else if uploadInfo.Path != "" {
- t.Fatal("file path should not be set on returned info")
- } else if uploadInfo.ThumbnailPath != "" {
- t.Fatal("file thumbnail path should not be set on returned info")
- } else if uploadInfo.PreviewPath != "" {
- t.Fatal("file preview path should not be set on returned info")
- }
-
- var info *model.FileInfo
- if result := <-th.App.Srv.Store.FileInfo().Get(uploadInfo.Id); result.Err != nil {
- t.Fatal(result.Err)
- } else {
- info = result.Data.(*model.FileInfo)
- }
-
- if info.Id != uploadInfo.Id {
- t.Fatal("file id from response should match one stored in database")
- } else if info.CreatorId != user.Id {
- t.Fatal("file should be assigned to user")
- } else if info.PostId != "" {
- t.Fatal("file shouldn't have a post")
- } else if info.Path == "" {
- t.Fatal("file path should be set in database")
- } else if info.ThumbnailPath == "" {
- t.Fatal("file thumbnail path should be set in database")
- } else if info.PreviewPath == "" {
- t.Fatal("file preview path should be set in database")
- }
-
- date := time.Now().Format("20060102")
-
- // This also makes sure that the relative path provided above is sanitized out
- expectedPath := fmt.Sprintf("%v/teams/%v/channels/%v/users/%v/%v/test.png", date, team.Id, channel.Id, user.Id, info.Id)
- if info.Path != expectedPath {
- t.Logf("file is saved in %v", info.Path)
- t.Fatalf("file should've been saved in %v", expectedPath)
- }
-
- expectedThumbnailPath := fmt.Sprintf("%v/teams/%v/channels/%v/users/%v/%v/test_thumb.jpg", date, team.Id, channel.Id, user.Id, info.Id)
- if info.ThumbnailPath != expectedThumbnailPath {
- t.Logf("file thumbnail is saved in %v", info.ThumbnailPath)
- t.Fatalf("file thumbnail should've been saved in %v", expectedThumbnailPath)
- }
-
- expectedPreviewPath := fmt.Sprintf("%v/teams/%v/channels/%v/users/%v/%v/test_preview.jpg", date, team.Id, channel.Id, user.Id, info.Id)
- if info.PreviewPath != expectedPreviewPath {
- t.Logf("file preview is saved in %v", info.PreviewPath)
- t.Fatalf("file preview should've been saved in %v", expectedPreviewPath)
- }
-
- if _, err := Client.UploadPostAttachment(data, model.NewId(), "test.png"); err == nil || err.StatusCode != http.StatusForbidden {
- t.Fatal("should have failed - bad channel id")
- }
-
- if _, err := Client.UploadPostAttachment(data, "../../junk", "test.png"); err == nil || err.StatusCode != http.StatusForbidden {
- t.Fatal("should have failed - bad channel id")
- }
-
- if _, err := th.SystemAdminClient.UploadPostAttachment(data, model.NewId(), "test.png"); err == nil || err.StatusCode != http.StatusForbidden {
- t.Fatal("should have failed - bad channel id")
- }
-
- if _, err := th.SystemAdminClient.UploadPostAttachment(data, "../../junk", "test.png"); err == nil || err.StatusCode != http.StatusForbidden {
- t.Fatal("should have failed - bad channel id")
- }
-
- enableFileAttachments := *th.App.Config().FileSettings.EnableFileAttachments
- defer func() {
- th.App.UpdateConfig(func(cfg *model.Config) { *cfg.FileSettings.EnableFileAttachments = enableFileAttachments })
- }()
- th.App.UpdateConfig(func(cfg *model.Config) { *cfg.FileSettings.EnableFileAttachments = false })
-
- if data, err := readTestFile("test.png"); err != nil {
- t.Fatal(err)
- } else if _, err = Client.UploadPostAttachment(data, channel.Id, "test.png"); err == nil {
- t.Fatal("should have errored")
- }
-
- // Wait a bit for files to ready
- time.Sleep(2 * time.Second)
-
- if err := cleanupTestFile(info, &th.App.Config().FileSettings); err != nil {
- t.Fatal(err)
- }
-}
-
-func TestGetFileInfo(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- if *th.App.Config().FileSettings.DriverName == "" {
- t.Skip("skipping because no file driver is enabled")
- }
-
- Client := th.BasicClient
- user := th.BasicUser
- channel := th.BasicChannel
-
- var fileId string
- if data, err := readTestFile("test.png"); err != nil {
- t.Fatal(err)
- } else {
- fileId = Client.MustGeneric(Client.UploadPostAttachment(data, channel.Id, "test.png")).(*model.FileUploadResponse).FileInfos[0].Id
- }
-
- info, err := Client.GetFileInfo(fileId)
- if err != nil {
- t.Fatal(err)
- } else if info.Id != fileId {
- t.Fatal("got incorrect file")
- } else if info.CreatorId != user.Id {
- t.Fatal("file should be assigned to user")
- } else if info.PostId != "" {
- t.Fatal("file shouldn't have a post")
- } else if info.Path != "" {
- t.Fatal("file path shouldn't have been returned to client")
- } else if info.ThumbnailPath != "" {
- t.Fatal("file thumbnail path shouldn't have been returned to client")
- } else if info.PreviewPath != "" {
- t.Fatal("file preview path shouldn't have been returned to client")
- } else if info.MimeType != "image/png" {
- t.Fatal("mime type should've been image/png")
- }
-
- // Wait a bit for files to ready
- time.Sleep(2 * time.Second)
-
- // Other user shouldn't be able to get file info for this file before it's attached to a post
- th.LoginBasic2()
-
- if _, err := Client.GetFileInfo(fileId); err == nil {
- t.Fatal("other user shouldn't be able to get file info before it's attached to a post")
- }
-
- // Hacky way to assign file to a post (usually would be done by CreatePost call)
- store.Must(th.App.Srv.Store.FileInfo().AttachToPost(fileId, th.BasicPost.Id))
-
- // Other user shouldn't be able to get file info for this file if they're not in the channel for it
- if _, err := Client.GetFileInfo(fileId); err == nil {
- t.Fatal("other user shouldn't be able to get file info when not in channel")
- }
-
- Client.Must(Client.JoinChannel(channel.Id))
-
- // Other user should now be able to get file info
- if info2, err := Client.GetFileInfo(fileId); err != nil {
- t.Fatal(err)
- } else if info2.Id != fileId {
- t.Fatal("other user got incorrect file")
- }
-
- if err := cleanupTestFile(store.Must(th.App.Srv.Store.FileInfo().Get(fileId)).(*model.FileInfo), &th.App.Config().FileSettings); err != nil {
- t.Fatal(err)
- }
-}
-
-func TestGetFile(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- if *th.App.Config().FileSettings.DriverName == "" {
- t.Skip("skipping because no file driver is enabled")
- }
-
- Client := th.BasicClient
- channel := th.BasicChannel
-
- var fileId string
- data, err := readTestFile("test.png")
- if err != nil {
- t.Fatal(err)
- } else {
- fileId = Client.MustGeneric(Client.UploadPostAttachment(data, channel.Id, "test.png")).(*model.FileUploadResponse).FileInfos[0].Id
- }
-
- // Wait a bit for files to ready
- time.Sleep(2 * time.Second)
-
- if body, err := Client.GetFile(fileId); err != nil {
- t.Fatal(err)
- } else {
- received, err := ioutil.ReadAll(body)
- if err != nil {
- t.Fatal(err)
- } else if len(received) != len(data) {
- t.Fatal("received file should be the same size as the sent one")
- }
-
- for i := range data {
- if data[i] != received[i] {
- t.Fatal("received file didn't match sent one")
- }
- }
-
- body.Close()
- }
-
- // Other user shouldn't be able to get file for this file before it's attached to a post
- th.LoginBasic2()
-
- if _, err := Client.GetFile(fileId); err == nil {
- t.Fatal("other user shouldn't be able to get file before it's attached to a post")
- }
-
- // Hacky way to assign file to a post (usually would be done by CreatePost call)
- store.Must(th.App.Srv.Store.FileInfo().AttachToPost(fileId, th.BasicPost.Id))
-
- // Other user shouldn't be able to get file for this file if they're not in the channel for it
- if _, err := Client.GetFile(fileId); err == nil {
- t.Fatal("other user shouldn't be able to get file when not in channel")
- }
-
- Client.Must(Client.JoinChannel(channel.Id))
-
- // Other user should now be able to get file
- if body, err := Client.GetFile(fileId); err != nil {
- t.Fatal(err)
- } else {
- received, err := ioutil.ReadAll(body)
- if err != nil {
- t.Fatal(err)
- } else if len(received) != len(data) {
- t.Fatal("received file should be the same size as the sent one")
- }
-
- for i := range data {
- if data[i] != received[i] {
- t.Fatal("received file didn't match sent one")
- }
- }
-
- body.Close()
- }
-
- if err := cleanupTestFile(store.Must(th.App.Srv.Store.FileInfo().Get(fileId)).(*model.FileInfo), &th.App.Config().FileSettings); err != nil {
- t.Fatal(err)
- }
-}
-
-func TestGetFileThumbnail(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- if *th.App.Config().FileSettings.DriverName == "" {
- t.Skip("skipping because no file driver is enabled")
- }
-
- Client := th.BasicClient
- channel := th.BasicChannel
-
- var fileId string
- data, err := readTestFile("test.png")
- if err != nil {
- t.Fatal(err)
- } else {
- fileId = Client.MustGeneric(Client.UploadPostAttachment(data, channel.Id, "test.png")).(*model.FileUploadResponse).FileInfos[0].Id
- }
-
- // Wait a bit for files to ready
- time.Sleep(2 * time.Second)
-
- if body, err := Client.GetFileThumbnail(fileId); err != nil {
- t.Fatal(err)
- } else {
- body.Close()
- }
-
- // Other user shouldn't be able to get thumbnail for this file before it's attached to a post
- th.LoginBasic2()
-
- if _, err := Client.GetFileThumbnail(fileId); err == nil {
- t.Fatal("other user shouldn't be able to get file before it's attached to a post")
- }
-
- // Hacky way to assign file to a post (usually would be done by CreatePost call)
- store.Must(th.App.Srv.Store.FileInfo().AttachToPost(fileId, th.BasicPost.Id))
-
- // Other user shouldn't be able to get thumbnail for this file if they're not in the channel for it
- if _, err := Client.GetFileThumbnail(fileId); err == nil {
- t.Fatal("other user shouldn't be able to get file when not in channel")
- }
-
- Client.Must(Client.JoinChannel(channel.Id))
-
- // Other user should now be able to get thumbnail
- if body, err := Client.GetFileThumbnail(fileId); err != nil {
- t.Fatal(err)
- } else {
- body.Close()
- }
-
- if err := cleanupTestFile(store.Must(th.App.Srv.Store.FileInfo().Get(fileId)).(*model.FileInfo), &th.App.Config().FileSettings); err != nil {
- t.Fatal(err)
- }
-}
-
-func TestGetFilePreview(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- if *th.App.Config().FileSettings.DriverName == "" {
- t.Skip("skipping because no file driver is enabled")
- }
-
- Client := th.BasicClient
- channel := th.BasicChannel
-
- var fileId string
- data, err := readTestFile("test.png")
- if err != nil {
- t.Fatal(err)
- } else {
- fileId = Client.MustGeneric(Client.UploadPostAttachment(data, channel.Id, "test.png")).(*model.FileUploadResponse).FileInfos[0].Id
- }
-
- // Wait a bit for files to ready
- time.Sleep(2 * time.Second)
-
- if body, err := Client.GetFilePreview(fileId); err != nil {
- t.Fatal(err)
- } else {
- body.Close()
- }
-
- // Other user shouldn't be able to get preview for this file before it's attached to a post
- th.LoginBasic2()
-
- if _, err := Client.GetFilePreview(fileId); err == nil {
- t.Fatal("other user shouldn't be able to get file before it's attached to a post")
- }
-
- // Hacky way to assign file to a post (usually would be done by CreatePost call)
- store.Must(th.App.Srv.Store.FileInfo().AttachToPost(fileId, th.BasicPost.Id))
-
- // Other user shouldn't be able to get preview for this file if they're not in the channel for it
- if _, err := Client.GetFilePreview(fileId); err == nil {
- t.Fatal("other user shouldn't be able to get file when not in channel")
- }
-
- Client.Must(Client.JoinChannel(channel.Id))
-
- // Other user should now be able to get preview
- if body, err := Client.GetFilePreview(fileId); err != nil {
- t.Fatal(err)
- } else {
- body.Close()
- }
-
- if err := cleanupTestFile(store.Must(th.App.Srv.Store.FileInfo().Get(fileId)).(*model.FileInfo), &th.App.Config().FileSettings); err != nil {
- t.Fatal(err)
- }
-}
-
-func TestGetPublicFile(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- if *th.App.Config().FileSettings.DriverName == "" {
- t.Skip("skipping because no file driver is enabled")
- }
-
- enablePublicLink := th.App.Config().FileSettings.EnablePublicLink
- publicLinkSalt := *th.App.Config().FileSettings.PublicLinkSalt
- defer func() {
- th.App.UpdateConfig(func(cfg *model.Config) { cfg.FileSettings.EnablePublicLink = enablePublicLink })
- th.App.UpdateConfig(func(cfg *model.Config) { *cfg.FileSettings.PublicLinkSalt = publicLinkSalt })
- }()
- th.App.UpdateConfig(func(cfg *model.Config) { cfg.FileSettings.EnablePublicLink = true })
- th.App.UpdateConfig(func(cfg *model.Config) { *cfg.FileSettings.PublicLinkSalt = model.NewId() })
-
- Client := th.BasicClient
- channel := th.BasicChannel
-
- var fileId string
- data, err := readTestFile("test.png")
- if err != nil {
- t.Fatal(err)
- } else {
- fileId = Client.MustGeneric(Client.UploadPostAttachment(data, channel.Id, "test.png")).(*model.FileUploadResponse).FileInfos[0].Id
- }
-
- // Hacky way to assign file to a post (usually would be done by CreatePost call)
- store.Must(th.App.Srv.Store.FileInfo().AttachToPost(fileId, th.BasicPost.Id))
-
- link := Client.MustGeneric(Client.GetPublicLink(fileId)).(string)
-
- // Wait a bit for files to ready
- time.Sleep(2 * time.Second)
-
- if resp, err := http.Get(link); err != nil || resp.StatusCode != http.StatusOK {
- t.Log(link)
- t.Fatal("failed to get image with public link", err)
- }
-
- if resp, err := http.Get(link[:strings.LastIndex(link, "?")]); err == nil && resp.StatusCode != http.StatusBadRequest {
- t.Fatal("should've failed to get image with public link without hash", resp.Status)
- }
-
- th.App.UpdateConfig(func(cfg *model.Config) { cfg.FileSettings.EnablePublicLink = false })
- if resp, err := http.Get(link); err == nil && resp.StatusCode != http.StatusNotImplemented {
- t.Fatal("should've failed to get image with disabled public link")
- }
-
- th.App.UpdateConfig(func(cfg *model.Config) { cfg.FileSettings.EnablePublicLink = true })
-
- // test after the salt has changed
- th.App.UpdateConfig(func(cfg *model.Config) { *cfg.FileSettings.PublicLinkSalt = model.NewId() })
-
- if resp, err := http.Get(link); err == nil && resp.StatusCode != http.StatusBadRequest {
- t.Fatal("should've failed to get image with public link after salt changed")
- }
-
- if resp, err := http.Get(link); err == nil && resp.StatusCode != http.StatusBadRequest {
- t.Fatal("should've failed to get image with public link after salt changed")
- }
-
- if err := cleanupTestFile(store.Must(th.App.Srv.Store.FileInfo().Get(fileId)).(*model.FileInfo), &th.App.Config().FileSettings); err != nil {
- t.Fatal(err)
- }
-}
-
-func TestGetPublicFileOld(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- if *th.App.Config().FileSettings.DriverName == "" {
- t.Skip("skipping because no file driver is enabled")
- }
-
- enablePublicLink := th.App.Config().FileSettings.EnablePublicLink
- publicLinkSalt := *th.App.Config().FileSettings.PublicLinkSalt
- defer func() {
- th.App.UpdateConfig(func(cfg *model.Config) { cfg.FileSettings.EnablePublicLink = enablePublicLink })
- th.App.UpdateConfig(func(cfg *model.Config) { *cfg.FileSettings.PublicLinkSalt = publicLinkSalt })
- }()
- th.App.UpdateConfig(func(cfg *model.Config) { cfg.FileSettings.EnablePublicLink = true })
- th.App.UpdateConfig(func(cfg *model.Config) { *cfg.FileSettings.PublicLinkSalt = model.NewId() })
-
- channel := th.BasicChannel
-
- var fileId string
- data, err := readTestFile("test.png")
- if err != nil {
- t.Fatal(err)
- } else {
- //fileId = Client.MustGeneric(Client.UploadPostAttachment(data, channel.Id, "test.png")).(*model.FileUploadResponse).FileInfos[0].Id
- fileId = model.NewId()
- fileInfo := model.FileInfo{
- Id: fileId,
- CreateAt: model.GetMillis(),
- CreatorId: th.BasicUser.Id,
- Path: fmt.Sprintf("teams/%s/channels/%s/users/%s/%s/%s", th.BasicTeam.Id, channel.Id, th.BasicUser.Id, fileId, "test.png"),
- }
- store.Must(th.App.Srv.Store.FileInfo().Save(&fileInfo))
- uploadFileOld(t, data, fmt.Sprintf("data/teams/%s/channels/%s/users/%s/%s", th.BasicTeam.Id, channel.Id, th.BasicUser.Id, fileId), "test.png")
- }
-
- // Hacky way to assign file to a post (usually would be done by CreatePost call)
- store.Must(th.App.Srv.Store.FileInfo().AttachToPost(fileId, th.BasicPost.Id))
-
- // reconstruct old style of link
- siteURL := fmt.Sprintf("http://localhost:%v", th.App.Srv.ListenAddr.Port)
- link := generatePublicLinkOld(siteURL, th.BasicTeam.Id, channel.Id, th.BasicUser.Id, fileId+"/test.png", *th.App.Config().FileSettings.PublicLinkSalt)
-
- // Wait a bit for files to ready
- time.Sleep(2 * time.Second)
-
- if resp, err := http.Get(link); err != nil || resp.StatusCode != http.StatusOK {
- t.Fatalf("failed to get image with public link err=%v resp=%v", err, resp)
- }
-
- if resp, err := http.Get(link[:strings.LastIndex(link, "?")]); err == nil && resp.StatusCode != http.StatusBadRequest {
- t.Fatal("should've failed to get image with public link without hash", resp.Status)
- }
-
- th.App.UpdateConfig(func(cfg *model.Config) { cfg.FileSettings.EnablePublicLink = false })
- if resp, err := http.Get(link); err == nil && resp.StatusCode != http.StatusNotImplemented {
- t.Fatal("should've failed to get image with disabled public link")
- }
-
- th.App.UpdateConfig(func(cfg *model.Config) { cfg.FileSettings.EnablePublicLink = true })
-
- // test after the salt has changed
- th.App.UpdateConfig(func(cfg *model.Config) { *cfg.FileSettings.PublicLinkSalt = model.NewId() })
-
- if resp, err := http.Get(link); err == nil && resp.StatusCode != http.StatusBadRequest {
- t.Fatal("should've failed to get image with public link after salt changed")
- }
-
- if resp, err := http.Get(link); err == nil && resp.StatusCode != http.StatusBadRequest {
- t.Fatal("should've failed to get image with public link after salt changed")
- }
-
- if err := cleanupTestFile(store.Must(th.App.Srv.Store.FileInfo().Get(fileId)).(*model.FileInfo), &th.App.Config().FileSettings); err != nil {
- t.Fatal(err)
- }
-}
-
-func generatePublicLinkOld(siteURL, teamId, channelId, userId, filename, salt string) string {
- hash := app.GeneratePublicLinkHash(filename, salt)
- return fmt.Sprintf("%s%s/public/files/get/%s/%s/%s/%s?h=%s", siteURL, model.API_URL_SUFFIX_V3, teamId, channelId, userId, filename, hash)
-}
-
-func TestGetPublicLink(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- if *th.App.Config().FileSettings.DriverName == "" {
- t.Skip("skipping because no file driver is enabled")
- }
-
- enablePublicLink := th.App.Config().FileSettings.EnablePublicLink
- defer func() {
- th.App.UpdateConfig(func(cfg *model.Config) { cfg.FileSettings.EnablePublicLink = enablePublicLink })
- }()
- th.App.UpdateConfig(func(cfg *model.Config) { cfg.FileSettings.EnablePublicLink = true })
-
- Client := th.BasicClient
- channel := th.BasicChannel
-
- var fileId string
- data, err := readTestFile("test.png")
- if err != nil {
- t.Fatal(err)
- } else {
- fileId = Client.MustGeneric(Client.UploadPostAttachment(data, channel.Id, "test.png")).(*model.FileUploadResponse).FileInfos[0].Id
- }
-
- if _, err := Client.GetPublicLink(fileId); err == nil {
- t.Fatal("should've failed to get public link before file is attached to a post")
- }
-
- // Hacky way to assign file to a post (usually would be done by CreatePost call)
- store.Must(th.App.Srv.Store.FileInfo().AttachToPost(fileId, th.BasicPost.Id))
-
- th.App.UpdateConfig(func(cfg *model.Config) { cfg.FileSettings.EnablePublicLink = false })
-
- if _, err := Client.GetPublicLink(fileId); err == nil {
- t.Fatal("should've failed to get public link when disabled")
- }
-
- th.App.UpdateConfig(func(cfg *model.Config) { cfg.FileSettings.EnablePublicLink = true })
-
- if link, err := Client.GetPublicLink(fileId); err != nil {
- t.Fatal(err)
- } else if link == "" {
- t.Fatal("should've received public link")
- }
-
- // Other user shouldn't be able to get public link for this file if they're not in the channel for it
- th.LoginBasic2()
-
- if _, err := Client.GetPublicLink(fileId); err == nil {
- t.Fatal("other user shouldn't be able to get file when not in channel")
- }
-
- Client.Must(Client.JoinChannel(channel.Id))
-
- // Other user should now be able to get public link
- if link, err := Client.GetPublicLink(fileId); err != nil {
- t.Fatal(err)
- } else if link == "" {
- t.Fatal("should've received public link")
- }
-
- // Wait a bit for files to ready
- time.Sleep(2 * time.Second)
-
- if err := cleanupTestFile(store.Must(th.App.Srv.Store.FileInfo().Get(fileId)).(*model.FileInfo), &th.App.Config().FileSettings); err != nil {
- t.Fatal(err)
- }
-}
-
-func TestMigrateFilenamesToFileInfos(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- if *th.App.Config().FileSettings.DriverName == "" {
- t.Skip("skipping because no file driver is enabled")
- }
-
- Client := th.BasicClient
-
- user1 := th.BasicUser
-
- channel1 := Client.Must(Client.CreateChannel(&model.Channel{
- Name: model.NewId(),
- Type: model.CHANNEL_OPEN,
- // No TeamId set to simulate a direct channel
- })).Data.(*model.Channel)
-
- var fileId1 string
- var fileId2 string
- data, err := readTestFile("test.png")
- if err != nil {
- t.Fatal(err)
- } else {
- fileId1 = Client.MustGeneric(Client.UploadPostAttachment(data, channel1.Id, "test.png")).(*model.FileUploadResponse).FileInfos[0].Id
- uploadFileOld(t, data, fmt.Sprintf("data/teams/%s/channels/%s/users/%s/%s", th.BasicTeam.Id, channel1.Id, user1.Id, fileId1), "test.png")
- fileId2 = Client.MustGeneric(Client.UploadPostAttachment(data, channel1.Id, "test.png")).(*model.FileUploadResponse).FileInfos[0].Id
- uploadFileOld(t, data, fmt.Sprintf("data/teams/%s/channels/%s/users/%s/%s", th.BasicTeam.Id, channel1.Id, user1.Id, fileId2), "test.png")
- }
-
- // Bypass the Client whenever possible since we're trying to simulate a pre-3.5 post
- post1 := store.Must(th.App.Srv.Store.Post().Save(&model.Post{
- UserId: user1.Id,
- ChannelId: channel1.Id,
- Message: "test",
- Filenames: []string{
- fmt.Sprintf("/%s/%s/%s/%s", channel1.Id, user1.Id, fileId1, "test.png"),
- fmt.Sprintf("/%s/%s/%s/%s", channel1.Id, user1.Id, fileId2, "test.png"),
- fmt.Sprintf("/%s/%s/%s/%s", channel1.Id, user1.Id, fileId2, "test.png"), // duplicate a filename to recreate a rare bug
- },
- })).(*model.Post)
-
- if post1.FileIds != nil && len(post1.FileIds) > 0 {
- t.Fatal("post shouldn't have file ids")
- } else if post1.Filenames == nil || len(post1.Filenames) != 3 {
- t.Fatal("post should have filenames")
- }
-
- // Indirectly call migrateFilenamesToFileInfos by calling Client.GetFileInfosForPost
- var infos []*model.FileInfo
- if infosResult, err := Client.GetFileInfosForPost(post1.ChannelId, post1.Id, ""); err != nil {
- t.Fatal(err)
- } else {
- infos = infosResult
- }
-
- if len(infos) != 2 {
- t.Log(infos)
- t.Fatal("should've had 2 infos after migration")
- } else if infos[0].Path != "" || infos[0].ThumbnailPath != "" || infos[0].PreviewPath != "" {
- t.Fatal("shouldn't return paths to client")
- }
-
- // Should be able to get files after migration
- if body, err := Client.GetFile(infos[0].Id); err != nil {
- t.Fatal(err)
- } else {
- body.Close()
- }
-
- if body, err := Client.GetFile(infos[1].Id); err != nil {
- t.Fatal(err)
- } else {
- body.Close()
- }
-
- // Make sure we aren't generating a new set of FileInfos on a second call to GetFileInfosForPost
- if infos2 := Client.MustGeneric(Client.GetFileInfosForPost(post1.ChannelId, post1.Id, "")).([]*model.FileInfo); len(infos2) != len(infos) {
- t.Fatal("should've received the same 2 infos after second call")
- } else if (infos[0].Id != infos2[0].Id && infos[0].Id != infos2[1].Id) || (infos[1].Id != infos2[0].Id && infos[1].Id != infos2[1].Id) {
- t.Fatal("should've returned the exact same 2 infos after second call")
- }
-
- if result, err := Client.GetPost(post1.ChannelId, post1.Id, ""); err != nil {
- t.Fatal(err)
- } else if post := result.Data.(*model.PostList).Posts[post1.Id]; len(post.Filenames) != 0 {
- t.Fatal("post shouldn't have filenames")
- } else if len(post.FileIds) != 2 {
- t.Fatal("post should have 2 file ids")
- } else if (infos[0].Id != post.FileIds[0] && infos[0].Id != post.FileIds[1]) || (infos[1].Id != post.FileIds[0] && infos[1].Id != post.FileIds[1]) {
- t.Fatal("post file ids should match GetFileInfosForPost results")
- }
-}
-
-func uploadFileOld(t *testing.T, data []byte, dest string, filename string) {
- os.MkdirAll(dest, os.ModePerm)
- eFile, err := os.Create(dest + "/" + filename)
- if err != nil {
- t.Fatal(err)
- }
- defer eFile.Close()
-
- _, err = io.Copy(eFile, bytes.NewReader(data)) // first var shows number of bytes
- if err != nil {
- t.Fatal(err)
- }
-
- err = eFile.Sync()
- if err != nil {
- t.Fatal(err)
- }
-}
-
-func TestFindTeamIdForFilename(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- if *th.App.Config().FileSettings.DriverName == "" {
- t.Skip("skipping because no file driver is enabled")
- }
-
- Client := th.BasicClient
-
- user1 := th.BasicUser
-
- team1 := th.BasicTeam
- team2 := th.CreateTeam(th.BasicClient)
-
- channel1 := th.BasicChannel
-
- Client.SetTeamId(team2.Id)
- channel2 := Client.Must(Client.CreateChannel(&model.Channel{
- Name: model.NewId(),
- Type: model.CHANNEL_OPEN,
- // No TeamId set to simulate a direct channel
- })).Data.(*model.Channel)
- Client.SetTeamId(team1.Id)
-
- var fileId1 string
- var fileId2 string
- data, err := readTestFile("test.png")
- if err != nil {
- t.Fatal(err)
- } else {
- fileId1 = Client.MustGeneric(Client.UploadPostAttachment(data, channel1.Id, "test.png")).(*model.FileUploadResponse).FileInfos[0].Id
- uploadFileOld(t, data, fmt.Sprintf("data/teams/%s/channels/%s/users/%s/%s", team1.Id, channel1.Id, user1.Id, fileId1), "test.png")
-
- Client.SetTeamId(team2.Id)
- fileId2 = Client.MustGeneric(Client.UploadPostAttachment(data, channel2.Id, "test.png")).(*model.FileUploadResponse).FileInfos[0].Id
- uploadFileOld(t, data, fmt.Sprintf("data/teams/%s/channels/%s/users/%s/%s", team2.Id, channel2.Id, user1.Id, fileId2), "test.png")
- Client.SetTeamId(team1.Id)
- }
-
- // Bypass the Client whenever possible since we're trying to simulate a pre-3.5 post
- post1 := store.Must(th.App.Srv.Store.Post().Save(&model.Post{
- UserId: user1.Id,
- ChannelId: channel1.Id,
- Message: "test",
- Filenames: []string{fmt.Sprintf("/%s/%s/%s/%s", channel1.Id, user1.Id, fileId1, "test.png")},
- })).(*model.Post)
-
- if teamId := th.App.FindTeamIdForFilename(post1, post1.Filenames[0]); teamId != team1.Id {
- t.Log(teamId)
- t.Fatal("file should've been found under team1")
- }
-
- Client.SetTeamId(team2.Id)
- post2 := store.Must(th.App.Srv.Store.Post().Save(&model.Post{
- UserId: user1.Id,
- ChannelId: channel2.Id,
- Message: "test",
- Filenames: []string{fmt.Sprintf("/%s/%s/%s/%s", channel2.Id, user1.Id, fileId2, "test.png")},
- })).(*model.Post)
- Client.SetTeamId(team1.Id)
-
- if teamId := th.App.FindTeamIdForFilename(post2, post2.Filenames[0]); teamId != team2.Id {
- t.Fatal("file should've been found under team2")
- }
-}
-
-func TestGetInfoForFilename(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- if *th.App.Config().FileSettings.DriverName == "" {
- t.Skip("skipping because no file driver is enabled")
- }
-
- Client := th.BasicClient
-
- user1 := th.BasicUser
-
- team1 := th.BasicTeam
-
- channel1 := th.BasicChannel
-
- var fileId1 string
- var path string
- var thumbnailPath string
- var previewPath string
- data, err := readTestFile("test.png")
- if err != nil {
- t.Fatal(err)
- } else {
- fileId1 = Client.MustGeneric(Client.UploadPostAttachment(data, channel1.Id, "test.png")).(*model.FileUploadResponse).FileInfos[0].Id
- uploadFileOld(t, data, fmt.Sprintf("data/teams/%s/channels/%s/users/%s/%s", team1.Id, channel1.Id, user1.Id, fileId1), "test.png")
- path = store.Must(th.App.Srv.Store.FileInfo().Get(fileId1)).(*model.FileInfo).Path
- thumbnailPath = store.Must(th.App.Srv.Store.FileInfo().Get(fileId1)).(*model.FileInfo).ThumbnailPath
- previewPath = store.Must(th.App.Srv.Store.FileInfo().Get(fileId1)).(*model.FileInfo).PreviewPath
- }
-
- // Bypass the Client whenever possible since we're trying to simulate a pre-3.5 post
- post1 := store.Must(th.App.Srv.Store.Post().Save(&model.Post{
- UserId: user1.Id,
- ChannelId: channel1.Id,
- Message: "test",
- Filenames: []string{fmt.Sprintf("/%s/%s/%s/%s", channel1.Id, user1.Id, fileId1, "test.png")},
- })).(*model.Post)
-
- date := time.Now().Format("20060102")
-
- if info := th.App.GetInfoForFilename(post1, team1.Id, post1.Filenames[0]); info == nil {
- t.Fatal("info shouldn't be nil")
- } else if info.Id == "" {
- t.Fatal("info.Id shouldn't be empty")
- } else if info.CreatorId != user1.Id {
- t.Fatal("incorrect user id")
- } else if info.PostId != post1.Id {
- t.Fatal("incorrect user id")
- } else if fmt.Sprintf("%s/%s", date, info.Path) != path {
- t.Fatal("incorrect path")
- } else if fmt.Sprintf("%s/%s", date, info.ThumbnailPath) != thumbnailPath {
- t.Fatal("incorrect thumbnail path")
- } else if fmt.Sprintf("%s/%s", date, info.PreviewPath) != previewPath {
- t.Fatal("incorrect preview path")
- } else if info.Name != "test.png" {
- t.Fatal("incorrect name")
- }
-}
-
-func readTestFile(name string) ([]byte, error) {
- path, _ := utils.FindDir("tests")
- file, err := os.Open(filepath.Join(path, name))
- if err != nil {
- return nil, err
- }
- defer file.Close()
-
- data := &bytes.Buffer{}
- if _, err := io.Copy(data, file); err != nil {
- return nil, err
- } else {
- return data.Bytes(), nil
- }
-}
-
-// Similar to s3.New() but allows initialization of signature v2 or signature v4 client.
-// If signV2 input is false, function always returns signature v4.
-//
-// Additionally this function also takes a user defined region, if set
-// disables automatic region lookup.
-func s3New(endpoint, accessKey, secretKey string, secure bool, signV2 bool, region string) (*s3.Client, error) {
- var creds *credentials.Credentials
- if signV2 {
- creds = credentials.NewStatic(accessKey, secretKey, "", credentials.SignatureV2)
- } else {
- creds = credentials.NewStatic(accessKey, secretKey, "", credentials.SignatureV4)
- }
- return s3.NewWithCredentials(endpoint, creds, secure, region)
-}
-
-func cleanupTestFile(info *model.FileInfo, settings *model.FileSettings) error {
- if *settings.DriverName == model.IMAGE_DRIVER_S3 {
- endpoint := settings.AmazonS3Endpoint
- accessKey := settings.AmazonS3AccessKeyId
- secretKey := settings.AmazonS3SecretAccessKey
- secure := *settings.AmazonS3SSL
- signV2 := *settings.AmazonS3SignV2
- region := settings.AmazonS3Region
- s3Clnt, err := s3New(endpoint, accessKey, secretKey, secure, signV2, region)
- if err != nil {
- return err
- }
- bucket := settings.AmazonS3Bucket
- if err := s3Clnt.RemoveObject(bucket, info.Path); err != nil {
- return err
- }
-
- if info.ThumbnailPath != "" {
- if err := s3Clnt.RemoveObject(bucket, info.ThumbnailPath); err != nil {
- return err
- }
- }
-
- if info.PreviewPath != "" {
- if err := s3Clnt.RemoveObject(bucket, info.PreviewPath); err != nil {
- return err
- }
- }
- } else if *settings.DriverName == model.IMAGE_DRIVER_LOCAL {
- if err := os.Remove(settings.Directory + info.Path); err != nil {
- return err
- }
-
- if info.ThumbnailPath != "" {
- if err := os.Remove(settings.Directory + info.ThumbnailPath); err != nil {
- return err
- }
- }
-
- if info.PreviewPath != "" {
- if err := os.Remove(settings.Directory + info.PreviewPath); err != nil {
- return err
- }
- }
- }
-
- return nil
-}
diff --git a/api/general.go b/api/general.go
deleted file mode 100644
index 51c491526..000000000
--- a/api/general.go
+++ /dev/null
@@ -1,73 +0,0 @@
-// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-package api
-
-import (
- "fmt"
- "net/http"
- "strings"
-
- "github.com/mattermost/mattermost-server/model"
-)
-
-func (api *API) InitGeneral() {
- api.BaseRoutes.General.Handle("/client_props", api.ApiAppHandler(getClientConfig)).Methods("GET")
- api.BaseRoutes.General.Handle("/log_client", api.ApiAppHandler(logClient)).Methods("POST")
- api.BaseRoutes.General.Handle("/ping", api.ApiAppHandler(ping)).Methods("GET")
-}
-
-func getClientConfig(c *Context, w http.ResponseWriter, r *http.Request) {
- w.Write([]byte(model.MapToJson(c.App.ClientConfig())))
-}
-
-func logClient(c *Context, w http.ResponseWriter, r *http.Request) {
- forceToDebug := false
-
- if !*c.App.Config().ServiceSettings.EnableDeveloper {
- if c.Session.UserId == "" {
- c.Err = model.NewAppError("Permissions", "api.context.permissions.app_error", nil, "", http.StatusForbidden)
- return
- }
-
- if !c.App.SessionHasPermissionTo(c.Session, model.PERMISSION_MANAGE_SYSTEM) {
- forceToDebug = true
- }
- }
-
- m := model.MapFromJson(r.Body)
-
- lvl := m["level"]
- msg := m["message"]
-
- // filter out javascript errors from franz that are polluting the log files
- if strings.Contains(msg, "/franz") {
- forceToDebug = true
- }
-
- if len(msg) > 400 {
- msg = msg[0:399]
- }
-
- if lvl == "ERROR" {
- err := &model.AppError{}
- err.Message = msg
- err.Id = msg
- err.Where = "client"
-
- if forceToDebug {
- c.LogDebug(err)
- } else {
- c.LogError(err)
- }
- }
-
- ReturnStatusOK(w)
-}
-
-func ping(c *Context, w http.ResponseWriter, r *http.Request) {
- m := make(map[string]string)
- m["version"] = model.CurrentVersion
- m["server_time"] = fmt.Sprintf("%v", model.GetMillis())
- w.Write([]byte(model.MapToJson(m)))
-}
diff --git a/api/general_test.go b/api/general_test.go
deleted file mode 100644
index 5b0a2630f..000000000
--- a/api/general_test.go
+++ /dev/null
@@ -1,63 +0,0 @@
-// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-package api
-
-import (
- "testing"
-
- "github.com/mattermost/mattermost-server/model"
-)
-
-func TestGetClientProperties(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- if props, err := th.BasicClient.GetClientProperties(); err != nil {
- t.Fatal(err)
- } else {
- if len(props["Version"]) == 0 {
- t.Fatal()
- }
- }
-}
-
-func TestLogClient(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- if ret, _ := th.BasicClient.LogClient("this is a test"); !ret {
- t.Fatal("failed to log")
- }
-
- enableDeveloper := *th.App.Config().ServiceSettings.EnableDeveloper
- defer func() {
- th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableDeveloper = enableDeveloper })
- }()
- th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableDeveloper = false })
-
- th.BasicClient.Logout()
-
- if _, err := th.BasicClient.LogClient("this is a test"); err == nil {
- t.Fatal("should have failed")
- }
-
- th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableDeveloper = true })
-
- if ret, _ := th.BasicClient.LogClient("this is a test"); !ret {
- t.Fatal("failed to log")
- }
-}
-
-func TestGetPing(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- if m, err := th.BasicClient.GetPing(); err != nil {
- t.Fatal(err)
- } else {
- if len(m["version"]) == 0 {
- t.Fatal()
- }
- }
-}
diff --git a/api/license.go b/api/license.go
deleted file mode 100644
index 432442ad6..000000000
--- a/api/license.go
+++ /dev/null
@@ -1,100 +0,0 @@
-// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-package api
-
-import (
- "bytes"
- "io"
- "net/http"
-
- "github.com/mattermost/mattermost-server/model"
-)
-
-func (api *API) InitLicense() {
- api.BaseRoutes.License.Handle("/add", api.ApiAdminSystemRequired(addLicense)).Methods("POST")
- api.BaseRoutes.License.Handle("/remove", api.ApiAdminSystemRequired(removeLicense)).Methods("POST")
- api.BaseRoutes.License.Handle("/client_config", api.ApiAppHandler(getClientLicenceConfig)).Methods("GET")
-}
-
-func addLicense(c *Context, w http.ResponseWriter, r *http.Request) {
- c.LogAudit("attempt")
- err := r.ParseMultipartForm(*c.App.Config().FileSettings.MaxFileSize)
- if err != nil {
- http.Error(w, err.Error(), http.StatusInternalServerError)
- return
- }
-
- m := r.MultipartForm
-
- fileArray, ok := m.File["license"]
- if !ok {
- c.Err = model.NewAppError("addLicense", "api.license.add_license.no_file.app_error", nil, "", http.StatusBadRequest)
- return
- }
-
- if len(fileArray) <= 0 {
- c.Err = model.NewAppError("addLicense", "api.license.add_license.array.app_error", nil, "", http.StatusBadRequest)
- return
- }
-
- fileData := fileArray[0]
-
- file, err := fileData.Open()
- if err != nil {
- c.Err = model.NewAppError("addLicense", "api.license.add_license.open.app_error", nil, err.Error(), http.StatusInternalServerError)
- return
- }
- defer file.Close()
-
- buf := bytes.NewBuffer(nil)
- io.Copy(buf, file)
-
- if license, err := c.App.SaveLicense(buf.Bytes()); err != nil {
- if err.Id == model.EXPIRED_LICENSE_ERROR {
- c.LogAudit("failed - expired or non-started license")
- } else if err.Id == model.INVALID_LICENSE_ERROR {
- c.LogAudit("failed - invalid license")
- } else {
- c.LogAudit("failed - unable to save license")
- }
- c.Err = err
- return
- } else {
- c.LogAudit("success")
- w.Write([]byte(license.ToJson()))
- }
-}
-
-func removeLicense(c *Context, w http.ResponseWriter, r *http.Request) {
- c.LogAudit("")
-
- if err := c.App.RemoveLicense(); err != nil {
- c.Err = err
- return
- }
-
- rdata := map[string]string{}
- rdata["status"] = "ok"
- w.Write([]byte(model.MapToJson(rdata)))
-}
-
-func getClientLicenceConfig(c *Context, w http.ResponseWriter, r *http.Request) {
- useSanitizedLicense := !c.App.SessionHasPermissionTo(c.Session, model.PERMISSION_MANAGE_SYSTEM)
-
- etag := c.App.GetClientLicenseEtag(useSanitizedLicense)
- if c.HandleEtag(etag, "Get Client License Config", w, r) {
- return
- }
-
- var clientLicense map[string]string
-
- if useSanitizedLicense {
- clientLicense = c.App.ClientLicense()
- } else {
- clientLicense = c.App.GetSanitizedClientLicense()
- }
-
- w.Header().Set(model.HEADER_ETAG_SERVER, etag)
- w.Write([]byte(model.MapToJson(clientLicense)))
-}
diff --git a/api/license_test.go b/api/license_test.go
deleted file mode 100644
index 47586151a..000000000
--- a/api/license_test.go
+++ /dev/null
@@ -1,51 +0,0 @@
-// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-package api
-
-import (
- "testing"
-)
-
-func TestGetLicenceConfig(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- Client := th.BasicClient
-
- if result, err := Client.GetClientLicenceConfig(""); err != nil {
- t.Fatal(err)
- } else {
- cfg := result.Data.(map[string]string)
-
- if _, ok := cfg["IsLicensed"]; !ok {
- t.Fatal(cfg)
- }
-
- // test etag caching
- if cache_result, err := Client.GetClientLicenceConfig(result.Etag); err != nil {
- t.Fatal(err)
- } else if len(cache_result.Data.(map[string]string)) != 0 {
- t.Log(cache_result.Data)
- t.Fatal("cache should be empty")
- }
-
- th.App.SetClientLicense(map[string]string{"IsLicensed": "true"})
-
- if cache_result, err := Client.GetClientLicenceConfig(result.Etag); err != nil {
- t.Fatal(err)
- } else if len(cache_result.Data.(map[string]string)) == 0 {
- t.Fatal("result should not be empty")
- }
-
- th.App.SetClientLicense(map[string]string{"SomeFeature": "true", "IsLicensed": "true"})
-
- if cache_result, err := Client.GetClientLicenceConfig(result.Etag); err != nil {
- t.Fatal(err)
- } else if len(cache_result.Data.(map[string]string)) == 0 {
- t.Fatal("result should not be empty")
- }
-
- th.App.SetClientLicense(map[string]string{"IsLicensed": "false"})
- }
-}
diff --git a/api/oauth.go b/api/oauth.go
deleted file mode 100644
index 2fc83d122..000000000
--- a/api/oauth.go
+++ /dev/null
@@ -1,264 +0,0 @@
-// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-package api
-
-import (
- "net/http"
-
- "github.com/gorilla/mux"
- "github.com/mattermost/mattermost-server/model"
-)
-
-func (api *API) InitOAuth() {
- api.BaseRoutes.OAuth.Handle("/register", api.ApiUserRequired(registerOAuthApp)).Methods("POST")
- api.BaseRoutes.OAuth.Handle("/list", api.ApiUserRequired(getOAuthApps)).Methods("GET")
- api.BaseRoutes.OAuth.Handle("/app/{client_id}", api.ApiUserRequired(getOAuthAppInfo)).Methods("GET")
- api.BaseRoutes.OAuth.Handle("/allow", api.ApiUserRequired(allowOAuth)).Methods("GET")
- api.BaseRoutes.OAuth.Handle("/authorized", api.ApiUserRequired(getAuthorizedApps)).Methods("GET")
- api.BaseRoutes.OAuth.Handle("/delete", api.ApiUserRequired(deleteOAuthApp)).Methods("POST")
- api.BaseRoutes.OAuth.Handle("/{id:[A-Za-z0-9]+}/deauthorize", api.ApiUserRequired(deauthorizeOAuthApp)).Methods("POST")
- api.BaseRoutes.OAuth.Handle("/{id:[A-Za-z0-9]+}/regen_secret", api.ApiUserRequired(regenerateOAuthSecret)).Methods("POST")
- api.BaseRoutes.OAuth.Handle("/{service:[A-Za-z0-9]+}/login", api.AppHandlerIndependent(loginWithOAuth)).Methods("GET")
- api.BaseRoutes.OAuth.Handle("/{service:[A-Za-z0-9]+}/signup", api.AppHandlerIndependent(signupWithOAuth)).Methods("GET")
-}
-
-func registerOAuthApp(c *Context, w http.ResponseWriter, r *http.Request) {
- if !c.App.SessionHasPermissionTo(c.Session, model.PERMISSION_MANAGE_OAUTH) {
- c.Err = model.NewAppError("registerOAuthApp", "api.command.admin_only.app_error", nil, "", http.StatusForbidden)
- return
- }
-
- oauthApp := model.OAuthAppFromJson(r.Body)
-
- if oauthApp == nil {
- c.SetInvalidParam("registerOAuthApp", "app")
- return
- }
-
- if !c.App.SessionHasPermissionTo(c.Session, model.PERMISSION_MANAGE_SYSTEM) {
- oauthApp.IsTrusted = false
- }
-
- oauthApp.CreatorId = c.Session.UserId
-
- rapp, err := c.App.CreateOAuthApp(oauthApp)
-
- if err != nil {
- c.Err = err
- return
- }
-
- c.LogAudit("client_id=" + rapp.Id)
- w.Write([]byte(rapp.ToJson()))
-}
-
-func getOAuthApps(c *Context, w http.ResponseWriter, r *http.Request) {
- if !c.App.SessionHasPermissionTo(c.Session, model.PERMISSION_MANAGE_OAUTH) {
- c.Err = model.NewAppError("getOAuthApps", "api.command.admin_only.app_error", nil, "", http.StatusForbidden)
- return
- }
-
- var apps []*model.OAuthApp
- var err *model.AppError
- if c.App.SessionHasPermissionTo(c.Session, model.PERMISSION_MANAGE_SYSTEM_WIDE_OAUTH) {
- apps, err = c.App.GetOAuthApps(0, 100000)
- } else {
- apps, err = c.App.GetOAuthAppsByCreator(c.Session.UserId, 0, 100000)
- }
-
- if err != nil {
- c.Err = err
- return
- }
-
- w.Write([]byte(model.OAuthAppListToJson(apps)))
-}
-
-func getOAuthAppInfo(c *Context, w http.ResponseWriter, r *http.Request) {
- params := mux.Vars(r)
- clientId := params["client_id"]
-
- oauthApp, err := c.App.GetOAuthApp(clientId)
-
- if err != nil {
- c.Err = err
- return
- }
-
- oauthApp.Sanitize()
- w.Write([]byte(oauthApp.ToJson()))
-}
-
-func allowOAuth(c *Context, w http.ResponseWriter, r *http.Request) {
- responseType := r.URL.Query().Get("response_type")
- if len(responseType) == 0 {
- c.Err = model.NewAppError("allowOAuth", "api.oauth.allow_oauth.bad_response.app_error", nil, "", http.StatusBadRequest)
- return
- }
-
- clientId := r.URL.Query().Get("client_id")
- if len(clientId) != 26 {
- c.Err = model.NewAppError("allowOAuth", "api.oauth.allow_oauth.bad_client.app_error", nil, "", http.StatusBadRequest)
- return
- }
-
- redirectUri := r.URL.Query().Get("redirect_uri")
- if len(redirectUri) == 0 {
- c.Err = model.NewAppError("allowOAuth", "api.oauth.allow_oauth.bad_redirect.app_error", nil, "", http.StatusBadRequest)
- return
- }
-
- scope := r.URL.Query().Get("scope")
- state := r.URL.Query().Get("state")
-
- c.LogAudit("attempt")
-
- authRequest := &model.AuthorizeRequest{
- ResponseType: responseType,
- ClientId: clientId,
- RedirectUri: redirectUri,
- Scope: scope,
- State: state,
- }
-
- redirectUrl, err := c.App.AllowOAuthAppAccessToUser(c.Session.UserId, authRequest)
-
- if err != nil {
- c.Err = err
- return
- }
-
- c.LogAudit("")
-
- w.Write([]byte(model.MapToJson(map[string]string{"redirect": redirectUrl})))
-}
-
-func getAuthorizedApps(c *Context, w http.ResponseWriter, r *http.Request) {
- apps, err := c.App.GetAuthorizedAppsForUser(c.Session.UserId, 0, 10000)
- if err != nil {
- c.Err = err
- return
- }
-
- w.Write([]byte(model.OAuthAppListToJson(apps)))
-}
-
-func loginWithOAuth(c *Context, w http.ResponseWriter, r *http.Request) {
- params := mux.Vars(r)
- service := params["service"]
- loginHint := r.URL.Query().Get("login_hint")
- redirectTo := r.URL.Query().Get("redirect_to")
-
- teamId, err := c.App.GetTeamIdFromQuery(r.URL.Query())
- if err != nil {
- c.Err = err
- return
- }
-
- if authUrl, err := c.App.GetOAuthLoginEndpoint(w, r, service, teamId, model.OAUTH_ACTION_LOGIN, redirectTo, loginHint); err != nil {
- c.Err = err
- return
- } else {
- http.Redirect(w, r, authUrl, http.StatusFound)
- }
-}
-
-func signupWithOAuth(c *Context, w http.ResponseWriter, r *http.Request) {
- params := mux.Vars(r)
- service := params["service"]
-
- if !c.App.Config().TeamSettings.EnableUserCreation {
- c.Err = model.NewAppError("signupWithOAuth", "api.oauth.singup_with_oauth.disabled.app_error", nil, "", http.StatusNotImplemented)
- return
- }
-
- teamId, err := c.App.GetTeamIdFromQuery(r.URL.Query())
- if err != nil {
- c.Err = err
- return
- }
-
- if authUrl, err := c.App.GetOAuthSignupEndpoint(w, r, service, teamId); err != nil {
- c.Err = err
- return
- } else {
- http.Redirect(w, r, authUrl, http.StatusFound)
- }
-}
-
-func deleteOAuthApp(c *Context, w http.ResponseWriter, r *http.Request) {
- props := model.MapFromJson(r.Body)
-
- id := props["id"]
- if len(id) == 0 {
- c.SetInvalidParam("deleteOAuthApp", "id")
- return
- }
-
- c.LogAudit("attempt")
-
- if !c.App.SessionHasPermissionTo(c.Session, model.PERMISSION_MANAGE_OAUTH) {
- c.Err = model.NewAppError("deleteOAuthApp", "api.command.admin_only.app_error", nil, "", http.StatusForbidden)
- return
- }
-
- oauthApp, err := c.App.GetOAuthApp(id)
- if err != nil {
- c.Err = err
- return
- }
-
- if c.Session.UserId != oauthApp.CreatorId && !c.App.SessionHasPermissionTo(c.Session, model.PERMISSION_MANAGE_SYSTEM_WIDE_OAUTH) {
- c.LogAudit("fail - inappropriate permissions")
- c.Err = model.NewAppError("deleteOAuthApp", "api.oauth.delete.permissions.app_error", nil, "user_id="+c.Session.UserId, http.StatusForbidden)
- return
- }
-
- err = c.App.DeleteOAuthApp(id)
- if err != nil {
- c.Err = err
- return
- }
-
- c.LogAudit("success")
- ReturnStatusOK(w)
-}
-
-func deauthorizeOAuthApp(c *Context, w http.ResponseWriter, r *http.Request) {
- params := mux.Vars(r)
- id := params["id"]
-
- err := c.App.DeauthorizeOAuthAppForUser(c.Session.UserId, id)
- if err != nil {
- c.Err = err
- return
- }
-
- c.LogAudit("success")
- ReturnStatusOK(w)
-}
-
-func regenerateOAuthSecret(c *Context, w http.ResponseWriter, r *http.Request) {
- params := mux.Vars(r)
- id := params["id"]
-
- oauthApp, err := c.App.GetOAuthApp(id)
- if err != nil {
- c.Err = err
- return
- }
-
- if oauthApp.CreatorId != c.Session.UserId && !c.App.SessionHasPermissionTo(c.Session, model.PERMISSION_MANAGE_SYSTEM_WIDE_OAUTH) {
- c.Err = model.NewAppError("regenerateOAuthSecret", "api.command.admin_only.app_error", nil, "", http.StatusForbidden)
- return
- }
-
- oauthApp, err = c.App.RegenerateOAuthAppSecret(oauthApp)
- if err != nil {
- c.Err = err
- return
- }
-
- w.Write([]byte(oauthApp.ToJson()))
-}
diff --git a/api/oauth_test.go b/api/oauth_test.go
deleted file mode 100644
index 2428441b1..000000000
--- a/api/oauth_test.go
+++ /dev/null
@@ -1,895 +0,0 @@
-// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-package api
-
-import (
- "encoding/base64"
- "io"
- "io/ioutil"
- "net/http"
- "net/url"
- "strings"
- "testing"
-
- "github.com/mattermost/mattermost-server/einterfaces"
- "github.com/mattermost/mattermost-server/model"
- "github.com/mattermost/mattermost-server/utils"
-)
-
-func TestOAuthRegisterApp(t *testing.T) {
- th := Setup().InitBasic().InitSystemAdmin()
- defer th.TearDown()
-
- Client := th.BasicClient
-
- oauthApp := &model.OAuthApp{Name: "TestApp" + model.NewId(), Homepage: "https://nowhere.com", Description: "test", CallbackUrls: []string{"https://nowhere.com"}, IsTrusted: true}
-
- th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableOAuthServiceProvider = false })
- if !th.App.Config().ServiceSettings.EnableOAuthServiceProvider {
- if _, err := Client.RegisterApp(oauthApp); err == nil {
- t.Fatal("should have failed - oauth providing turned off")
- }
- }
-
- th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableOAuthServiceProvider = true })
-
- // calling the endpoint without an app
- if _, err := Client.DoApiPost("/oauth/register", ""); err == nil {
- t.Fatal("should have failed")
- }
-
- Client.Logout()
-
- if _, err := Client.RegisterApp(oauthApp); err == nil {
- t.Fatal("not logged in - should have failed")
- }
-
- th.LoginSystemAdmin()
- Client = th.SystemAdminClient
-
- if result, err := Client.RegisterApp(oauthApp); err != nil {
- t.Fatal(err)
- } else {
- rapp := result.Data.(*model.OAuthApp)
- if len(rapp.Id) != 26 {
- t.Fatal("clientid didn't return properly")
- }
- if len(rapp.ClientSecret) != 26 {
- t.Fatal("client secret didn't return properly")
- }
- }
-
- oauthApp = &model.OAuthApp{Name: "", Homepage: "https://nowhere.com", Description: "test", CallbackUrls: []string{"https://nowhere.com"}}
- if _, err := Client.RegisterApp(oauthApp); err == nil {
- t.Fatal("missing name - should have failed")
- }
-
- oauthApp = &model.OAuthApp{Name: "TestApp" + model.NewId(), Homepage: "", Description: "test", CallbackUrls: []string{"https://nowhere.com"}}
- if _, err := Client.RegisterApp(oauthApp); err == nil {
- t.Fatal("missing homepage - should have failed")
- }
-
- oauthApp = &model.OAuthApp{Name: "TestApp" + model.NewId(), Homepage: "https://nowhere.com", Description: "test", CallbackUrls: []string{}}
- if _, err := Client.RegisterApp(oauthApp); err == nil {
- t.Fatal("missing callback url - should have failed")
- }
-
- user := &model.User{Email: strings.ToLower("test+"+model.NewId()) + "@simulator.amazonses.com", Password: "hello1", Username: "n" + model.NewId(), EmailVerified: true}
-
- ruser := Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
- th.App.UpdateUserRoles(ruser.Id, "", false)
-
- Client.Logout()
- Client.Login(user.Email, user.Password)
-
- oauthApp = &model.OAuthApp{Name: "TestApp" + model.NewId(), Homepage: "https://nowhere.com", Description: "test", CallbackUrls: []string{"https://nowhere.com"}, IsTrusted: true}
- if _, err := Client.RegisterApp(oauthApp); err == nil {
- t.Fatal("should have failed. not enough permissions")
- }
-
- defaultRolePermissions := th.SaveDefaultRolePermissions()
- defer func() {
- th.RestoreDefaultRolePermissions(defaultRolePermissions)
- }()
- th.AddPermissionToRole(model.PERMISSION_MANAGE_OAUTH.Id, model.TEAM_USER_ROLE_ID)
- th.AddPermissionToRole(model.PERMISSION_MANAGE_OAUTH.Id, model.SYSTEM_USER_ROLE_ID)
-
- th.LoginBasic()
-
- if result, err := th.BasicClient.RegisterApp(oauthApp); err != nil {
- t.Fatal(err)
- } else {
- rapp := result.Data.(*model.OAuthApp)
- if rapp.IsTrusted {
- t.Fatal("trusted should be false - created by non admin")
- }
- }
-}
-
-func TestOAuthAllow(t *testing.T) {
- th := Setup().InitBasic().InitSystemAdmin()
- defer th.TearDown()
-
- Client := th.BasicClient
- AdminClient := th.SystemAdminClient
-
- th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableOAuthServiceProvider = true })
- oauthApp := &model.OAuthApp{Name: "TestApp" + model.NewId(), Homepage: "https://nowhere.com", Description: "test", CallbackUrls: []string{"https://nowhere.com"}}
- oauthApp = AdminClient.Must(AdminClient.RegisterApp(oauthApp)).Data.(*model.OAuthApp)
-
- state := "123"
-
- th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableOAuthServiceProvider = false })
- if _, err := Client.AllowOAuth(model.AUTHCODE_RESPONSE_TYPE, oauthApp.Id, oauthApp.CallbackUrls[0], "all", state); err == nil {
- t.Fatal("should have failed - oauth providing turned off")
- }
-
- th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableOAuthServiceProvider = true })
-
- if result, err := Client.AllowOAuth(model.AUTHCODE_RESPONSE_TYPE, oauthApp.Id, oauthApp.CallbackUrls[0], "all", state); err != nil {
- t.Fatal(err)
- } else {
- redirect := result.Data.(map[string]string)["redirect"]
- if len(redirect) == 0 {
- t.Fatal("redirect url should be set")
- }
-
- ru, _ := url.Parse(redirect)
- if ru == nil {
- t.Fatal("redirect url unparseable")
- } else {
- if len(ru.Query().Get("code")) == 0 {
- t.Fatal("authorization code not returned")
- }
- if ru.Query().Get("state") != state {
- t.Fatal("returned state doesn't match")
- }
- }
- }
-
- if _, err := Client.AllowOAuth(model.AUTHCODE_RESPONSE_TYPE, oauthApp.Id, "", "all", state); err == nil {
- t.Fatal("should have failed - no redirect_url given")
- }
-
- if _, err := Client.AllowOAuth("", oauthApp.Id, "", "", state); err == nil {
- t.Fatal("should have failed - no response type given")
- }
-
- if _, err := Client.AllowOAuth(model.AUTHCODE_RESPONSE_TYPE, oauthApp.Id, "", "", state); err == nil {
- t.Fatal("should have failed - no redirect_url given")
- }
-
- if result, err := Client.AllowOAuth("junk", oauthApp.Id, oauthApp.CallbackUrls[0], "all", state); err != nil {
- t.Fatal(err)
- } else {
- redirect := result.Data.(map[string]string)["redirect"]
- if len(redirect) == 0 {
- t.Fatal("redirect url should be set")
- }
-
- ru, _ := url.Parse(redirect)
- if ru == nil {
- t.Fatal("redirect url unparseable")
- } else {
- if ru.Query().Get("error") != "unsupported_response_type" {
- t.Fatal("wrong error returned")
- }
- if ru.Query().Get("state") != state {
- t.Fatal("returned state doesn't match")
- }
- }
- }
-
- if _, err := Client.AllowOAuth(model.AUTHCODE_RESPONSE_TYPE, "", oauthApp.CallbackUrls[0], "all", state); err == nil {
- t.Fatal("should have failed - empty client id")
- }
-
- if _, err := Client.AllowOAuth(model.AUTHCODE_RESPONSE_TYPE, "junk", oauthApp.CallbackUrls[0], "all", state); err == nil {
- t.Fatal("should have failed - bad client id")
- }
-
- if _, err := Client.AllowOAuth(model.AUTHCODE_RESPONSE_TYPE, oauthApp.Id, "https://somewhereelse.com", "", state); err == nil {
- t.Fatal("should have failed - redirect uri host does not match app host")
- }
-}
-
-func TestOAuthGetAppsByUser(t *testing.T) {
- th := Setup().InitBasic().InitSystemAdmin()
- defer th.TearDown()
-
- Client := th.BasicClient
- AdminClient := th.SystemAdminClient
-
- th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableOAuthServiceProvider = false })
- if !th.App.Config().ServiceSettings.EnableOAuthServiceProvider {
- if _, err := Client.GetOAuthAppsByUser(); err == nil {
- t.Fatal("should have failed - oauth providing turned off")
- }
-
- }
-
- th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableOAuthServiceProvider = true })
-
- if _, err := Client.GetOAuthAppsByUser(); err == nil {
- t.Fatal("Should have failed.")
- }
-
- defaultRolePermissions := th.SaveDefaultRolePermissions()
- defer func() {
- th.RestoreDefaultRolePermissions(defaultRolePermissions)
- }()
- th.AddPermissionToRole(model.PERMISSION_MANAGE_OAUTH.Id, model.TEAM_USER_ROLE_ID)
- th.AddPermissionToRole(model.PERMISSION_MANAGE_OAUTH.Id, model.SYSTEM_USER_ROLE_ID)
-
- if result, err := Client.GetOAuthAppsByUser(); err != nil {
- t.Fatal(err)
- } else {
- apps := result.Data.([]*model.OAuthApp)
-
- if len(apps) != 0 {
- t.Fatal("incorrect number of apps should have been 0")
- }
- }
-
- oauthApp := &model.OAuthApp{Name: "TestApp" + model.NewId(), Homepage: "https://nowhere.com", Description: "test", CallbackUrls: []string{"https://nowhere.com"}}
- oauthApp = Client.Must(Client.RegisterApp(oauthApp)).Data.(*model.OAuthApp)
-
- if result, err := Client.GetOAuthAppsByUser(); err != nil {
- t.Fatal(err)
- } else {
- apps := result.Data.([]*model.OAuthApp)
-
- if len(apps) != 1 {
- t.Fatal("incorrect number of apps should have been 1")
- }
- }
-
- oauthApp = &model.OAuthApp{Name: "TestApp4" + model.NewId(), Homepage: "https://nowhere.com", Description: "test", CallbackUrls: []string{"https://nowhere.com"}}
- oauthApp = AdminClient.Must(Client.RegisterApp(oauthApp)).Data.(*model.OAuthApp)
-
- if result, err := AdminClient.GetOAuthAppsByUser(); err != nil {
- t.Fatal(err)
- } else {
- apps := result.Data.([]*model.OAuthApp)
-
- if len(apps) < 4 {
- t.Fatal("incorrect number of apps should have been 4 or more")
- }
- }
-
- user := &model.User{Email: strings.ToLower("test+"+model.NewId()) + "@simulator.amazonses.com", Password: "hello1", Username: "n" + model.NewId(), EmailVerified: true}
- ruser := Client.Must(AdminClient.CreateUser(user, "")).Data.(*model.User)
- if _, err := th.App.UpdateUserRoles(ruser.Id, "", false); err != nil {
- t.Fatal(err)
- }
-
- Client.Logout()
- Client.Login(user.Email, user.Password)
-
- if _, err := Client.GetOAuthAppsByUser(); err == nil {
- t.Fatal("should have failed. not enough permissions")
- }
-}
-
-func TestOAuthGetAppInfo(t *testing.T) {
- th := Setup().InitBasic().InitSystemAdmin()
- defer th.TearDown()
-
- Client := th.BasicClient
- AdminClient := th.SystemAdminClient
-
- th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableOAuthServiceProvider = false })
- if !th.App.Config().ServiceSettings.EnableOAuthServiceProvider {
- if _, err := Client.GetOAuthAppInfo("fakeId"); err == nil {
- t.Fatal("should have failed - oauth providing turned off")
- }
-
- }
-
- th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableOAuthServiceProvider = true })
-
- oauthApp := &model.OAuthApp{Name: "TestApp5" + model.NewId(), Homepage: "https://nowhere.com", Description: "test", CallbackUrls: []string{"https://nowhere.com"}}
-
- oauthApp = AdminClient.Must(AdminClient.RegisterApp(oauthApp)).Data.(*model.OAuthApp)
-
- if _, err := Client.GetOAuthAppInfo(model.NewId()); err == nil {
- t.Fatal("Should have failed")
- }
-
- if _, err := Client.GetOAuthAppInfo(oauthApp.Id); err != nil {
- t.Fatal(err)
- }
-}
-
-func TestOAuthGetAuthorizedApps(t *testing.T) {
- th := Setup().InitBasic().InitSystemAdmin()
- defer th.TearDown()
-
- Client := th.BasicClient
- AdminClient := th.SystemAdminClient
-
- th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableOAuthServiceProvider = false })
- if !th.App.Config().ServiceSettings.EnableOAuthServiceProvider {
- if _, err := Client.GetOAuthAuthorizedApps(); err == nil {
- t.Fatal("should have failed - oauth providing turned off")
- }
-
- }
-
- th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableOAuthServiceProvider = true })
-
- oauthApp := &model.OAuthApp{Name: "TestApp5" + model.NewId(), Homepage: "https://nowhere.com", Description: "test", CallbackUrls: []string{"https://nowhere.com"}}
- oauthApp = AdminClient.Must(AdminClient.RegisterApp(oauthApp)).Data.(*model.OAuthApp)
-
- if _, err := Client.AllowOAuth(model.AUTHCODE_RESPONSE_TYPE, oauthApp.Id, "https://nowhere.com", "user", ""); err != nil {
- t.Fatal(err)
- }
-
- if result, err := Client.GetOAuthAuthorizedApps(); err != nil {
- t.Fatal(err)
- } else {
- apps := result.Data.([]*model.OAuthApp)
-
- if len(apps) != 1 {
- t.Fatal("incorrect number of apps should have been 1")
- }
- }
-}
-
-func TestOAuthDeauthorizeApp(t *testing.T) {
- th := Setup().InitBasic().InitSystemAdmin()
- defer th.TearDown()
-
- Client := th.BasicClient
- AdminClient := th.SystemAdminClient
-
- th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableOAuthServiceProvider = false })
- if !th.App.Config().ServiceSettings.EnableOAuthServiceProvider {
- if err := Client.OAuthDeauthorizeApp(model.NewId()); err == nil {
- t.Fatal("should have failed - oauth providing turned off")
- }
-
- }
-
- th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableOAuthServiceProvider = true })
-
- oauthApp := &model.OAuthApp{Name: "TestApp5" + model.NewId(), Homepage: "https://nowhere.com", Description: "test", CallbackUrls: []string{"https://nowhere.com"}}
-
- oauthApp = AdminClient.Must(AdminClient.RegisterApp(oauthApp)).Data.(*model.OAuthApp)
-
- if _, err := Client.AllowOAuth(model.AUTHCODE_RESPONSE_TYPE, oauthApp.Id, "https://nowhere.com", "user", ""); err != nil {
- t.Fatal(err)
- }
-
- if err := Client.OAuthDeauthorizeApp(""); err == nil {
- t.Fatal("Should have failed - no id provided")
- }
-
- a1 := model.AccessData{}
- a1.ClientId = oauthApp.Id
- a1.UserId = th.BasicUser.Id
- a1.Token = model.NewId()
- a1.RefreshToken = model.NewId()
- a1.ExpiresAt = model.GetMillis()
- a1.RedirectUri = "http://example.com"
- <-th.App.Srv.Store.OAuth().SaveAccessData(&a1)
-
- if err := Client.OAuthDeauthorizeApp(oauthApp.Id); err != nil {
- t.Fatal(err)
- }
-
- if result, err := Client.GetOAuthAuthorizedApps(); err != nil {
- t.Fatal(err)
- } else {
- apps := result.Data.([]*model.OAuthApp)
-
- if len(apps) != 0 {
- t.Fatal("incorrect number of apps should have been 0")
- }
- }
-}
-
-func TestOAuthRegenerateAppSecret(t *testing.T) {
- th := Setup().InitBasic().InitSystemAdmin()
- defer th.TearDown()
-
- Client := th.BasicClient
- AdminClient := th.SystemAdminClient
-
- th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableOAuthServiceProvider = false })
- if !th.App.Config().ServiceSettings.EnableOAuthServiceProvider {
- if _, err := AdminClient.RegenerateOAuthAppSecret(model.NewId()); err == nil {
- t.Fatal("should have failed - oauth providing turned off")
- }
-
- }
-
- th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableOAuthServiceProvider = true })
-
- oauthApp := &model.OAuthApp{Name: "TestApp6" + model.NewId(), Homepage: "https://nowhere.com", Description: "test", CallbackUrls: []string{"https://nowhere.com"}}
-
- oauthApp = AdminClient.Must(AdminClient.RegisterApp(oauthApp)).Data.(*model.OAuthApp)
-
- if _, err := AdminClient.RegenerateOAuthAppSecret(model.NewId()); err == nil {
- t.Fatal("Should have failed - invalid app id")
- }
-
- if _, err := Client.RegenerateOAuthAppSecret(oauthApp.Id); err == nil {
- t.Fatal("Should have failed - only admin or the user who registered the app are allowed to perform this action")
- }
-
- if regenApp, err := AdminClient.RegenerateOAuthAppSecret(oauthApp.Id); err != nil {
- t.Fatal(err)
- } else {
- app2 := regenApp.Data.(*model.OAuthApp)
- if app2.Id != oauthApp.Id {
- t.Fatal("Should have been the same app Id")
- }
-
- if app2.ClientSecret == oauthApp.ClientSecret {
- t.Fatal("Should have been different client Secrets")
- }
- }
-}
-
-func TestOAuthDeleteApp(t *testing.T) {
- th := Setup().InitBasic().InitSystemAdmin()
- defer th.TearDown()
-
- Client := th.BasicClient
- AdminClient := th.SystemAdminClient
-
- th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableOAuthServiceProvider = false })
- if !th.App.Config().ServiceSettings.EnableOAuthServiceProvider {
- if _, err := Client.DeleteOAuthApp("fakeId"); err == nil {
- t.Fatal("should have failed - oauth providing turned off")
- }
-
- }
-
- th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableOAuthServiceProvider = true })
-
- defaultRolePermissions := th.SaveDefaultRolePermissions()
- defer func() {
- th.RestoreDefaultRolePermissions(defaultRolePermissions)
- }()
- th.AddPermissionToRole(model.PERMISSION_MANAGE_OAUTH.Id, model.TEAM_USER_ROLE_ID)
- th.AddPermissionToRole(model.PERMISSION_MANAGE_OAUTH.Id, model.SYSTEM_USER_ROLE_ID)
-
- oauthApp := &model.OAuthApp{Name: "TestApp5" + model.NewId(), Homepage: "https://nowhere.com", Description: "test", CallbackUrls: []string{"https://nowhere.com"}}
-
- oauthApp = Client.Must(Client.RegisterApp(oauthApp)).Data.(*model.OAuthApp)
-
- if _, err := Client.DeleteOAuthApp(oauthApp.Id); err != nil {
- t.Fatal(err)
- }
-
- oauthApp = &model.OAuthApp{Name: "TestApp5" + model.NewId(), Homepage: "https://nowhere.com", Description: "test", CallbackUrls: []string{"https://nowhere.com"}}
-
- oauthApp = Client.Must(Client.RegisterApp(oauthApp)).Data.(*model.OAuthApp)
-
- if _, err := AdminClient.DeleteOAuthApp(""); err == nil {
- t.Fatal("Should have failed - id not provided")
- }
-
- if _, err := AdminClient.DeleteOAuthApp(model.NewId()); err == nil {
- t.Fatal("Should have failed - invalid id")
- }
-
- if _, err := AdminClient.DeleteOAuthApp(oauthApp.Id); err != nil {
- t.Fatal(err)
- }
-
- oauthApp = &model.OAuthApp{Name: "TestApp5" + model.NewId(), Homepage: "https://nowhere.com", Description: "test", CallbackUrls: []string{"https://nowhere.com"}}
- oauthApp = AdminClient.Must(AdminClient.RegisterApp(oauthApp)).Data.(*model.OAuthApp)
-
- if _, err := Client.DeleteOAuthApp(oauthApp.Id); err == nil {
- t.Fatal("Should have failed - only admin or the user who registered the app are allowed to perform this action")
- }
-
- user := &model.User{Email: strings.ToLower("test+"+model.NewId()) + "@simulator.amazonses.com", Password: "hello1", Username: "n" + model.NewId(), EmailVerified: true}
- ruser := Client.Must(AdminClient.CreateUser(user, "")).Data.(*model.User)
- th.App.UpdateUserRoles(ruser.Id, "", false)
-
- Client.Logout()
- Client.Login(user.Email, user.Password)
- if _, err := Client.DeleteOAuthApp(oauthApp.Id); err == nil {
- t.Fatal("Should have failed - not enough permissions")
- }
-}
-
-func TestOAuthAccessToken(t *testing.T) {
- if testing.Short() {
- t.SkipNow()
- }
-
- th := Setup().InitBasic()
- defer th.TearDown()
-
- Client := th.BasicClient
-
- enableOAuth := th.App.Config().ServiceSettings.EnableOAuthServiceProvider
- defer func() {
- th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableOAuthServiceProvider = enableOAuth })
- }()
- th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableOAuthServiceProvider = true })
-
- defaultRolePermissions := th.SaveDefaultRolePermissions()
- defer func() {
- th.RestoreDefaultRolePermissions(defaultRolePermissions)
- }()
- th.AddPermissionToRole(model.PERMISSION_MANAGE_OAUTH.Id, model.TEAM_USER_ROLE_ID)
- th.AddPermissionToRole(model.PERMISSION_MANAGE_OAUTH.Id, model.SYSTEM_USER_ROLE_ID)
-
- oauthApp := &model.OAuthApp{Name: "TestApp5" + model.NewId(), Homepage: "https://nowhere.com", Description: "test", CallbackUrls: []string{"https://nowhere.com"}}
- oauthApp = Client.Must(Client.RegisterApp(oauthApp)).Data.(*model.OAuthApp)
-
- th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableOAuthServiceProvider = false })
- data := url.Values{"grant_type": []string{"junk"}, "client_id": []string{"12345678901234567890123456"}, "client_secret": []string{"12345678901234567890123456"}, "code": []string{"junk"}, "redirect_uri": []string{oauthApp.CallbackUrls[0]}}
-
- if _, err := Client.GetAccessToken(data); err == nil {
- t.Fatal("should have failed - oauth providing turned off")
- }
- th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableOAuthServiceProvider = true })
-
- redirect := Client.Must(Client.AllowOAuth(model.AUTHCODE_RESPONSE_TYPE, oauthApp.Id, oauthApp.CallbackUrls[0], "all", "123")).Data.(map[string]string)["redirect"]
- rurl, _ := url.Parse(redirect)
-
- Client.Logout()
-
- data = url.Values{"grant_type": []string{"junk"}, "client_id": []string{oauthApp.Id}, "client_secret": []string{oauthApp.ClientSecret}, "code": []string{rurl.Query().Get("code")}, "redirect_uri": []string{oauthApp.CallbackUrls[0]}}
-
- if _, err := Client.GetAccessToken(data); err == nil {
- t.Fatal("should have failed - bad grant type")
- }
-
- data.Set("grant_type", model.ACCESS_TOKEN_GRANT_TYPE)
- data.Set("client_id", "")
- if _, err := Client.GetAccessToken(data); err == nil {
- t.Fatal("should have failed - missing client id")
- }
- data.Set("client_id", "junk")
- if _, err := Client.GetAccessToken(data); err == nil {
- t.Fatal("should have failed - bad client id")
- }
-
- data.Set("client_id", oauthApp.Id)
- data.Set("client_secret", "")
- if _, err := Client.GetAccessToken(data); err == nil {
- t.Fatal("should have failed - missing client secret")
- }
-
- data.Set("client_secret", "junk")
- if _, err := Client.GetAccessToken(data); err == nil {
- t.Fatal("should have failed - bad client secret")
- }
-
- data.Set("client_secret", oauthApp.ClientSecret)
- data.Set("code", "")
- if _, err := Client.GetAccessToken(data); err == nil {
- t.Fatal("should have failed - missing code")
- }
-
- data.Set("code", "junk")
- if _, err := Client.GetAccessToken(data); err == nil {
- t.Fatal("should have failed - bad code")
- }
-
- data.Set("code", rurl.Query().Get("code"))
- data.Set("redirect_uri", "junk")
- if _, err := Client.GetAccessToken(data); err == nil {
- t.Fatal("should have failed - non-matching redirect uri")
- }
-
- // reset data for successful request
- data.Set("grant_type", model.ACCESS_TOKEN_GRANT_TYPE)
- data.Set("client_id", oauthApp.Id)
- data.Set("client_secret", oauthApp.ClientSecret)
- data.Set("code", rurl.Query().Get("code"))
- data.Set("redirect_uri", oauthApp.CallbackUrls[0])
-
- token := ""
- refreshToken := ""
- if result, err := Client.GetAccessToken(data); err != nil {
- t.Fatal(err)
- } else {
- rsp := result.Data.(*model.AccessResponse)
- if len(rsp.AccessToken) == 0 {
- t.Fatal("access token not returned")
- } else if len(rsp.RefreshToken) == 0 {
- t.Fatal("refresh token not returned")
- } else {
- token = rsp.AccessToken
- refreshToken = rsp.RefreshToken
- }
- if rsp.TokenType != model.ACCESS_TOKEN_TYPE {
- t.Fatal("access token type incorrect")
- }
- }
-
- if result, err := Client.DoApiGet("/teams/"+th.BasicTeam.Id+"/users/0/100?access_token="+token, "", ""); err != nil {
- t.Fatal(err)
- } else {
- userMap := model.UserMapFromJson(result.Body)
- if len(userMap) == 0 {
- t.Fatal("user map empty - did not get results correctly")
- }
- }
-
- if _, err := Client.DoApiGet("/teams/"+th.BasicTeam.Id+"/users/0/100", "", ""); err == nil {
- t.Fatal("should have failed - no access token provided")
- }
-
- if _, err := Client.DoApiGet("/teams/"+th.BasicTeam.Id+"/users/0/100?access_token=junk", "", ""); err == nil {
- t.Fatal("should have failed - bad access token provided")
- }
-
- Client.SetOAuthToken(token)
- if result, err := Client.DoApiGet("/teams/"+th.BasicTeam.Id+"/users/0/100", "", ""); err != nil {
- t.Fatal(err)
- } else {
- userMap := model.UserMapFromJson(result.Body)
- if len(userMap) == 0 {
- t.Fatal("user map empty - did not get results correctly")
- }
- }
-
- if _, err := Client.GetAccessToken(data); err == nil {
- t.Fatal("should have failed - tried to reuse auth code")
- }
-
- data.Set("grant_type", model.REFRESH_TOKEN_GRANT_TYPE)
- data.Set("client_id", oauthApp.Id)
- data.Set("client_secret", oauthApp.ClientSecret)
- data.Set("refresh_token", "")
- data.Set("redirect_uri", oauthApp.CallbackUrls[0])
- data.Del("code")
- if _, err := Client.GetAccessToken(data); err == nil {
- t.Fatal("Should have failed - refresh token empty")
- }
-
- data.Set("refresh_token", refreshToken)
- if result, err := Client.GetAccessToken(data); err != nil {
- t.Fatal(err)
- } else {
- rsp := result.Data.(*model.AccessResponse)
- if len(rsp.AccessToken) == 0 {
- t.Fatal("access token not returned")
- } else if len(rsp.RefreshToken) == 0 {
- t.Fatal("refresh token not returned")
- } else if rsp.RefreshToken == refreshToken {
- t.Fatal("refresh token did not update")
- }
-
- if rsp.TokenType != model.ACCESS_TOKEN_TYPE {
- t.Fatal("access token type incorrect")
- }
- Client.SetOAuthToken(rsp.AccessToken)
- _, err = Client.GetMe("")
- if err != nil {
- t.Fatal(err)
- }
-
- data.Set("refresh_token", rsp.RefreshToken)
- }
-
- if result, err := Client.GetAccessToken(data); err != nil {
- t.Fatal(err)
- } else {
- rsp := result.Data.(*model.AccessResponse)
- if len(rsp.AccessToken) == 0 {
- t.Fatal("access token not returned")
- } else if len(rsp.RefreshToken) == 0 {
- t.Fatal("refresh token not returned")
- } else if rsp.RefreshToken == refreshToken {
- t.Fatal("refresh token did not update")
- }
-
- if rsp.TokenType != model.ACCESS_TOKEN_TYPE {
- t.Fatal("access token type incorrect")
- }
- Client.SetOAuthToken(rsp.AccessToken)
- _, err = Client.GetMe("")
- if err != nil {
- t.Fatal(err)
- }
- }
-
- authData := &model.AuthData{ClientId: oauthApp.Id, RedirectUri: oauthApp.CallbackUrls[0], UserId: th.BasicUser.Id, Code: model.NewId(), ExpiresIn: -1}
- <-th.App.Srv.Store.OAuth().SaveAuthData(authData)
-
- data.Set("grant_type", model.ACCESS_TOKEN_GRANT_TYPE)
- data.Set("client_id", oauthApp.Id)
- data.Set("client_secret", oauthApp.ClientSecret)
- data.Set("redirect_uri", oauthApp.CallbackUrls[0])
- data.Set("code", authData.Code)
- data.Del("refresh_token")
- if _, err := Client.GetAccessToken(data); err == nil {
- t.Fatal("Should have failed - code is expired")
- }
-
- Client.ClearOAuthToken()
-}
-
-func TestOAuthComplete(t *testing.T) {
- if testing.Short() {
- t.SkipNow()
- }
-
- th := Setup().InitBasic()
- defer th.TearDown()
-
- Client := th.BasicClient
-
- if r, err := HttpGet(Client.Url+"/login/gitlab/complete", Client.HttpClient, "", true); err == nil {
- t.Fatal("should have failed - no code provided")
- closeBody(r)
- }
-
- if r, err := HttpGet(Client.Url+"/login/gitlab/complete?code=123", Client.HttpClient, "", true); err == nil {
- t.Fatal("should have failed - gitlab disabled")
- closeBody(r)
- }
-
- th.App.UpdateConfig(func(cfg *model.Config) { cfg.GitLabSettings.Enable = true })
- if r, err := HttpGet(Client.Url+"/login/gitlab/complete?code=123&state=!#$#F@#Yˆ&~ñ", Client.HttpClient, "", true); err == nil {
- t.Fatal("should have failed - gitlab disabled")
- closeBody(r)
- }
-
- th.App.UpdateConfig(func(cfg *model.Config) { cfg.GitLabSettings.AuthEndpoint = Client.Url + "/oauth/authorize" })
- th.App.UpdateConfig(func(cfg *model.Config) { cfg.GitLabSettings.Id = model.NewId() })
-
- stateProps := map[string]string{}
- stateProps["action"] = model.OAUTH_ACTION_LOGIN
- stateProps["team_id"] = th.BasicTeam.Id
- stateProps["redirect_to"] = th.App.Config().GitLabSettings.AuthEndpoint
-
- state := base64.StdEncoding.EncodeToString([]byte(model.MapToJson(stateProps)))
- if r, err := HttpGet(Client.Url+"/login/gitlab/complete?code=123&state="+url.QueryEscape(state), Client.HttpClient, "", true); err == nil {
- t.Fatal("should have failed - bad state")
- closeBody(r)
- }
-
- stateProps["hash"] = utils.HashSha256(th.App.Config().GitLabSettings.Id)
- state = base64.StdEncoding.EncodeToString([]byte(model.MapToJson(stateProps)))
- if r, err := HttpGet(Client.Url+"/login/gitlab/complete?code=123&state="+url.QueryEscape(state), Client.HttpClient, "", true); err == nil {
- t.Fatal("should have failed - no connection")
- closeBody(r)
- }
-
- // We are going to use mattermost as the provider emulating gitlab
- th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableOAuthServiceProvider = true })
-
- defaultRolePermissions := th.SaveDefaultRolePermissions()
- defer func() {
- th.RestoreDefaultRolePermissions(defaultRolePermissions)
- }()
- th.AddPermissionToRole(model.PERMISSION_MANAGE_OAUTH.Id, model.TEAM_USER_ROLE_ID)
- th.AddPermissionToRole(model.PERMISSION_MANAGE_OAUTH.Id, model.SYSTEM_USER_ROLE_ID)
-
- oauthApp := &model.OAuthApp{
- Name: "TestApp5" + model.NewId(),
- Homepage: "https://nowhere.com",
- Description: "test",
- CallbackUrls: []string{
- Client.Url + "/signup/" + model.SERVICE_GITLAB + "/complete",
- Client.Url + "/login/" + model.SERVICE_GITLAB + "/complete",
- },
- IsTrusted: true,
- }
- oauthApp = Client.Must(Client.RegisterApp(oauthApp)).Data.(*model.OAuthApp)
-
- th.App.UpdateConfig(func(cfg *model.Config) { cfg.GitLabSettings.Id = oauthApp.Id })
- th.App.UpdateConfig(func(cfg *model.Config) { cfg.GitLabSettings.Secret = oauthApp.ClientSecret })
- th.App.UpdateConfig(func(cfg *model.Config) { cfg.GitLabSettings.AuthEndpoint = Client.Url + "/oauth/authorize" })
- th.App.UpdateConfig(func(cfg *model.Config) { cfg.GitLabSettings.TokenEndpoint = Client.Url + "/oauth/access_token" })
- th.App.UpdateConfig(func(cfg *model.Config) { cfg.GitLabSettings.UserApiEndpoint = Client.ApiUrl + "/users/me" })
-
- provider := &MattermostTestProvider{}
-
- redirect := Client.Must(Client.AllowOAuth(model.AUTHCODE_RESPONSE_TYPE, oauthApp.Id, oauthApp.CallbackUrls[0], "all", "123")).Data.(map[string]string)["redirect"]
- rurl, _ := url.Parse(redirect)
- code := rurl.Query().Get("code")
- stateProps["action"] = model.OAUTH_ACTION_EMAIL_TO_SSO
- delete(stateProps, "team_id")
- stateProps["redirect_to"] = th.App.Config().GitLabSettings.AuthEndpoint
- stateProps["hash"] = utils.HashSha256(th.App.Config().GitLabSettings.Id)
- stateProps["redirect_to"] = "/oauth/authorize"
- state = base64.StdEncoding.EncodeToString([]byte(model.MapToJson(stateProps)))
- if r, err := HttpGet(Client.Url+"/login/"+model.SERVICE_GITLAB+"/complete?code="+url.QueryEscape(code)+"&state="+url.QueryEscape(state), Client.HttpClient, "", false); err == nil {
- closeBody(r)
- }
-
- einterfaces.RegisterOauthProvider(model.SERVICE_GITLAB, provider)
- redirect = Client.Must(Client.AllowOAuth(model.AUTHCODE_RESPONSE_TYPE, oauthApp.Id, oauthApp.CallbackUrls[0], "all", "123")).Data.(map[string]string)["redirect"]
- rurl, _ = url.Parse(redirect)
- code = rurl.Query().Get("code")
- if r, err := HttpGet(Client.Url+"/login/"+model.SERVICE_GITLAB+"/complete?code="+url.QueryEscape(code)+"&state="+url.QueryEscape(state), Client.HttpClient, "", false); err == nil {
- closeBody(r)
- }
-
- if result := <-th.App.Srv.Store.User().UpdateAuthData(
- th.BasicUser.Id, model.SERVICE_GITLAB, &th.BasicUser.Email, th.BasicUser.Email, true); result.Err != nil {
- t.Fatal(result.Err)
- }
-
- redirect = Client.Must(Client.AllowOAuth(model.AUTHCODE_RESPONSE_TYPE, oauthApp.Id, oauthApp.CallbackUrls[0], "all", "123")).Data.(map[string]string)["redirect"]
- rurl, _ = url.Parse(redirect)
- code = rurl.Query().Get("code")
- stateProps["action"] = model.OAUTH_ACTION_LOGIN
- state = base64.StdEncoding.EncodeToString([]byte(model.MapToJson(stateProps)))
- if r, err := HttpGet(Client.Url+"/login/"+model.SERVICE_GITLAB+"/complete?code="+url.QueryEscape(code)+"&state="+url.QueryEscape(state), Client.HttpClient, "", false); err == nil {
- closeBody(r)
- }
-
- redirect = Client.Must(Client.AllowOAuth(model.AUTHCODE_RESPONSE_TYPE, oauthApp.Id, oauthApp.CallbackUrls[0], "all", "123")).Data.(map[string]string)["redirect"]
- rurl, _ = url.Parse(redirect)
- code = rurl.Query().Get("code")
- delete(stateProps, "action")
- state = base64.StdEncoding.EncodeToString([]byte(model.MapToJson(stateProps)))
- if r, err := HttpGet(Client.Url+"/login/"+model.SERVICE_GITLAB+"/complete?code="+url.QueryEscape(code)+"&state="+url.QueryEscape(state), Client.HttpClient, "", false); err == nil {
- closeBody(r)
- }
-
- redirect = Client.Must(Client.AllowOAuth(model.AUTHCODE_RESPONSE_TYPE, oauthApp.Id, oauthApp.CallbackUrls[0], "all", "123")).Data.(map[string]string)["redirect"]
- rurl, _ = url.Parse(redirect)
- code = rurl.Query().Get("code")
- stateProps["action"] = model.OAUTH_ACTION_SIGNUP
- state = base64.StdEncoding.EncodeToString([]byte(model.MapToJson(stateProps)))
- if r, err := HttpGet(Client.Url+"/login/"+model.SERVICE_GITLAB+"/complete?code="+url.QueryEscape(code)+"&state="+url.QueryEscape(state), Client.HttpClient, "", false); err == nil {
- closeBody(r)
- }
-}
-
-func HttpGet(url string, httpClient *http.Client, authToken string, followRedirect bool) (*http.Response, *model.AppError) {
- rq, _ := http.NewRequest("GET", url, nil)
- rq.Close = true
-
- if len(authToken) > 0 {
- rq.Header.Set(model.HEADER_AUTH, authToken)
- }
-
- if !followRedirect {
- httpClient.CheckRedirect = func(req *http.Request, via []*http.Request) error {
- return http.ErrUseLastResponse
- }
- }
-
- if rp, err := httpClient.Do(rq); err != nil {
- return nil, model.NewAppError(url, "model.client.connecting.app_error", nil, err.Error(), 0)
- } else if rp.StatusCode == 304 {
- return rp, nil
- } else if rp.StatusCode == 307 {
- return rp, nil
- } else if rp.StatusCode >= 300 {
- defer closeBody(rp)
- return rp, model.AppErrorFromJson(rp.Body)
- } else {
- return rp, nil
- }
-}
-
-func closeBody(r *http.Response) {
- if r.Body != nil {
- ioutil.ReadAll(r.Body)
- r.Body.Close()
- }
-}
-
-type MattermostTestProvider struct {
-}
-
-func (m *MattermostTestProvider) GetIdentifier() string {
- return model.SERVICE_GITLAB
-}
-
-func (m *MattermostTestProvider) GetUserFromJson(data io.Reader) *model.User {
- return model.UserFromJson(data)
-}
-
-func (m *MattermostTestProvider) GetAuthDataFromJson(data io.Reader) string {
- authData := model.UserFromJson(data)
- return authData.Email
-}
diff --git a/api/post.go b/api/post.go
deleted file mode 100644
index bed2f3fdb..000000000
--- a/api/post.go
+++ /dev/null
@@ -1,560 +0,0 @@
-// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-package api
-
-import (
- "net/http"
- "strconv"
- "time"
-
- "github.com/gorilla/mux"
-
- "github.com/mattermost/mattermost-server/model"
- "github.com/mattermost/mattermost-server/utils"
-)
-
-const OPEN_GRAPH_METADATA_CACHE_SIZE = 10000
-
-var openGraphDataCache = utils.NewLru(OPEN_GRAPH_METADATA_CACHE_SIZE)
-
-func (api *API) InitPost() {
- api.BaseRoutes.ApiRoot.Handle("/get_opengraph_metadata", api.ApiUserRequired(getOpenGraphMetadata)).Methods("POST")
-
- api.BaseRoutes.NeedTeam.Handle("/posts/search", api.ApiUserRequiredActivity(searchPosts, true)).Methods("POST")
- api.BaseRoutes.NeedTeam.Handle("/posts/flagged/{offset:[0-9]+}/{limit:[0-9]+}", api.ApiUserRequired(getFlaggedPosts)).Methods("GET")
- api.BaseRoutes.NeedTeam.Handle("/posts/{post_id}", api.ApiUserRequired(getPostById)).Methods("GET")
- api.BaseRoutes.NeedTeam.Handle("/pltmp/{post_id}", api.ApiUserRequired(getPermalinkTmp)).Methods("GET")
-
- api.BaseRoutes.Posts.Handle("/create", api.ApiUserRequiredActivity(createPost, true)).Methods("POST")
- api.BaseRoutes.Posts.Handle("/update", api.ApiUserRequiredActivity(updatePost, true)).Methods("POST")
- api.BaseRoutes.Posts.Handle("/page/{offset:[0-9]+}/{limit:[0-9]+}", api.ApiUserRequired(getPosts)).Methods("GET")
- api.BaseRoutes.Posts.Handle("/since/{time:[0-9]+}", api.ApiUserRequired(getPostsSince)).Methods("GET")
-
- api.BaseRoutes.NeedPost.Handle("/get", api.ApiUserRequired(getPost)).Methods("GET")
- api.BaseRoutes.NeedPost.Handle("/delete", api.ApiUserRequiredActivity(deletePost, true)).Methods("POST")
- api.BaseRoutes.NeedPost.Handle("/before/{offset:[0-9]+}/{num_posts:[0-9]+}", api.ApiUserRequired(getPostsBefore)).Methods("GET")
- api.BaseRoutes.NeedPost.Handle("/after/{offset:[0-9]+}/{num_posts:[0-9]+}", api.ApiUserRequired(getPostsAfter)).Methods("GET")
- api.BaseRoutes.NeedPost.Handle("/get_file_infos", api.ApiUserRequired(getFileInfosForPost)).Methods("GET")
- api.BaseRoutes.NeedPost.Handle("/pin", api.ApiUserRequired(pinPost)).Methods("POST")
- api.BaseRoutes.NeedPost.Handle("/unpin", api.ApiUserRequired(unpinPost)).Methods("POST")
-}
-
-func createPost(c *Context, w http.ResponseWriter, r *http.Request) {
- post := model.PostFromJson(r.Body)
- if post == nil {
- c.SetInvalidParam("createPost", "post")
- return
- }
-
- post.UserId = c.Session.UserId
-
- hasPermission := false
- if c.App.SessionHasPermissionToChannel(c.Session, post.ChannelId, model.PERMISSION_CREATE_POST) {
- hasPermission = true
- } else if channel, err := c.App.GetChannel(post.ChannelId); err == nil {
- // Temporary permission check method until advanced permissions, please do not copy
- if channel.Type == model.CHANNEL_OPEN && c.App.SessionHasPermissionToTeam(c.Session, channel.TeamId, model.PERMISSION_CREATE_POST_PUBLIC) {
- hasPermission = true
- }
- }
-
- if !hasPermission {
- c.SetPermissionError(model.PERMISSION_CREATE_POST)
- return
- }
-
- if post.CreateAt != 0 && !c.App.SessionHasPermissionTo(c.Session, model.PERMISSION_MANAGE_SYSTEM) {
- post.CreateAt = 0
- }
-
- rp, err := c.App.CreatePostAsUser(post)
- if err != nil {
- c.Err = err
- return
- }
-
- w.Write([]byte(rp.ToJson()))
-}
-
-func updatePost(c *Context, w http.ResponseWriter, r *http.Request) {
- post := model.PostFromJson(r.Body)
-
- if post == nil {
- c.SetInvalidParam("updatePost", "post")
- return
- }
-
- if !c.App.SessionHasPermissionToChannel(c.Session, post.ChannelId, model.PERMISSION_EDIT_POST) {
- c.SetPermissionError(model.PERMISSION_EDIT_POST)
- return
- }
-
- post.UserId = c.Session.UserId
-
- rpost, err := c.App.UpdatePost(post, true)
- if err != nil {
- c.Err = err
- return
- }
-
- w.Write([]byte(rpost.ToJson()))
-}
-
-func saveIsPinnedPost(c *Context, w http.ResponseWriter, r *http.Request, isPinned bool) {
- params := mux.Vars(r)
-
- channelId := params["channel_id"]
- if len(channelId) != 26 {
- c.SetInvalidParam("savedIsPinnedPost", "channelId")
- return
- }
-
- postId := params["post_id"]
- if len(postId) != 26 {
- c.SetInvalidParam("savedIsPinnedPost", "postId")
- return
- }
-
- pchan := c.App.Srv.Store.Post().Get(postId)
-
- var oldPost *model.Post
- if result := <-pchan; result.Err != nil {
- c.Err = result.Err
- return
- } else {
- oldPost = result.Data.(*model.PostList).Posts[postId]
- newPost := &model.Post{}
- *newPost = *oldPost
- newPost.IsPinned = isPinned
-
- if result := <-c.App.Srv.Store.Post().Update(newPost, oldPost); result.Err != nil {
- c.Err = result.Err
- return
- } else {
- rpost := result.Data.(*model.Post)
-
- message := model.NewWebSocketEvent(model.WEBSOCKET_EVENT_POST_EDITED, "", rpost.ChannelId, "", nil)
- message.Add("post", c.App.PostWithProxyAddedToImageURLs(rpost).ToJson())
- c.App.Publish(message)
-
- c.App.InvalidateCacheForChannelPosts(rpost.ChannelId)
-
- w.Write([]byte(rpost.ToJson()))
- }
- }
-}
-
-func pinPost(c *Context, w http.ResponseWriter, r *http.Request) {
- saveIsPinnedPost(c, w, r, true)
-}
-
-func unpinPost(c *Context, w http.ResponseWriter, r *http.Request) {
- saveIsPinnedPost(c, w, r, false)
-}
-
-func getFlaggedPosts(c *Context, w http.ResponseWriter, r *http.Request) {
- params := mux.Vars(r)
-
- offset, err := strconv.Atoi(params["offset"])
- if err != nil {
- c.SetInvalidParam("getFlaggedPosts", "offset")
- return
- }
-
- limit, err := strconv.Atoi(params["limit"])
- if err != nil {
- c.SetInvalidParam("getFlaggedPosts", "limit")
- return
- }
-
- if !c.App.SessionHasPermissionToTeam(c.Session, c.TeamId, model.PERMISSION_VIEW_TEAM) {
- c.SetPermissionError(model.PERMISSION_VIEW_TEAM)
- return
- }
-
- if posts, err := c.App.GetFlaggedPostsForTeam(c.Session.UserId, c.TeamId, offset, limit); err != nil {
- c.Err = err
- return
- } else {
- w.Write([]byte(posts.ToJson()))
- }
-}
-
-func getPosts(c *Context, w http.ResponseWriter, r *http.Request) {
- params := mux.Vars(r)
-
- id := params["channel_id"]
- if len(id) != 26 {
- c.SetInvalidParam("getPosts", "channelId")
- return
- }
-
- offset, err := strconv.Atoi(params["offset"])
- if err != nil {
- c.SetInvalidParam("getPosts", "offset")
- return
- }
-
- limit, err := strconv.Atoi(params["limit"])
- if err != nil {
- c.SetInvalidParam("getPosts", "limit")
- return
- }
-
- if !c.App.SessionHasPermissionToChannel(c.Session, id, model.PERMISSION_CREATE_POST) {
- c.SetPermissionError(model.PERMISSION_CREATE_POST)
- return
- }
-
- etag := c.App.GetPostsEtag(id)
-
- if c.HandleEtag(etag, "Get Posts", w, r) {
- return
- }
-
- if list, err := c.App.GetPosts(id, offset, limit); err != nil {
- c.Err = err
- return
- } else {
- w.Header().Set(model.HEADER_ETAG_SERVER, etag)
- w.Write([]byte(list.ToJson()))
- }
-
-}
-
-func getPostsSince(c *Context, w http.ResponseWriter, r *http.Request) {
- params := mux.Vars(r)
-
- id := params["channel_id"]
- if len(id) != 26 {
- c.SetInvalidParam("getPostsSince", "channelId")
- return
- }
-
- time, err := strconv.ParseInt(params["time"], 10, 64)
- if err != nil {
- c.SetInvalidParam("getPostsSince", "time")
- return
- }
-
- if !c.App.SessionHasPermissionToChannel(c.Session, id, model.PERMISSION_READ_CHANNEL) {
- c.SetPermissionError(model.PERMISSION_READ_CHANNEL)
- return
- }
-
- if list, err := c.App.GetPostsSince(id, time); err != nil {
- c.Err = err
- return
- } else {
- w.Write([]byte(list.ToJson()))
- }
-
-}
-
-func getPost(c *Context, w http.ResponseWriter, r *http.Request) {
- params := mux.Vars(r)
-
- channelId := params["channel_id"]
- if len(channelId) != 26 {
- c.SetInvalidParam("getPost", "channelId")
- return
- }
-
- postId := params["post_id"]
- if len(postId) != 26 {
- c.SetInvalidParam("getPost", "postId")
- return
- }
-
- if !c.App.SessionHasPermissionToChannel(c.Session, channelId, model.PERMISSION_READ_CHANNEL) {
- c.SetPermissionError(model.PERMISSION_READ_CHANNEL)
- return
- }
-
- if list, err := c.App.GetPostThread(postId); err != nil {
- c.Err = err
- return
- } else if c.HandleEtag(list.Etag(), "Get Post", w, r) {
- return
- } else {
- if !list.IsChannelId(channelId) {
- c.Err = model.NewAppError("getPost", "api.post.get_post.permissions.app_error", nil, "", http.StatusForbidden)
- return
- }
-
- w.Header().Set(model.HEADER_ETAG_SERVER, list.Etag())
- w.Write([]byte(list.ToJson()))
- }
-}
-
-func getPostById(c *Context, w http.ResponseWriter, r *http.Request) {
- params := mux.Vars(r)
-
- postId := params["post_id"]
- if len(postId) != 26 {
- c.SetInvalidParam("getPostById", "postId")
- return
- }
-
- if list, err := c.App.GetPostThread(postId); err != nil {
- c.Err = err
- return
- } else {
- if len(list.Order) != 1 {
- c.Err = model.NewAppError("getPostById", "api.post_get_post_by_id.get.app_error", nil, "", http.StatusInternalServerError)
- return
- }
- post := list.Posts[list.Order[0]]
-
- if !c.App.SessionHasPermissionToChannel(c.Session, post.ChannelId, model.PERMISSION_READ_CHANNEL) {
- c.SetPermissionError(model.PERMISSION_READ_CHANNEL)
- return
- }
-
- if c.HandleEtag(list.Etag(), "Get Post By Id", w, r) {
- return
- }
-
- w.Header().Set(model.HEADER_ETAG_SERVER, list.Etag())
- w.Write([]byte(list.ToJson()))
- }
-}
-
-func getPermalinkTmp(c *Context, w http.ResponseWriter, r *http.Request) {
- params := mux.Vars(r)
-
- postId := params["post_id"]
- if len(postId) != 26 {
- c.SetInvalidParam("getPermalinkTmp", "postId")
- return
- }
-
- var channel *model.Channel
- if result := <-c.App.Srv.Store.Channel().GetForPost(postId); result.Err == nil {
- channel = result.Data.(*model.Channel)
- } else {
- c.SetInvalidParam("getPermalinkTmp", "postId")
- return
- }
-
- if channel.Type == model.CHANNEL_OPEN {
- if !c.App.HasPermissionToChannelByPost(c.Session.UserId, postId, model.PERMISSION_JOIN_PUBLIC_CHANNELS) {
- c.SetPermissionError(model.PERMISSION_JOIN_PUBLIC_CHANNELS)
- return
- }
- } else {
- if !c.App.HasPermissionToChannelByPost(c.Session.UserId, postId, model.PERMISSION_READ_CHANNEL) {
- c.SetPermissionError(model.PERMISSION_READ_CHANNEL)
- return
- }
- }
-
- if list, err := c.App.GetPermalinkPost(postId, c.Session.UserId); err != nil {
- c.Err = err
- return
- } else if c.HandleEtag(list.Etag(), "Get Permalink TMP", w, r) {
- return
- } else {
- w.Header().Set(model.HEADER_ETAG_SERVER, list.Etag())
- w.Write([]byte(list.ToJson()))
- }
-}
-
-func deletePost(c *Context, w http.ResponseWriter, r *http.Request) {
- params := mux.Vars(r)
-
- channelId := params["channel_id"]
- if len(channelId) != 26 {
- c.SetInvalidParam("deletePost", "channelId")
- return
- }
-
- postId := params["post_id"]
- if len(postId) != 26 {
- c.SetInvalidParam("deletePost", "postId")
- return
- }
-
- if !c.App.SessionHasPermissionToChannel(c.Session, channelId, model.PERMISSION_DELETE_POST) {
- c.SetPermissionError(model.PERMISSION_DELETE_POST)
- return
- }
-
- if !c.App.SessionHasPermissionToPost(c.Session, postId, model.PERMISSION_DELETE_OTHERS_POSTS) {
- c.SetPermissionError(model.PERMISSION_DELETE_OTHERS_POSTS)
- return
- }
-
- if post, err := c.App.DeletePost(postId); err != nil {
- c.Err = err
- return
- } else {
- if post.ChannelId != channelId {
- c.Err = model.NewAppError("deletePost", "api.post.delete_post.permissions.app_error", nil, "", http.StatusForbidden)
- return
- }
-
- result := make(map[string]string)
- result["id"] = postId
- w.Write([]byte(model.MapToJson(result)))
- }
-}
-
-func getPostsBefore(c *Context, w http.ResponseWriter, r *http.Request) {
- getPostsBeforeOrAfter(c, w, r, true)
-}
-
-func getPostsAfter(c *Context, w http.ResponseWriter, r *http.Request) {
- getPostsBeforeOrAfter(c, w, r, false)
-}
-
-func getPostsBeforeOrAfter(c *Context, w http.ResponseWriter, r *http.Request, before bool) {
- params := mux.Vars(r)
-
- id := params["channel_id"]
- if len(id) != 26 {
- c.SetInvalidParam("getPostsBeforeOrAfter", "channelId")
- return
- }
-
- postId := params["post_id"]
- if len(postId) != 26 {
- c.SetInvalidParam("getPostsBeforeOrAfter", "postId")
- return
- }
-
- numPosts, err := strconv.Atoi(params["num_posts"])
- if err != nil || numPosts <= 0 {
- c.SetInvalidParam("getPostsBeforeOrAfter", "numPosts")
- return
- }
-
- offset, err := strconv.Atoi(params["offset"])
- if err != nil || offset < 0 {
- c.SetInvalidParam("getPostsBeforeOrAfter", "offset")
- return
- }
-
- if !c.App.SessionHasPermissionToChannel(c.Session, id, model.PERMISSION_READ_CHANNEL) {
- c.SetPermissionError(model.PERMISSION_READ_CHANNEL)
- return
- }
-
- // We can do better than this etag in this situation
- etag := c.App.GetPostsEtag(id)
-
- if c.HandleEtag(etag, "Get Posts Before or After", w, r) {
- return
- }
-
- if list, err := c.App.GetPostsAroundPost(postId, id, offset, numPosts, before); err != nil {
- c.Err = err
- return
- } else {
- w.Header().Set(model.HEADER_ETAG_SERVER, etag)
- w.Write([]byte(list.ToJson()))
- }
-}
-
-func searchPosts(c *Context, w http.ResponseWriter, r *http.Request) {
- props := model.StringInterfaceFromJson(r.Body)
-
- terms := props["terms"].(string)
- if len(terms) == 0 {
- c.SetInvalidParam("search", "terms")
- return
- }
-
- isOrSearch := false
- if val, ok := props["is_or_search"]; ok && val != nil {
- isOrSearch = val.(bool)
- }
-
- startTime := time.Now()
-
- posts, err := c.App.SearchPostsInTeam(terms, c.Session.UserId, c.TeamId, isOrSearch)
-
- elapsedTime := float64(time.Since(startTime)) / float64(time.Second)
- metrics := c.App.Metrics
- if metrics != nil {
- metrics.IncrementPostsSearchCounter()
- metrics.ObservePostsSearchDuration(elapsedTime)
- }
-
- if err != nil {
- c.Err = err
- return
- }
-
- w.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate")
- w.Write([]byte(posts.ToJson()))
-}
-
-func getFileInfosForPost(c *Context, w http.ResponseWriter, r *http.Request) {
- params := mux.Vars(r)
-
- channelId := params["channel_id"]
- if len(channelId) != 26 {
- c.SetInvalidParam("getFileInfosForPost", "channelId")
- return
- }
-
- postId := params["post_id"]
- if len(postId) != 26 {
- c.SetInvalidParam("getFileInfosForPost", "postId")
- return
- }
-
- if !c.App.SessionHasPermissionToChannel(c.Session, channelId, model.PERMISSION_READ_CHANNEL) {
- c.SetPermissionError(model.PERMISSION_READ_CHANNEL)
- return
- }
-
- if infos, err := c.App.GetFileInfosForPost(postId, false); err != nil {
- c.Err = err
- return
- } else if c.HandleEtag(model.GetEtagForFileInfos(infos), "Get File Infos For Post", w, r) {
- return
- } else {
- if len(infos) > 0 {
- w.Header().Set("Cache-Control", "max-age=2592000, public")
- }
-
- w.Header().Set(model.HEADER_ETAG_SERVER, model.GetEtagForFileInfos(infos))
- w.Write([]byte(model.FileInfosToJson(infos)))
- }
-}
-
-func getOpenGraphMetadata(c *Context, w http.ResponseWriter, r *http.Request) {
- if !*c.App.Config().ServiceSettings.EnableLinkPreviews {
- c.Err = model.NewAppError("getOpenGraphMetadata", "api.post.link_preview_disabled.app_error", nil, "", http.StatusNotImplemented)
- return
- }
-
- props := model.StringInterfaceFromJson(r.Body)
-
- ogJSONGeneric, ok := openGraphDataCache.Get(props["url"])
- if ok {
- w.Write(ogJSONGeneric.([]byte))
- return
- }
-
- url := ""
- ok = false
- if url, ok = props["url"].(string); len(url) == 0 || !ok {
- c.SetInvalidParam("getOpenGraphMetadata", "url")
- return
- }
-
- og := c.App.GetOpenGraphMetadata(url)
-
- ogJSON, err := og.ToJSON()
- openGraphDataCache.AddWithExpiresInSecs(props["url"], ogJSON, 3600) // Cache would expire after 1 hour
- if err != nil {
- w.Write([]byte(`{"url": ""}`))
- return
- }
-
- w.Write(ogJSON)
-}
diff --git a/api/post_test.go b/api/post_test.go
deleted file mode 100644
index 7a2367312..000000000
--- a/api/post_test.go
+++ /dev/null
@@ -1,1510 +0,0 @@
-// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-package api
-
-import (
- "encoding/json"
- "fmt"
- "net/http"
- "net/http/httptest"
- "net/url"
- "reflect"
- "strings"
-
- "testing"
- "time"
-
- "github.com/mattermost/mattermost-server/app"
- "github.com/mattermost/mattermost-server/model"
- "github.com/mattermost/mattermost-server/store"
- "github.com/mattermost/mattermost-server/utils"
-)
-
-func TestCreatePost(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- Client := th.BasicClient
- team := th.BasicTeam
- team2 := th.CreateTeam(th.BasicClient)
- user3 := th.CreateUser(th.BasicClient)
- th.LinkUserToTeam(user3, team2)
- channel1 := th.BasicChannel
- channel2 := th.CreateChannel(Client, team)
-
- th.InitSystemAdmin()
- AdminClient := th.SystemAdminClient
- adminTeam := th.SystemAdminTeam
- adminUser := th.CreateUser(th.SystemAdminClient)
- th.LinkUserToTeam(adminUser, adminTeam)
-
- post1 := &model.Post{ChannelId: channel1.Id, Message: "#hashtag a" + model.NewId() + "a", Props: model.StringInterface{model.PROPS_ADD_CHANNEL_MEMBER: "no good"}}
- rpost1, err := Client.CreatePost(post1)
- if err != nil {
- t.Fatal(err)
- }
-
- if rpost1.Data.(*model.Post).Message != post1.Message {
- t.Fatal("message didn't match")
- }
-
- if rpost1.Data.(*model.Post).Hashtags != "#hashtag" {
- t.Fatal("hashtag didn't match")
- }
-
- if len(rpost1.Data.(*model.Post).FileIds) != 0 {
- t.Fatal("shouldn't have files")
- }
-
- if rpost1.Data.(*model.Post).EditAt != 0 {
- t.Fatal("Newly craeted post shouldn't have EditAt set")
- }
-
- if rpost1.Data.(*model.Post).Props[model.PROPS_ADD_CHANNEL_MEMBER] != nil {
- t.Fatal("newly created post shouldn't have Props['add_channel_member'] set")
- }
-
- _, err = Client.CreatePost(&model.Post{ChannelId: channel1.Id, Message: "#hashtag a" + model.NewId() + "a", Type: model.POST_SYSTEM_GENERIC})
- if err == nil {
- t.Fatal("should have failed - bad post type")
- }
-
- post2 := &model.Post{ChannelId: channel1.Id, Message: "zz" + model.NewId() + "a", RootId: rpost1.Data.(*model.Post).Id}
- rpost2, err := Client.CreatePost(post2)
- if err != nil {
- t.Fatal(err)
- }
-
- post3 := &model.Post{ChannelId: channel1.Id, Message: "zz" + model.NewId() + "a", RootId: rpost1.Data.(*model.Post).Id, ParentId: rpost2.Data.(*model.Post).Id}
- _, err = Client.CreatePost(post3)
- if err != nil {
- t.Fatal(err)
- }
-
- post4 := &model.Post{ChannelId: channel1.Id, Message: "zz" + model.NewId() + "a", RootId: "junk"}
- _, err = Client.CreatePost(post4)
- if err.StatusCode != http.StatusBadRequest {
- t.Fatal("Should have been invalid param")
- }
-
- post5 := &model.Post{ChannelId: channel1.Id, Message: "zz" + model.NewId() + "a", RootId: rpost1.Data.(*model.Post).Id, ParentId: "junk"}
- _, err = Client.CreatePost(post5)
- if err.StatusCode != http.StatusBadRequest {
- t.Fatal("Should have been invalid param")
- }
-
- post1c2 := &model.Post{ChannelId: channel2.Id, Message: "zz" + model.NewId() + "a"}
- rpost1c2, err := Client.CreatePost(post1c2)
-
- post2c2 := &model.Post{ChannelId: channel1.Id, Message: "zz" + model.NewId() + "a", RootId: rpost1c2.Data.(*model.Post).Id}
- _, err = Client.CreatePost(post2c2)
- if err.StatusCode != http.StatusBadRequest {
- t.Fatal("Should have been invalid param")
- }
-
- post6 := &model.Post{ChannelId: "junk", Message: "zz" + model.NewId() + "a"}
- _, err = Client.CreatePost(post6)
- if err.StatusCode != http.StatusForbidden {
- t.Fatal("Should have been forbidden")
- }
-
- th.LoginBasic2()
-
- post7 := &model.Post{ChannelId: channel1.Id, Message: "zz" + model.NewId() + "a"}
- _, err = Client.CreatePost(post7)
- if err.StatusCode != http.StatusForbidden {
- t.Fatal("Should have been forbidden")
- }
-
- Client.Login(user3.Email, user3.Password)
- Client.SetTeamId(team2.Id)
- channel3 := th.CreateChannel(Client, team2)
-
- post8 := &model.Post{ChannelId: channel1.Id, Message: "zz" + model.NewId() + "a"}
- _, err = Client.CreatePost(post8)
- if err.StatusCode != http.StatusForbidden {
- t.Fatal("Should have been forbidden")
- }
-
- if _, err = Client.DoApiPost("/channels/"+channel3.Id+"/create", "garbage"); err == nil {
- t.Fatal("should have been an error")
- }
-
- fileIds := make([]string, 4)
- if data, err := readTestFile("test.png"); err != nil {
- t.Fatal(err)
- } else {
- for i := 0; i < 3; i++ {
- fileIds[i] = Client.MustGeneric(Client.UploadPostAttachment(data, channel3.Id, "test.png")).(*model.FileUploadResponse).FileInfos[0].Id
- }
- }
-
- // Make sure duplicated file ids are removed
- fileIds[3] = fileIds[0]
-
- post9 := &model.Post{
- ChannelId: channel3.Id,
- Message: "test",
- FileIds: fileIds,
- }
- if resp, err := Client.CreatePost(post9); err != nil {
- t.Fatal(err)
- } else if rpost9 := resp.Data.(*model.Post); len(rpost9.FileIds) != 3 {
- t.Fatal("post should have 3 files")
- } else {
- infos := store.Must(th.App.Srv.Store.FileInfo().GetForPost(rpost9.Id, true, true)).([]*model.FileInfo)
-
- if len(infos) != 3 {
- t.Fatal("should've attached all 3 files to post")
- }
- }
-
- th.App.UpdateConfig(func(cfg *model.Config) { *cfg.TeamSettings.ExperimentalTownSquareIsReadOnly = true })
- th.App.SetLicense(model.NewTestLicense())
-
- defaultChannel := store.Must(th.App.Srv.Store.Channel().GetByName(team.Id, model.DEFAULT_CHANNEL, true)).(*model.Channel)
- defaultPost := &model.Post{
- ChannelId: defaultChannel.Id,
- Message: "Default Channel Post",
- }
- if _, err = Client.CreatePost(defaultPost); err == nil {
- t.Fatal("should have failed -- ExperimentalTownSquareIsReadOnly is true and it's a read only channel")
- }
-
- adminDefaultChannel := store.Must(th.App.Srv.Store.Channel().GetByName(adminTeam.Id, model.DEFAULT_CHANNEL, true)).(*model.Channel)
- adminDefaultPost := &model.Post{
- ChannelId: adminDefaultChannel.Id,
- Message: "Admin Default Channel Post",
- }
- if _, err = AdminClient.CreatePost(adminDefaultPost); err != nil {
- t.Fatal("should not have failed -- ExperimentalTownSquareIsReadOnly is true and admin can post to channel")
- }
-}
-
-func TestCreatePostWithCreateAt(t *testing.T) {
-
- // An ordinary user cannot use CreateAt
-
- th := Setup().InitBasic()
- defer th.TearDown()
-
- Client := th.BasicClient
- channel1 := th.BasicChannel
-
- post := &model.Post{
- ChannelId: channel1.Id,
- Message: "PLT-4349",
- CreateAt: 1234,
- }
- if resp, err := Client.CreatePost(post); err != nil {
- t.Fatal(err)
- } else if rpost := resp.Data.(*model.Post); rpost.CreateAt == post.CreateAt {
- t.Fatal("post should be created with default CreateAt timestamp for ordinary user")
- }
-
- // But a System Admin user can
-
- th.InitSystemAdmin()
- SysClient := th.SystemAdminClient
-
- if resp, err := SysClient.CreatePost(post); err != nil {
- t.Fatal(err)
- } else if rpost := resp.Data.(*model.Post); rpost.CreateAt != post.CreateAt {
- t.Fatal("post should be created with provided CreateAt timestamp for System Admin user")
- }
-}
-
-func testCreatePostWithOutgoingHook(
- t *testing.T,
- hookContentType, expectedContentType, message, triggerWord string,
- fileIds []string,
- triggerWhen int,
-) {
- th := Setup().InitSystemAdmin()
- defer th.TearDown()
-
- Client := th.SystemAdminClient
- team := th.SystemAdminTeam
- user := th.SystemAdminUser
- channel := th.CreateChannel(Client, team)
-
- th.App.UpdateConfig(func(cfg *model.Config) {
- cfg.ServiceSettings.EnableOutgoingWebhooks = true
- *cfg.ServiceSettings.AllowedUntrustedInternalConnections = "localhost 127.0.0.1"
- })
-
- var hook *model.OutgoingWebhook
- var post *model.Post
-
- // Create a test server that is the target of the outgoing webhook. It will
- // validate the webhook body fields and write to the success channel on
- // success/failure.
- success := make(chan bool)
- wait := make(chan bool, 1)
- ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- <-wait
-
- requestContentType := r.Header.Get("Content-Type")
- if requestContentType != expectedContentType {
- t.Logf("Content-Type is %s, should be %s", requestContentType, expectedContentType)
- success <- false
- return
- }
-
- expectedPayload := &model.OutgoingWebhookPayload{
- Token: hook.Token,
- TeamId: hook.TeamId,
- TeamDomain: team.Name,
- ChannelId: post.ChannelId,
- ChannelName: channel.Name,
- Timestamp: post.CreateAt,
- UserId: post.UserId,
- UserName: user.Username,
- PostId: post.Id,
- Text: post.Message,
- TriggerWord: triggerWord,
- FileIds: strings.Join(post.FileIds, ","),
- }
-
- // depending on the Content-Type, we expect to find a JSON or form encoded payload
- if requestContentType == "application/json" {
- decoder := json.NewDecoder(r.Body)
- o := &model.OutgoingWebhookPayload{}
- decoder.Decode(&o)
-
- if !reflect.DeepEqual(expectedPayload, o) {
- t.Logf("JSON payload is %+v, should be %+v", o, expectedPayload)
- success <- false
- return
- }
- } else {
- err := r.ParseForm()
- if err != nil {
- t.Logf("Error parsing form: %q", err)
- success <- false
- return
- }
-
- expectedFormValues, _ := url.ParseQuery(expectedPayload.ToFormValues())
- if !reflect.DeepEqual(expectedFormValues, r.Form) {
- t.Logf("Form values are %q, should be %q", r.Form, expectedFormValues)
- success <- false
- return
- }
- }
-
- resp := &model.OutgoingWebhookResponse{}
- resp.Text = model.NewString("some test text")
- resp.Username = "testusername"
- resp.IconURL = "http://www.mattermost.org/wp-content/uploads/2016/04/icon.png"
- resp.Props = map[string]interface{}{"someprop": "somevalue"}
- resp.Type = "custom_test"
-
- w.Write([]byte(resp.ToJson()))
-
- success <- true
- }))
- defer ts.Close()
-
- // create an outgoing webhook, passing it the test server URL
- var triggerWords []string
- if triggerWord != "" {
- triggerWords = []string{triggerWord}
- }
-
- hook = &model.OutgoingWebhook{
- ChannelId: channel.Id,
- TeamId: team.Id,
- ContentType: hookContentType,
- TriggerWords: triggerWords,
- TriggerWhen: triggerWhen,
- CallbackURLs: []string{ts.URL},
- }
-
- if result, err := Client.CreateOutgoingWebhook(hook); err != nil {
- t.Fatal(err)
- } else {
- hook = result.Data.(*model.OutgoingWebhook)
- }
-
- // create a post to trigger the webhook
- post = &model.Post{
- ChannelId: channel.Id,
- Message: message,
- FileIds: fileIds,
- }
-
- if result, err := Client.CreatePost(post); err != nil {
- t.Fatal(err)
- } else {
- post = result.Data.(*model.Post)
- }
-
- wait <- true
-
- // We wait for the test server to write to the success channel and we make
- // the test fail if that doesn't happen before the timeout.
- select {
- case ok := <-success:
- if !ok {
- t.Fatal("Test server did send an invalid webhook.")
- }
- case <-time.After(time.Second):
- t.Fatal("Timeout, test server did not send the webhook.")
- }
-}
-
-func TestCreatePostWithOutgoingHook_form_urlencoded(t *testing.T) {
- testCreatePostWithOutgoingHook(t, "application/x-www-form-urlencoded", "application/x-www-form-urlencoded", "triggerword lorem ipsum", "triggerword", []string{"file_id_1"}, app.TRIGGERWORDS_EXACT_MATCH)
- testCreatePostWithOutgoingHook(t, "application/x-www-form-urlencoded", "application/x-www-form-urlencoded", "triggerwordaaazzz lorem ipsum", "triggerword", []string{"file_id_1"}, app.TRIGGERWORDS_STARTS_WITH)
- testCreatePostWithOutgoingHook(t, "application/x-www-form-urlencoded", "application/x-www-form-urlencoded", "", "", []string{"file_id_1"}, app.TRIGGERWORDS_EXACT_MATCH)
- testCreatePostWithOutgoingHook(t, "application/x-www-form-urlencoded", "application/x-www-form-urlencoded", "", "", []string{"file_id_1"}, app.TRIGGERWORDS_STARTS_WITH)
-}
-
-func TestCreatePostWithOutgoingHook_json(t *testing.T) {
- testCreatePostWithOutgoingHook(t, "application/json", "application/json", "triggerword lorem ipsum", "triggerword", []string{"file_id_1, file_id_2"}, app.TRIGGERWORDS_EXACT_MATCH)
- testCreatePostWithOutgoingHook(t, "application/json", "application/json", "triggerwordaaazzz lorem ipsum", "triggerword", []string{"file_id_1, file_id_2"}, app.TRIGGERWORDS_STARTS_WITH)
- testCreatePostWithOutgoingHook(t, "application/json", "application/json", "triggerword lorem ipsum", "", []string{"file_id_1"}, app.TRIGGERWORDS_EXACT_MATCH)
- testCreatePostWithOutgoingHook(t, "application/json", "application/json", "triggerwordaaazzz lorem ipsum", "", []string{"file_id_1"}, app.TRIGGERWORDS_STARTS_WITH)
-}
-
-// hooks created before we added the ContentType field should be considered as
-// application/x-www-form-urlencoded
-func TestCreatePostWithOutgoingHook_no_content_type(t *testing.T) {
- testCreatePostWithOutgoingHook(t, "", "application/x-www-form-urlencoded", "triggerword lorem ipsum", "triggerword", []string{"file_id_1"}, app.TRIGGERWORDS_EXACT_MATCH)
- testCreatePostWithOutgoingHook(t, "", "application/x-www-form-urlencoded", "triggerwordaaazzz lorem ipsum", "triggerword", []string{"file_id_1"}, app.TRIGGERWORDS_STARTS_WITH)
- testCreatePostWithOutgoingHook(t, "", "application/x-www-form-urlencoded", "triggerword lorem ipsum", "", []string{"file_id_1, file_id_2"}, app.TRIGGERWORDS_EXACT_MATCH)
- testCreatePostWithOutgoingHook(t, "", "application/x-www-form-urlencoded", "triggerwordaaazzz lorem ipsum", "", []string{"file_id_1, file_id_2"}, app.TRIGGERWORDS_STARTS_WITH)
-}
-
-func TestUpdatePost(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- Client := th.BasicClient
- channel1 := th.BasicChannel
-
- // Check the appropriate permissions are enforced.
- defaultRolePermissions := th.SaveDefaultRolePermissions()
- defer func() {
- th.RestoreDefaultRolePermissions(defaultRolePermissions)
- }()
- th.App.SetLicense(model.NewTestLicense())
-
- th.AddPermissionToRole(model.PERMISSION_EDIT_POST.Id, model.CHANNEL_USER_ROLE_ID)
-
- post1 := &model.Post{ChannelId: channel1.Id, Message: "zz" + model.NewId() + "a"}
- rpost1, err := Client.CreatePost(post1)
- if err != nil {
- t.Fatal(err)
- }
-
- if rpost1.Data.(*model.Post).Message != post1.Message {
- t.Fatal("full name didn't match")
- }
-
- post2 := &model.Post{ChannelId: channel1.Id, Message: "zz" + model.NewId() + "a", RootId: rpost1.Data.(*model.Post).Id}
- rpost2, err := Client.CreatePost(post2)
- if err != nil {
- t.Fatal(err)
- }
-
- if rpost2.Data.(*model.Post).EditAt != 0 {
- t.Fatal("Newly craeted post shouldn't have EditAt set")
- }
-
- msg2 := "zz" + model.NewId() + " update post 1"
- rpost2.Data.(*model.Post).Message = msg2
- rpost2.Data.(*model.Post).Props[model.PROPS_ADD_CHANNEL_MEMBER] = "no good"
- if rupost2, err := Client.UpdatePost(rpost2.Data.(*model.Post)); err != nil {
- t.Fatal(err)
- } else {
- if rupost2.Data.(*model.Post).Message != msg2 {
- t.Fatal("failed to updates")
- }
- if rupost2.Data.(*model.Post).EditAt == 0 {
- t.Fatal("EditAt not updated for post")
- }
- if rupost2.Data.(*model.Post).Props[model.PROPS_ADD_CHANNEL_MEMBER] != nil {
- t.Fatal("failed to sanitize Props['add_channel_member'], should be nil")
- }
- }
-
- msg1 := "#hashtag a" + model.NewId() + " update post 2"
- rpost1.Data.(*model.Post).Message = msg1
- if rupost1, err := Client.UpdatePost(rpost1.Data.(*model.Post)); err != nil {
- t.Fatal(err)
- } else {
- if rupost1.Data.(*model.Post).Message != msg1 && rupost1.Data.(*model.Post).Hashtags != "#hashtag" {
- t.Fatal("failed to updates")
- }
- }
-
- up12 := &model.Post{Id: rpost1.Data.(*model.Post).Id, ChannelId: channel1.Id, Message: "zz" + model.NewId() + " updaet post 1 update 2"}
- if rup12, err := Client.UpdatePost(up12); err != nil {
- t.Fatal(err)
- } else {
- if rup12.Data.(*model.Post).Message != up12.Message {
- t.Fatal("failed to updates")
- }
- }
-
- rpost3, err := th.App.CreatePost(&model.Post{ChannelId: channel1.Id, Message: "zz" + model.NewId() + "a", Type: model.POST_JOIN_LEAVE, UserId: th.BasicUser.Id}, channel1, false)
- if err != nil {
- t.Fatal(err)
- }
-
- up3 := &model.Post{Id: rpost3.Id, ChannelId: channel1.Id, Message: "zz" + model.NewId() + " update post 3"}
- if _, err := Client.UpdatePost(up3); err == nil {
- t.Fatal("shouldn't have been able to update system message")
- }
-
- // Test licensed policy controls for edit post
- th.RemovePermissionFromRole(model.PERMISSION_EDIT_POST.Id, model.CHANNEL_USER_ROLE_ID)
-
- post4 := &model.Post{ChannelId: channel1.Id, Message: "zz" + model.NewId() + "a", RootId: rpost1.Data.(*model.Post).Id}
- rpost4, err := Client.CreatePost(post4)
- if err != nil {
- t.Fatal(err)
- }
-
- up4 := &model.Post{Id: rpost4.Data.(*model.Post).Id, ChannelId: channel1.Id, Message: "zz" + model.NewId() + " update post 4"}
- if _, err := Client.UpdatePost(up4); err == nil {
- t.Fatal("shouldn't have been able to update a message when not allowed")
- }
-
- th.AddPermissionToRole(model.PERMISSION_EDIT_POST.Id, model.CHANNEL_USER_ROLE_ID)
- th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.PostEditTimeLimit = 1 }) //seconds
-
- post5 := &model.Post{ChannelId: channel1.Id, Message: "zz" + model.NewId() + "a", RootId: rpost1.Data.(*model.Post).Id}
- rpost5, err := Client.CreatePost(post5)
- if err != nil {
- t.Fatal(err)
- }
-
- msg5 := "zz" + model.NewId() + " update post 5"
- up5 := &model.Post{Id: rpost5.Data.(*model.Post).Id, ChannelId: channel1.Id, Message: msg5}
- if rup5, err := Client.UpdatePost(up5); err != nil {
- t.Fatal(err)
- } else {
- if rup5.Data.(*model.Post).Message != up5.Message {
- t.Fatal("failed to updates")
- }
- }
-
- time.Sleep(1000 * time.Millisecond)
-
- up6 := &model.Post{Id: rpost5.Data.(*model.Post).Id, ChannelId: channel1.Id, Message: "zz" + model.NewId() + " update post 5"}
- if _, err := Client.UpdatePost(up6); err == nil {
- t.Fatal("shouldn't have been able to update a message after time limit")
- }
-}
-
-func TestGetPosts(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- Client := th.BasicClient
- channel1 := th.BasicChannel
-
- time.Sleep(10 * time.Millisecond)
- post1 := &model.Post{ChannelId: channel1.Id, Message: "zz" + model.NewId() + "a"}
- post1 = Client.Must(Client.CreatePost(post1)).Data.(*model.Post)
-
- time.Sleep(10 * time.Millisecond)
- post1a1 := &model.Post{ChannelId: channel1.Id, Message: "zz" + model.NewId() + "a", RootId: post1.Id}
- post1a1 = Client.Must(Client.CreatePost(post1a1)).Data.(*model.Post)
-
- time.Sleep(10 * time.Millisecond)
- post2 := &model.Post{ChannelId: channel1.Id, Message: "zz" + model.NewId() + "a"}
- post2 = Client.Must(Client.CreatePost(post2)).Data.(*model.Post)
-
- time.Sleep(10 * time.Millisecond)
- post3 := &model.Post{ChannelId: channel1.Id, Message: "zz" + model.NewId() + "a"}
- post3 = Client.Must(Client.CreatePost(post3)).Data.(*model.Post)
-
- time.Sleep(10 * time.Millisecond)
- post3a1 := &model.Post{ChannelId: channel1.Id, Message: "zz" + model.NewId() + "a", RootId: post3.Id}
- post3a1 = Client.Must(Client.CreatePost(post3a1)).Data.(*model.Post)
-
- r1 := Client.Must(Client.GetPosts(channel1.Id, 0, 2, "")).Data.(*model.PostList)
-
- if r1.Order[0] != post3a1.Id {
- t.Fatal("wrong order")
- }
-
- if r1.Order[1] != post3.Id {
- t.Fatal("wrong order")
- }
-
- if len(r1.Posts) != 2 { // 3a1 and 3; 3a1's parent already there
- t.Fatal("wrong size")
- }
-
- r2 := Client.Must(Client.GetPosts(channel1.Id, 2, 2, "")).Data.(*model.PostList)
-
- if r2.Order[0] != post2.Id {
- t.Fatal("wrong order")
- }
-
- if r2.Order[1] != post1a1.Id {
- t.Fatal("wrong order")
- }
-
- if len(r2.Posts) != 3 { // 2 and 1a1; + 1a1's parent
- t.Log(r2.Posts)
- t.Fatal("wrong size")
- }
-}
-
-func TestGetPostsSince(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- Client := th.BasicClient
- channel1 := th.BasicChannel
-
- time.Sleep(10 * time.Millisecond)
- post0 := &model.Post{ChannelId: channel1.Id, Message: "zz" + model.NewId() + "a"}
- post0 = Client.Must(Client.CreatePost(post0)).Data.(*model.Post)
-
- time.Sleep(10 * time.Millisecond)
- post1 := &model.Post{ChannelId: channel1.Id, Message: "zz" + model.NewId() + "a"}
- post1 = Client.Must(Client.CreatePost(post1)).Data.(*model.Post)
-
- time.Sleep(10 * time.Millisecond)
- post1a1 := &model.Post{ChannelId: channel1.Id, Message: "zz" + model.NewId() + "a", RootId: post1.Id}
- post1a1 = Client.Must(Client.CreatePost(post1a1)).Data.(*model.Post)
-
- time.Sleep(10 * time.Millisecond)
- post2 := &model.Post{ChannelId: channel1.Id, Message: "zz" + model.NewId() + "a"}
- post2 = Client.Must(Client.CreatePost(post2)).Data.(*model.Post)
-
- time.Sleep(10 * time.Millisecond)
- post3 := &model.Post{ChannelId: channel1.Id, Message: "zz" + model.NewId() + "a"}
- post3 = Client.Must(Client.CreatePost(post3)).Data.(*model.Post)
-
- time.Sleep(10 * time.Millisecond)
- post3a1 := &model.Post{ChannelId: channel1.Id, Message: "zz" + model.NewId() + "a", RootId: post3.Id}
- post3a1 = Client.Must(Client.CreatePost(post3a1)).Data.(*model.Post)
-
- r1 := Client.Must(Client.GetPostsSince(channel1.Id, post1.CreateAt)).Data.(*model.PostList)
-
- if r1.Order[0] != post3a1.Id {
- t.Fatal("wrong order")
- }
-
- if r1.Order[1] != post3.Id {
- t.Fatal("wrong order")
- }
-
- if len(r1.Posts) != 5 {
- t.Fatal("wrong size")
- }
-
- now := model.GetMillis()
- r2 := Client.Must(Client.GetPostsSince(channel1.Id, now)).Data.(*model.PostList)
-
- if len(r2.Posts) != 0 {
- t.Fatal("should have been empty")
- }
-
- post2.Message = "new message"
- Client.Must(Client.UpdatePost(post2))
-
- r3 := Client.Must(Client.GetPostsSince(channel1.Id, now)).Data.(*model.PostList)
-
- if len(r3.Order) != 2 { // 2 because deleted post is returned as well
- t.Fatal("missing post update")
- }
-}
-
-func TestGetPostsBeforeAfter(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- Client := th.BasicClient
- channel1 := th.BasicChannel
-
- time.Sleep(10 * time.Millisecond)
- post0 := &model.Post{ChannelId: channel1.Id, Message: "zz" + model.NewId() + "a"}
- post0 = Client.Must(Client.CreatePost(post0)).Data.(*model.Post)
-
- time.Sleep(10 * time.Millisecond)
- post1 := &model.Post{ChannelId: channel1.Id, Message: "zz" + model.NewId() + "a"}
- post1 = Client.Must(Client.CreatePost(post1)).Data.(*model.Post)
-
- time.Sleep(10 * time.Millisecond)
- post1a1 := &model.Post{ChannelId: channel1.Id, Message: "zz" + model.NewId() + "a", RootId: post1.Id}
- post1a1 = Client.Must(Client.CreatePost(post1a1)).Data.(*model.Post)
-
- time.Sleep(10 * time.Millisecond)
- post2 := &model.Post{ChannelId: channel1.Id, Message: "zz" + model.NewId() + "a"}
- post2 = Client.Must(Client.CreatePost(post2)).Data.(*model.Post)
-
- time.Sleep(10 * time.Millisecond)
- post3 := &model.Post{ChannelId: channel1.Id, Message: "zz" + model.NewId() + "a"}
- post3 = Client.Must(Client.CreatePost(post3)).Data.(*model.Post)
-
- time.Sleep(10 * time.Millisecond)
- post3a1 := &model.Post{ChannelId: channel1.Id, Message: "zz" + model.NewId() + "a", RootId: post3.Id}
- post3a1 = Client.Must(Client.CreatePost(post3a1)).Data.(*model.Post)
-
- r1 := Client.Must(Client.GetPostsBefore(channel1.Id, post1a1.Id, 0, 10, "")).Data.(*model.PostList)
-
- if r1.Order[0] != post1.Id {
- t.Fatal("wrong order")
- }
-
- if r1.Order[1] != post0.Id {
- t.Fatal("wrong order")
- }
-
- // including created post from test helper and system 'joined' message
- if len(r1.Posts) != 4 {
- t.Fatal("wrong size")
- }
-
- r2 := Client.Must(Client.GetPostsAfter(channel1.Id, post3a1.Id, 0, 3, "")).Data.(*model.PostList)
-
- if len(r2.Posts) != 0 {
- t.Fatal("should have been empty")
- }
-
- post2.Message = "new message"
- Client.Must(Client.UpdatePost(post2))
-
- r3 := Client.Must(Client.GetPostsAfter(channel1.Id, post1a1.Id, 0, 2, "")).Data.(*model.PostList)
-
- if r3.Order[0] != post3.Id {
- t.Fatal("wrong order")
- }
-
- if r3.Order[1] != post2.Id {
- t.Fatal("wrong order")
- }
-
- if len(r3.Order) != 2 {
- t.Fatal("missing post update")
- }
-}
-
-func TestSearchPosts(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- Client := th.BasicClient
- channel1 := th.BasicChannel
-
- post1 := &model.Post{ChannelId: channel1.Id, Message: "search for post1"}
- post1 = Client.Must(Client.CreatePost(post1)).Data.(*model.Post)
-
- post2 := &model.Post{ChannelId: channel1.Id, Message: "search for post2"}
- post2 = Client.Must(Client.CreatePost(post2)).Data.(*model.Post)
-
- post3 := &model.Post{ChannelId: channel1.Id, Message: "#hashtag search for post3"}
- post3 = Client.Must(Client.CreatePost(post3)).Data.(*model.Post)
-
- post4 := &model.Post{ChannelId: channel1.Id, Message: "hashtag for post4"}
- post4 = Client.Must(Client.CreatePost(post4)).Data.(*model.Post)
-
- r1 := Client.Must(Client.SearchPosts("search", false)).Data.(*model.PostList)
-
- if len(r1.Order) != 3 {
- t.Fatal("wrong search")
- }
-
- r2 := Client.Must(Client.SearchPosts("post2", false)).Data.(*model.PostList)
-
- if len(r2.Order) != 1 && r2.Order[0] == post2.Id {
- t.Fatal("wrong search")
- }
-
- r3 := Client.Must(Client.SearchPosts("#hashtag", false)).Data.(*model.PostList)
-
- if len(r3.Order) != 1 && r3.Order[0] == post3.Id {
- t.Fatal("wrong search")
- }
-
- if r4 := Client.Must(Client.SearchPosts("*", false)).Data.(*model.PostList); len(r4.Order) != 0 {
- t.Fatal("searching for just * shouldn't return any results")
- }
-
- r5 := Client.Must(Client.SearchPosts("post1 post2", true)).Data.(*model.PostList)
-
- if len(r5.Order) != 2 {
- t.Fatal("wrong search results")
- }
-}
-
-func TestSearchHashtagPosts(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- Client := th.BasicClient
- channel1 := th.BasicChannel
-
- post1 := &model.Post{ChannelId: channel1.Id, Message: "#sgtitlereview with space"}
- post1 = Client.Must(Client.CreatePost(post1)).Data.(*model.Post)
-
- post2 := &model.Post{ChannelId: channel1.Id, Message: "#sgtitlereview\n with return"}
- post2 = Client.Must(Client.CreatePost(post2)).Data.(*model.Post)
-
- post3 := &model.Post{ChannelId: channel1.Id, Message: "no hashtag"}
- post3 = Client.Must(Client.CreatePost(post3)).Data.(*model.Post)
-
- r1 := Client.Must(Client.SearchPosts("#sgtitlereview", false)).Data.(*model.PostList)
-
- if len(r1.Order) != 2 {
- t.Fatal("wrong search")
- }
-}
-
-func TestSearchPostsInChannel(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- Client := th.BasicClient
- channel1 := th.BasicChannel
- team := th.BasicTeam
-
- post1 := &model.Post{ChannelId: channel1.Id, Message: "sgtitlereview with space"}
- post1 = Client.Must(Client.CreatePost(post1)).Data.(*model.Post)
-
- channel2 := &model.Channel{DisplayName: "TestGetPosts", Name: "zz" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
- channel2 = Client.Must(Client.CreateChannel(channel2)).Data.(*model.Channel)
-
- channel3 := &model.Channel{DisplayName: "TestGetPosts", Name: "zz" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
- channel3 = Client.Must(Client.CreateChannel(channel3)).Data.(*model.Channel)
-
- post2 := &model.Post{ChannelId: channel2.Id, Message: "sgtitlereview\n with return"}
- post2 = Client.Must(Client.CreatePost(post2)).Data.(*model.Post)
-
- post3 := &model.Post{ChannelId: channel2.Id, Message: "other message with no return"}
- post3 = Client.Must(Client.CreatePost(post3)).Data.(*model.Post)
-
- post4 := &model.Post{ChannelId: channel3.Id, Message: "other message with no return"}
- post4 = Client.Must(Client.CreatePost(post4)).Data.(*model.Post)
-
- if result := Client.Must(Client.SearchPosts("channel:", false)).Data.(*model.PostList); len(result.Order) != 0 {
- t.Fatalf("wrong number of posts returned %v", len(result.Order))
- }
-
- if result := Client.Must(Client.SearchPosts("in:", false)).Data.(*model.PostList); len(result.Order) != 0 {
- t.Fatalf("wrong number of posts returned %v", len(result.Order))
- }
-
- if result := Client.Must(Client.SearchPosts("channel:"+channel1.Name, false)).Data.(*model.PostList); len(result.Order) != 2 {
- t.Fatalf("wrong number of posts returned %v", len(result.Order))
- }
-
- if result := Client.Must(Client.SearchPosts("in: "+channel2.Name, false)).Data.(*model.PostList); len(result.Order) != 2 {
- t.Fatalf("wrong number of posts returned %v", len(result.Order))
- }
-
- if result := Client.Must(Client.SearchPosts("channel: "+channel2.Name, false)).Data.(*model.PostList); len(result.Order) != 2 {
- t.Fatalf("wrong number of posts returned %v", len(result.Order))
- }
-
- if result := Client.Must(Client.SearchPosts("ChAnNeL: "+channel2.Name, false)).Data.(*model.PostList); len(result.Order) != 2 {
- t.Fatalf("wrong number of posts returned %v", len(result.Order))
- }
-
- if result := Client.Must(Client.SearchPosts("sgtitlereview", false)).Data.(*model.PostList); len(result.Order) != 2 {
- t.Fatalf("wrong number of posts returned %v", len(result.Order))
- }
-
- if result := Client.Must(Client.SearchPosts("sgtitlereview channel:"+channel1.Name, false)).Data.(*model.PostList); len(result.Order) != 1 {
- t.Fatalf("wrong number of posts returned %v", len(result.Order))
- }
-
- if result := Client.Must(Client.SearchPosts("sgtitlereview in: "+channel2.Name, false)).Data.(*model.PostList); len(result.Order) != 1 {
- t.Fatalf("wrong number of posts returned %v", len(result.Order))
- }
-
- if result := Client.Must(Client.SearchPosts("sgtitlereview channel: "+channel2.Name, false)).Data.(*model.PostList); len(result.Order) != 1 {
- t.Fatalf("wrong number of posts returned %v", len(result.Order))
- }
-
- if result := Client.Must(Client.SearchPosts("channel: "+channel2.Name+" channel: "+channel3.Name, false)).Data.(*model.PostList); len(result.Order) != 3 {
- t.Fatalf("wrong number of posts returned :) %v :) %v", result.Posts, result.Order)
- }
-}
-
-func TestSearchPostsFromUser(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- Client := th.BasicClient
- channel1 := th.BasicChannel
- team := th.BasicTeam
- user1 := th.BasicUser
- user2 := th.BasicUser2
- channel2 := th.CreateChannel(Client, team)
- Client.Must(Client.AddChannelMember(channel1.Id, th.BasicUser2.Id))
- Client.Must(Client.AddChannelMember(channel2.Id, th.BasicUser2.Id))
- user3 := th.CreateUser(Client)
- th.LinkUserToTeam(user3, team)
- Client.Must(Client.AddChannelMember(channel1.Id, user3.Id))
- Client.Must(Client.AddChannelMember(channel2.Id, user3.Id))
-
- post1 := &model.Post{ChannelId: channel1.Id, Message: "sgtitlereview with space"}
- post1 = Client.Must(Client.CreatePost(post1)).Data.(*model.Post)
-
- th.LoginBasic2()
-
- post2 := &model.Post{ChannelId: channel2.Id, Message: "sgtitlereview\n with return"}
- post2 = Client.Must(Client.CreatePost(post2)).Data.(*model.Post)
-
- if result := Client.Must(Client.SearchPosts("from: "+user1.Username, false)).Data.(*model.PostList); len(result.Order) != 2 {
- t.Fatalf("wrong number of posts returned %v", len(result.Order))
- }
-
- if result := Client.Must(Client.SearchPosts("from: "+user2.Username, false)).Data.(*model.PostList); len(result.Order) != 1 {
- t.Fatalf("wrong number of posts returned %v", len(result.Order))
- }
-
- if result := Client.Must(Client.SearchPosts("from: "+user2.Username+" sgtitlereview", false)).Data.(*model.PostList); len(result.Order) != 1 {
- t.Fatalf("wrong number of posts returned %v", len(result.Order))
- }
-
- post3 := &model.Post{ChannelId: channel1.Id, Message: "hullo"}
- post3 = Client.Must(Client.CreatePost(post3)).Data.(*model.Post)
-
- if result := Client.Must(Client.SearchPosts("from: "+user2.Username+" in:"+channel1.Name, false)).Data.(*model.PostList); len(result.Order) != 1 {
- t.Fatalf("wrong number of posts returned %v", len(result.Order))
- }
-
- Client.Login(user3.Email, user3.Password)
-
- // wait for the join/leave messages to be created for user3 since they're done asynchronously
- time.Sleep(100 * time.Millisecond)
-
- if result := Client.Must(Client.SearchPosts("from: "+user2.Username, false)).Data.(*model.PostList); len(result.Order) != 2 {
- t.Fatalf("wrong number of posts returned %v", len(result.Order))
- }
-
- if result := Client.Must(Client.SearchPosts("from: "+user2.Username+" from: "+user3.Username, false)).Data.(*model.PostList); len(result.Order) != 2 {
- t.Fatalf("wrong number of posts returned %v", len(result.Order))
- }
-
- if result := Client.Must(Client.SearchPosts("from: "+user2.Username+" from: "+user3.Username+" in:"+channel2.Name, false)).Data.(*model.PostList); len(result.Order) != 1 {
- t.Fatalf("wrong number of posts returned %v", len(result.Order))
- }
-
- post4 := &model.Post{ChannelId: channel2.Id, Message: "coconut"}
- post4 = Client.Must(Client.CreatePost(post4)).Data.(*model.Post)
-
- if result := Client.Must(Client.SearchPosts("from: "+user2.Username+" from: "+user3.Username+" in:"+channel2.Name+" coconut", false)).Data.(*model.PostList); len(result.Order) != 1 {
- t.Fatalf("wrong number of posts returned %v", len(result.Order))
- }
-}
-
-func TestGetPostsCache(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- Client := th.BasicClient
- channel1 := th.BasicChannel
-
- time.Sleep(10 * time.Millisecond)
- post1 := &model.Post{ChannelId: channel1.Id, Message: "zz" + model.NewId() + "a"}
- post1 = Client.Must(Client.CreatePost(post1)).Data.(*model.Post)
-
- time.Sleep(10 * time.Millisecond)
- post2 := &model.Post{ChannelId: channel1.Id, Message: "zz" + model.NewId() + "a"}
- post2 = Client.Must(Client.CreatePost(post2)).Data.(*model.Post)
-
- time.Sleep(10 * time.Millisecond)
- post3 := &model.Post{ChannelId: channel1.Id, Message: "zz" + model.NewId() + "a"}
- post3 = Client.Must(Client.CreatePost(post3)).Data.(*model.Post)
-
- etag := Client.Must(Client.GetPosts(channel1.Id, 0, 2, "")).Etag
-
- // test etag caching
- if cache_result, err := Client.GetPosts(channel1.Id, 0, 2, etag); err != nil {
- t.Fatal(err)
- } else if cache_result.Data.(*model.PostList) != nil {
- t.Log(cache_result.Data)
- t.Fatal("cache should be empty")
- }
-
- etag = Client.Must(Client.GetPost(channel1.Id, post1.Id, "")).Etag
-
- // test etag caching
- if cache_result, err := Client.GetPost(channel1.Id, post1.Id, etag); err != nil {
- t.Fatal(err)
- } else if cache_result.Data.(*model.PostList) != nil {
- t.Log(cache_result.Data)
- t.Fatal("cache should be empty")
- }
-
-}
-
-func TestDeletePosts(t *testing.T) {
- th := Setup().InitBasic().InitSystemAdmin()
- defer th.TearDown()
-
- Client := th.BasicClient
- channel1 := th.BasicChannel
- team1 := th.BasicTeam
-
- time.Sleep(10 * time.Millisecond)
- post1 := &model.Post{ChannelId: channel1.Id, Message: "zz" + model.NewId() + "a"}
- post1 = Client.Must(Client.CreatePost(post1)).Data.(*model.Post)
-
- time.Sleep(10 * time.Millisecond)
- post1a1 := &model.Post{ChannelId: channel1.Id, Message: "zz" + model.NewId() + "a", RootId: post1.Id}
- post1a1 = Client.Must(Client.CreatePost(post1a1)).Data.(*model.Post)
-
- time.Sleep(10 * time.Millisecond)
- post1a2 := &model.Post{ChannelId: channel1.Id, Message: "zz" + model.NewId() + "a", RootId: post1.Id, ParentId: post1a1.Id}
- post1a2 = Client.Must(Client.CreatePost(post1a2)).Data.(*model.Post)
-
- time.Sleep(10 * time.Millisecond)
- post2 := &model.Post{ChannelId: channel1.Id, Message: "zz" + model.NewId() + "a"}
- post2 = Client.Must(Client.CreatePost(post2)).Data.(*model.Post)
-
- time.Sleep(10 * time.Millisecond)
- post3 := &model.Post{ChannelId: channel1.Id, Message: "zz" + model.NewId() + "a"}
- post3 = Client.Must(Client.CreatePost(post3)).Data.(*model.Post)
-
- time.Sleep(10 * time.Millisecond)
- post3a1 := &model.Post{ChannelId: channel1.Id, Message: "zz" + model.NewId() + "a", RootId: post3.Id}
- post3a1 = Client.Must(Client.CreatePost(post3a1)).Data.(*model.Post)
-
- time.Sleep(10 * time.Millisecond)
- Client.Must(Client.DeletePost(channel1.Id, post3.Id))
-
- r2 := Client.Must(Client.GetPosts(channel1.Id, 0, 10, "")).Data.(*model.PostList)
-
- if post := r2.Posts[post3.Id]; post != nil {
- t.Fatal("should have not returned deleted post")
- }
-
- time.Sleep(10 * time.Millisecond)
- post4a := &model.Post{ChannelId: channel1.Id, Message: "zz" + model.NewId() + "a"}
- post4a = Client.Must(Client.CreatePost(post4a)).Data.(*model.Post)
-
- time.Sleep(10 * time.Millisecond)
- post4b := &model.Post{ChannelId: channel1.Id, Message: "zz" + model.NewId() + "a"}
- post4b = Client.Must(Client.CreatePost(post4b)).Data.(*model.Post)
-
- SystemAdminClient := th.SystemAdminClient
- th.LinkUserToTeam(th.SystemAdminUser, th.BasicTeam)
- SystemAdminClient.Must(SystemAdminClient.JoinChannel(channel1.Id))
-
- th.LoginBasic2()
- Client.Must(Client.JoinChannel(channel1.Id))
-
- if _, err := Client.DeletePost(channel1.Id, post4a.Id); err == nil {
- t.Fatal(err)
- }
-
- // Check the appropriate permissions are enforced.
- defaultRolePermissions := th.SaveDefaultRolePermissions()
- defer func() {
- th.RestoreDefaultRolePermissions(defaultRolePermissions)
- }()
-
- th.UpdateUserToTeamAdmin(th.BasicUser2, th.BasicTeam)
-
- Client.Logout()
- th.LoginBasic2()
- Client.SetTeamId(team1.Id)
-
- Client.Must(Client.DeletePost(channel1.Id, post4a.Id))
-
- SystemAdminClient.Must(SystemAdminClient.DeletePost(channel1.Id, post4b.Id))
-
- th.RemovePermissionFromRole(model.PERMISSION_DELETE_POST.Id, model.CHANNEL_USER_ROLE_ID)
- th.AddPermissionToRole(model.PERMISSION_DELETE_POST.Id, model.TEAM_ADMIN_ROLE_ID)
-
- th.LoginBasic()
-
- time.Sleep(10 * time.Millisecond)
- post5a := &model.Post{ChannelId: channel1.Id, Message: "zz" + model.NewId() + "a"}
- post5a = Client.Must(Client.CreatePost(post5a)).Data.(*model.Post)
-
- time.Sleep(10 * time.Millisecond)
- post5b := &model.Post{ChannelId: channel1.Id, Message: "zz" + model.NewId() + "a"}
- post5b = Client.Must(Client.CreatePost(post5b)).Data.(*model.Post)
-
- if _, err := Client.DeletePost(channel1.Id, post5a.Id); err == nil {
- t.Fatal(err)
- }
-
- th.LoginBasic2()
-
- Client.Must(Client.DeletePost(channel1.Id, post5a.Id))
-
- SystemAdminClient.Must(SystemAdminClient.DeletePost(channel1.Id, post5b.Id))
-}
-
-func TestEmailMention(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- Client := th.BasicClient
- channel1 := th.BasicChannel
- Client.Must(Client.AddChannelMember(channel1.Id, th.BasicUser2.Id))
-
- th.LoginBasic2()
- //Set the notification properties
- data := make(map[string]string)
- data["user_id"] = th.BasicUser2.Id
- data["email"] = "true"
- data["desktop"] = "all"
- data["desktop_sound"] = "false"
- data["comments"] = "any"
- Client.Must(Client.UpdateUserNotify(data))
-
- store.Must(th.App.Srv.Store.Preference().Save(&model.Preferences{{
- UserId: th.BasicUser2.Id,
- Category: model.PREFERENCE_CATEGORY_NOTIFICATIONS,
- Name: model.PREFERENCE_NAME_EMAIL_INTERVAL,
- Value: "0",
- }}))
-
- //Delete all the messages before create a mention post
- utils.DeleteMailBox(th.BasicUser2.Email)
-
- //Send a mention message from user1 to user2
- th.LoginBasic()
- time.Sleep(10 * time.Millisecond)
- post1 := &model.Post{ChannelId: channel1.Id, Message: "@" + th.BasicUser2.Username + " this is a test"}
- post1 = Client.Must(Client.CreatePost(post1)).Data.(*model.Post)
-
- var resultsMailbox utils.JSONMessageHeaderInbucket
- err := utils.RetryInbucket(5, func() error {
- var err error
- resultsMailbox, err = utils.GetMailBox(th.BasicUser2.Email)
- return err
- })
- if err != nil {
- t.Log(err)
- t.Log("No email was received, maybe due load on the server. Disabling this verification")
- }
- if err == nil && len(resultsMailbox) > 0 {
- if !strings.ContainsAny(resultsMailbox[len(resultsMailbox)-1].To[0], th.BasicUser2.Email) {
- t.Fatal("Wrong To recipient")
- } else {
- for i := 0; i < 30; i++ {
- for j := len(resultsMailbox) - 1; j >= 0; j-- {
- isUser := false
- for _, to := range resultsMailbox[j].To {
- if to == "<"+th.BasicUser2.Email+">" {
- isUser = true
- }
- }
- if !isUser {
- continue
- }
- if resultsEmail, err := utils.GetMessageFromMailbox(th.BasicUser2.Email, resultsMailbox[j].ID); err == nil {
- if strings.Contains(resultsEmail.Body.Text, post1.Message) {
- return
- } else if i == 4 {
- t.Log(resultsEmail.Body.Text)
- t.Fatal("Received wrong Message")
- }
- }
- }
- time.Sleep(100 * time.Millisecond)
- }
- t.Fatal("Didn't receive message")
- }
- }
-}
-
-func TestFuzzyPosts(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- Client := th.BasicClient
- channel1 := th.BasicChannel
-
- for i := 0; i < len(utils.FUZZY_STRINGS_POSTS); i++ {
- post := &model.Post{ChannelId: channel1.Id, Message: utils.FUZZY_STRINGS_POSTS[i]}
-
- _, err := Client.CreatePost(post)
- if err != nil {
- t.Fatal(err)
- }
- }
-}
-
-func TestGetFlaggedPosts(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- Client := th.BasicClient
- user1 := th.BasicUser
- post1 := th.BasicPost
-
- preferences := &model.Preferences{
- {
- UserId: user1.Id,
- Category: model.PREFERENCE_CATEGORY_FLAGGED_POST,
- Name: post1.Id,
- Value: "true",
- },
- }
- Client.Must(Client.SetPreferences(preferences))
-
- r1 := Client.Must(Client.GetFlaggedPosts(0, 2)).Data.(*model.PostList)
-
- if len(r1.Order) == 0 {
- t.Fatal("should have gotten a flagged post")
- }
-
- if _, ok := r1.Posts[post1.Id]; !ok {
- t.Fatal("missing flagged post")
- }
-
- Client.DeletePreferences(preferences)
-
- r2 := Client.Must(Client.GetFlaggedPosts(0, 2)).Data.(*model.PostList)
-
- if len(r2.Order) != 0 {
- t.Fatal("should not have gotten a flagged post")
- }
-
- Client.SetTeamId(model.NewId())
- if _, err := Client.GetFlaggedPosts(0, 2); err == nil {
- t.Fatal("should have failed - bad team id")
- }
-}
-
-func TestGetMessageForNotification(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- testPng := store.Must(th.App.Srv.Store.FileInfo().Save(&model.FileInfo{
- CreatorId: model.NewId(),
- Path: "test1.png",
- Name: "test1.png",
- MimeType: "image/png",
- })).(*model.FileInfo)
-
- testJpg1 := store.Must(th.App.Srv.Store.FileInfo().Save(&model.FileInfo{
- CreatorId: model.NewId(),
- Path: "test2.jpg",
- Name: "test2.jpg",
- MimeType: "image/jpeg",
- })).(*model.FileInfo)
-
- testFile := store.Must(th.App.Srv.Store.FileInfo().Save(&model.FileInfo{
- CreatorId: model.NewId(),
- Path: "test1.go",
- Name: "test1.go",
- MimeType: "text/plain",
- })).(*model.FileInfo)
-
- testJpg2 := store.Must(th.App.Srv.Store.FileInfo().Save(&model.FileInfo{
- CreatorId: model.NewId(),
- Path: "test3.jpg",
- Name: "test3.jpg",
- MimeType: "image/jpeg",
- })).(*model.FileInfo)
-
- translateFunc := utils.GetUserTranslations("en")
-
- post := &model.Post{
- Id: model.NewId(),
- Message: "test",
- }
-
- if th.App.GetMessageForNotification(post, translateFunc) != "test" {
- t.Fatal("should've returned message text")
- }
-
- post.FileIds = model.StringArray{testPng.Id}
- store.Must(th.App.Srv.Store.FileInfo().AttachToPost(testPng.Id, post.Id))
- if th.App.GetMessageForNotification(post, translateFunc) != "test" {
- t.Fatal("should've returned message text, even with attachments")
- }
-
- post.Message = ""
- if message := th.App.GetMessageForNotification(post, translateFunc); message != "1 image sent: test1.png" {
- t.Fatal("should've returned number of images:", message)
- }
-
- post.FileIds = model.StringArray{testPng.Id, testJpg1.Id}
- store.Must(th.App.Srv.Store.FileInfo().AttachToPost(testJpg1.Id, post.Id))
- th.App.Srv.Store.FileInfo().InvalidateFileInfosForPostCache(post.Id)
- if message := th.App.GetMessageForNotification(post, translateFunc); message != "2 images sent: test1.png, test2.jpg" && message != "2 images sent: test2.jpg, test1.png" {
- t.Fatal("should've returned number of images:", message)
- }
-
- post.Id = model.NewId()
- post.FileIds = model.StringArray{testFile.Id}
- store.Must(th.App.Srv.Store.FileInfo().AttachToPost(testFile.Id, post.Id))
- if message := th.App.GetMessageForNotification(post, translateFunc); message != "1 file sent: test1.go" {
- t.Fatal("should've returned number of files:", message)
- }
-
- store.Must(th.App.Srv.Store.FileInfo().AttachToPost(testJpg2.Id, post.Id))
- th.App.Srv.Store.FileInfo().InvalidateFileInfosForPostCache(post.Id)
- post.FileIds = model.StringArray{testFile.Id, testJpg2.Id}
- if message := th.App.GetMessageForNotification(post, translateFunc); message != "2 files sent: test1.go, test3.jpg" && message != "2 files sent: test3.jpg, test1.go" {
- t.Fatal("should've returned number of mixed files:", message)
- }
-}
-
-func TestGetFileInfosForPost(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- Client := th.BasicClient
- channel1 := th.BasicChannel
-
- fileIds := make([]string, 3)
- if data, err := readTestFile("test.png"); err != nil {
- t.Fatal(err)
- } else {
- for i := 0; i < 3; i++ {
- fileIds[i] = Client.MustGeneric(Client.UploadPostAttachment(data, channel1.Id, "test.png")).(*model.FileUploadResponse).FileInfos[0].Id
- }
- }
-
- post1 := Client.Must(Client.CreatePost(&model.Post{
- ChannelId: channel1.Id,
- Message: "test",
- FileIds: fileIds,
- })).Data.(*model.Post)
-
- var etag string
- if infos, err := Client.GetFileInfosForPost(channel1.Id, post1.Id, ""); err != nil {
- t.Fatal(err)
- } else if len(infos) != 3 {
- t.Fatal("should've received 3 files")
- } else if Client.Etag == "" {
- t.Fatal("should've received etag")
- } else {
- etag = Client.Etag
- }
-
- if infos, err := Client.GetFileInfosForPost(channel1.Id, post1.Id, etag); err != nil {
- t.Fatal(err)
- } else if len(infos) != 0 {
- t.Fatal("should've returned nothing because of etag")
- }
-}
-
-func TestGetPostById(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- Client := th.BasicClient
- channel1 := th.BasicChannel
-
- time.Sleep(10 * time.Millisecond)
- post1 := &model.Post{ChannelId: channel1.Id, Message: "yommamma" + model.NewId() + "a"}
- post1 = Client.Must(Client.CreatePost(post1)).Data.(*model.Post)
-
- if post, respMetadata := Client.GetPostById(post1.Id, ""); respMetadata.Error != nil {
- t.Fatal(respMetadata.Error)
- } else {
- if len(post.Order) != 1 {
- t.Fatal("should be just one post")
- }
-
- if post.Order[0] != post1.Id {
- t.Fatal("wrong order")
- }
-
- if post.Posts[post.Order[0]].Message != post1.Message {
- t.Fatal("wrong message from post")
- }
- }
-
- if _, respMetadata := Client.GetPostById("45345435345345", ""); respMetadata.Error == nil {
- t.Fatal(respMetadata.Error)
- }
-}
-
-func TestGetPermalinkTmp(t *testing.T) {
- th := Setup().InitBasic().InitSystemAdmin()
- defer th.TearDown()
-
- Client := th.BasicClient
- channel1 := th.BasicChannel
- team := th.BasicTeam
-
- th.LoginBasic()
-
- time.Sleep(10 * time.Millisecond)
- post1 := &model.Post{ChannelId: channel1.Id, Message: "zz" + model.NewId() + "a"}
- post1 = Client.Must(Client.CreatePost(post1)).Data.(*model.Post)
-
- time.Sleep(10 * time.Millisecond)
- post2 := &model.Post{ChannelId: channel1.Id, Message: "zz" + model.NewId() + "a"}
- post2 = Client.Must(Client.CreatePost(post2)).Data.(*model.Post)
-
- etag := Client.Must(Client.GetPost(channel1.Id, post1.Id, "")).Etag
-
- // test etag caching
- if cache_result, respMetadata := Client.GetPermalink(channel1.Id, post1.Id, etag); respMetadata.Error != nil {
- t.Fatal(respMetadata.Error)
- } else if cache_result != nil {
- t.Log(cache_result)
- t.Fatal("cache should be empty")
- }
-
- if results, respMetadata := Client.GetPermalink(channel1.Id, post1.Id, ""); respMetadata.Error != nil {
- t.Fatal(respMetadata.Error)
- } else if results == nil {
- t.Fatal("should not be empty")
- }
-
- // Test permalink to private channels.
- channel2 := &model.Channel{DisplayName: "TestGetPermalinkPriv", Name: "zz" + model.NewId() + "a", Type: model.CHANNEL_PRIVATE, TeamId: team.Id}
- channel2 = Client.Must(Client.CreateChannel(channel2)).Data.(*model.Channel)
- time.Sleep(10 * time.Millisecond)
- post3 := &model.Post{ChannelId: channel2.Id, Message: "zz" + model.NewId() + "a"}
- post3 = Client.Must(Client.CreatePost(post3)).Data.(*model.Post)
-
- if _, md := Client.GetPermalink(channel2.Id, post3.Id, ""); md.Error != nil {
- t.Fatal(md.Error)
- }
-
- th.LoginBasic2()
-
- if _, md := Client.GetPermalink(channel2.Id, post3.Id, ""); md.Error == nil {
- t.Fatal("Expected 403 error")
- }
-
- // Test direct channels.
- th.LoginBasic()
- channel3 := Client.Must(Client.CreateDirectChannel(th.SystemAdminUser.Id)).Data.(*model.Channel)
- time.Sleep(10 * time.Millisecond)
- post4 := &model.Post{ChannelId: channel3.Id, Message: "zz" + model.NewId() + "a"}
- post4 = Client.Must(Client.CreatePost(post4)).Data.(*model.Post)
-
- if _, md := Client.GetPermalink(channel3.Id, post4.Id, ""); md.Error != nil {
- t.Fatal(md.Error)
- }
-
- th.LoginBasic2()
-
- if _, md := Client.GetPermalink(channel3.Id, post4.Id, ""); md.Error == nil {
- t.Fatal("Expected 403 error")
- }
-}
-
-func TestGetOpenGraphMetadata(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- Client := th.BasicClient
-
- th.App.UpdateConfig(func(cfg *model.Config) {
- *cfg.ServiceSettings.EnableLinkPreviews = true
- *cfg.ServiceSettings.AllowedUntrustedInternalConnections = "localhost 127.0.0.1"
- })
-
- ogDataCacheMissCount := 0
-
- ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- ogDataCacheMissCount++
-
- if r.URL.Path == "/og-data/" {
- fmt.Fprintln(w, `
- <html><head><meta property="og:type" content="article" />
- <meta property="og:title" content="Test Title" />
- <meta property="og:url" content="http://example.com/" />
- </head><body></body></html>
- `)
- } else if r.URL.Path == "/no-og-data/" {
- fmt.Fprintln(w, `<html><head></head><body></body></html>`)
- }
- }))
-
- for _, data := range [](map[string]interface{}){
- {"path": "/og-data/", "title": "Test Title", "cacheMissCount": 1},
- {"path": "/no-og-data/", "title": "", "cacheMissCount": 2},
-
- // Data should be cached for following
- {"path": "/og-data/", "title": "Test Title", "cacheMissCount": 2},
- {"path": "/no-og-data/", "title": "", "cacheMissCount": 2},
- } {
- res, err := Client.DoApiPost(
- "/get_opengraph_metadata",
- fmt.Sprintf("{\"url\":\"%s\"}", ts.URL+data["path"].(string)),
- )
- if err != nil {
- t.Fatal(err)
- }
-
- ogData := model.StringInterfaceFromJson(res.Body)
- if strings.Compare(ogData["title"].(string), data["title"].(string)) != 0 {
- t.Fatal(fmt.Sprintf(
- "OG data title mismatch for path \"%s\". Expected title: \"%s\". Actual title: \"%s\"",
- data["path"].(string), data["title"].(string), ogData["title"].(string),
- ))
- }
-
- if ogDataCacheMissCount != data["cacheMissCount"].(int) {
- t.Fatal(fmt.Sprintf(
- "Cache miss count didn't match. Expected value %d. Actual value %d.",
- data["cacheMissCount"].(int), ogDataCacheMissCount,
- ))
- }
- }
-
- th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableLinkPreviews = false })
- if _, err := Client.DoApiPost("/get_opengraph_metadata", "{\"url\":\"/og-data/\"}"); err == nil || err.StatusCode != http.StatusNotImplemented {
- t.Fatal("should have failed with 501 - disabled link previews")
- }
-}
-
-func TestPinPost(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- Client := th.BasicClient
-
- post := th.BasicPost
- if rupost1, err := Client.PinPost(post.ChannelId, post.Id); err != nil {
- t.Fatal(err)
- } else {
- if !rupost1.Data.(*model.Post).IsPinned {
- t.Fatal("failed to pin post")
- }
- }
-
- pinnedPost := th.PinnedPost
- if rupost2, err := Client.PinPost(pinnedPost.ChannelId, pinnedPost.Id); err != nil {
- t.Fatal(err)
- } else {
- if !rupost2.Data.(*model.Post).IsPinned {
- t.Fatal("pinning a post should be idempotent")
- }
- }
-}
-
-func TestUnpinPost(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- Client := th.BasicClient
-
- pinnedPost := th.PinnedPost
- if rupost1, err := Client.UnpinPost(pinnedPost.ChannelId, pinnedPost.Id); err != nil {
- t.Fatal(err)
- } else {
- if rupost1.Data.(*model.Post).IsPinned {
- t.Fatal("failed to unpin post")
- }
- }
-
- post := th.BasicPost
- if rupost2, err := Client.UnpinPost(post.ChannelId, post.Id); err != nil {
- t.Fatal(err)
- } else {
- if rupost2.Data.(*model.Post).IsPinned {
- t.Fatal("unpinning a post should be idempotent")
- }
- }
-}
diff --git a/api/preference.go b/api/preference.go
deleted file mode 100644
index 8de1ea453..000000000
--- a/api/preference.go
+++ /dev/null
@@ -1,85 +0,0 @@
-// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-package api
-
-import (
- "net/http"
-
- "github.com/gorilla/mux"
- "github.com/mattermost/mattermost-server/model"
-)
-
-func (api *API) InitPreference() {
- api.BaseRoutes.Preferences.Handle("/", api.ApiUserRequired(getAllPreferences)).Methods("GET")
- api.BaseRoutes.Preferences.Handle("/save", api.ApiUserRequired(savePreferences)).Methods("POST")
- api.BaseRoutes.Preferences.Handle("/delete", api.ApiUserRequired(deletePreferences)).Methods("POST")
- api.BaseRoutes.Preferences.Handle("/{category:[A-Za-z0-9_]+}", api.ApiUserRequired(getPreferenceCategory)).Methods("GET")
- api.BaseRoutes.Preferences.Handle("/{category:[A-Za-z0-9_]+}/{name:[A-Za-z0-9_]+}", api.ApiUserRequired(getPreference)).Methods("GET")
-}
-
-func getAllPreferences(c *Context, w http.ResponseWriter, r *http.Request) {
- if result := <-c.App.Srv.Store.Preference().GetAll(c.Session.UserId); result.Err != nil {
- c.Err = result.Err
- } else {
- data := result.Data.(model.Preferences)
-
- w.Write([]byte(data.ToJson()))
- }
-}
-
-func savePreferences(c *Context, w http.ResponseWriter, r *http.Request) {
- preferences, err := model.PreferencesFromJson(r.Body)
- if err != nil {
- c.Err = model.NewAppError("savePreferences", "api.preference.save_preferences.decode.app_error", nil, err.Error(), http.StatusBadRequest)
- return
- }
-
- if err := c.App.UpdatePreferences(c.Session.UserId, preferences); err != nil {
- c.Err = err
- return
- }
-
- w.Write([]byte("true"))
-}
-
-func getPreferenceCategory(c *Context, w http.ResponseWriter, r *http.Request) {
- params := mux.Vars(r)
- category := params["category"]
-
- if result := <-c.App.Srv.Store.Preference().GetCategory(c.Session.UserId, category); result.Err != nil {
- c.Err = result.Err
- } else {
- data := result.Data.(model.Preferences)
-
- w.Write([]byte(data.ToJson()))
- }
-}
-
-func getPreference(c *Context, w http.ResponseWriter, r *http.Request) {
- params := mux.Vars(r)
- category := params["category"]
- name := params["name"]
-
- if result := <-c.App.Srv.Store.Preference().Get(c.Session.UserId, category, name); result.Err != nil {
- c.Err = result.Err
- } else {
- data := result.Data.(model.Preference)
- w.Write([]byte(data.ToJson()))
- }
-}
-
-func deletePreferences(c *Context, w http.ResponseWriter, r *http.Request) {
- preferences, err := model.PreferencesFromJson(r.Body)
- if err != nil {
- c.Err = model.NewAppError("savePreferences", "api.preference.delete_preferences.decode.app_error", nil, err.Error(), http.StatusBadRequest)
- return
- }
-
- if err := c.App.DeletePreferences(c.Session.UserId, preferences); err != nil {
- c.Err = err
- return
- }
-
- ReturnStatusOK(w)
-}
diff --git a/api/preference_test.go b/api/preference_test.go
deleted file mode 100644
index 3948ca2c9..000000000
--- a/api/preference_test.go
+++ /dev/null
@@ -1,220 +0,0 @@
-// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-package api
-
-import (
- "testing"
-
- "github.com/mattermost/mattermost-server/model"
-)
-
-func TestGetAllPreferences(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- Client := th.BasicClient
- 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.Must(Client.SetPreferences(&preferences1))
-
- if result, err := Client.GetAllPreferences(); err != nil {
- t.Fatal(err)
- } else if data := result.Data.(model.Preferences); len(data) != 4 {
- t.Fatal("received the wrong number of preferences")
- }
-
- th.LoginBasic2()
-
- if result, err := Client.GetAllPreferences(); err != nil {
- t.Fatal(err)
- } else if data := result.Data.(model.Preferences); len(data) == 0 {
- t.Fatal("received the wrong number of preferences")
- }
-}
-
-func TestSetPreferences(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- Client := th.BasicClient
- user1 := th.BasicUser
-
- // save 10 preferences
- var preferences model.Preferences
- for i := 0; i < 10; i++ {
- preference := model.Preference{
- UserId: user1.Id,
- Category: model.PREFERENCE_CATEGORY_DIRECT_CHANNEL_SHOW,
- Name: model.NewId(),
- }
- preferences = append(preferences, preference)
- }
-
- if _, err := Client.SetPreferences(&preferences); err != nil {
- t.Fatal(err)
- }
-
- // update 10 preferences
- for _, preference := range preferences {
- preference.Value = "1234garbage"
- }
-
- if _, err := Client.SetPreferences(&preferences); err != nil {
- t.Fatal(err)
- }
-
- th.LoginBasic2()
-
- if _, err := Client.SetPreferences(&preferences); err == nil {
- t.Fatal("shouldn't have been able to update another user's preferences")
- }
-}
-
-func TestGetPreferenceCategory(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- Client := th.BasicClient
- 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.Must(Client.SetPreferences(&preferences1))
-
- if result, err := Client.GetPreferenceCategory(category); err != nil {
- t.Fatal(err)
- } else if data := result.Data.(model.Preferences); len(data) != 2 {
- t.Fatal("received the wrong number of preferences")
- } else if !((data[0] == preferences1[0] && data[1] == preferences1[1]) || (data[0] == preferences1[1] && data[1] == preferences1[0])) {
- t.Fatal("received incorrect preferences")
- }
-
- th.LoginBasic2()
-
- if result, err := Client.GetPreferenceCategory(category); err != nil {
- t.Fatal(err)
- } else if data := result.Data.(model.Preferences); len(data) != 0 {
- t.Fatal("received the wrong number of preferences")
- }
-}
-
-func TestGetPreference(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- Client := th.BasicClient
- user := th.BasicUser
-
- preferences := model.Preferences{
- {
- UserId: user.Id,
- Category: model.PREFERENCE_CATEGORY_DIRECT_CHANNEL_SHOW,
- Name: model.NewId(),
- Value: model.NewId(),
- },
- }
-
- Client.Must(Client.SetPreferences(&preferences))
-
- if result, err := Client.GetPreference(preferences[0].Category, preferences[0].Name); err != nil {
- t.Fatal(err)
- } else if data := result.Data.(*model.Preference); *data != preferences[0] {
- t.Fatal("preference saved incorrectly")
- }
-
- preferences[0].Value = model.NewId()
- Client.Must(Client.SetPreferences(&preferences))
-
- if result, err := Client.GetPreference(preferences[0].Category, preferences[0].Name); err != nil {
- t.Fatal(err)
- } else if data := result.Data.(*model.Preference); *data != preferences[0] {
- t.Fatal("preference updated incorrectly")
- }
-}
-
-func TestDeletePreferences(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- Client := th.BasicClient
- user1 := th.BasicUser
-
- var originalCount int
- if result, err := Client.GetAllPreferences(); err != nil {
- t.Fatal(err)
- } else {
- originalCount = len(result.Data.(model.Preferences))
- }
-
- // save 10 preferences
- var preferences model.Preferences
- for i := 0; i < 10; i++ {
- preference := model.Preference{
- UserId: user1.Id,
- Category: model.PREFERENCE_CATEGORY_DIRECT_CHANNEL_SHOW,
- Name: model.NewId(),
- }
- preferences = append(preferences, preference)
- }
-
- if _, err := Client.SetPreferences(&preferences); err != nil {
- t.Fatal(err)
- }
-
- // delete 10 preferences
- th.LoginBasic2()
-
- if _, err := Client.DeletePreferences(&preferences); err == nil {
- t.Fatal("shouldn't have been able to delete another user's preferences")
- }
-
- th.LoginBasic()
- if _, err := Client.DeletePreferences(&preferences); err != nil {
- t.Fatal(err)
- }
-
- if result, err := Client.GetAllPreferences(); err != nil {
- t.Fatal(err)
- } else if data := result.Data.(model.Preferences); len(data) != originalCount {
- t.Fatal("should've deleted preferences")
- }
-}
diff --git a/api/reaction.go b/api/reaction.go
deleted file mode 100644
index 812c9f582..000000000
--- a/api/reaction.go
+++ /dev/null
@@ -1,149 +0,0 @@
-// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-package api
-
-import (
- "net/http"
-
- "github.com/gorilla/mux"
- "github.com/mattermost/mattermost-server/model"
-)
-
-func (api *API) InitReaction() {
- api.BaseRoutes.NeedPost.Handle("/reactions/save", api.ApiUserRequired(saveReaction)).Methods("POST")
- api.BaseRoutes.NeedPost.Handle("/reactions/delete", api.ApiUserRequired(deleteReaction)).Methods("POST")
- api.BaseRoutes.NeedPost.Handle("/reactions", api.ApiUserRequired(listReactions)).Methods("GET")
-}
-
-func saveReaction(c *Context, w http.ResponseWriter, r *http.Request) {
- reaction := model.ReactionFromJson(r.Body)
- if reaction == nil {
- c.SetInvalidParam("saveReaction", "reaction")
- return
- }
-
- if reaction.UserId != c.Session.UserId {
- c.Err = model.NewAppError("saveReaction", "api.reaction.save_reaction.user_id.app_error", nil, "", http.StatusForbidden)
- return
- }
-
- params := mux.Vars(r)
-
- channelId := params["channel_id"]
- if len(channelId) != 26 {
- c.SetInvalidParam("saveReaction", "channelId")
- return
- }
-
- if !c.App.SessionHasPermissionToChannel(c.Session, channelId, model.PERMISSION_ADD_REACTION) {
- c.SetPermissionError(model.PERMISSION_ADD_REACTION)
- return
- }
-
- postId := params["post_id"]
- if len(postId) != 26 || postId != reaction.PostId {
- c.SetInvalidParam("saveReaction", "postId")
- return
- }
-
- var post *model.Post
-
- if result := <-c.App.Srv.Store.Post().Get(reaction.PostId); result.Err != nil {
- c.Err = result.Err
- return
- } else if post = result.Data.(*model.PostList).Posts[postId]; post.ChannelId != channelId {
- c.Err = model.NewAppError("saveReaction", "api.reaction.save_reaction.mismatched_channel_id.app_error",
- nil, "channelId="+channelId+", post.ChannelId="+post.ChannelId+", postId="+postId, http.StatusBadRequest)
- return
- }
-
- if reaction, err := c.App.SaveReactionForPost(reaction); err != nil {
- c.Err = err
- return
- } else {
- w.Write([]byte(reaction.ToJson()))
- return
- }
-}
-
-func deleteReaction(c *Context, w http.ResponseWriter, r *http.Request) {
- reaction := model.ReactionFromJson(r.Body)
- if reaction == nil {
- c.SetInvalidParam("deleteReaction", "reaction")
- return
- }
-
- if reaction.UserId != c.Session.UserId {
- c.Err = model.NewAppError("deleteReaction", "api.reaction.delete_reaction.user_id.app_error", nil, "", http.StatusForbidden)
- return
- }
-
- params := mux.Vars(r)
-
- channelId := params["channel_id"]
- if len(channelId) != 26 {
- c.SetInvalidParam("deleteReaction", "channelId")
- return
- }
-
- if !c.App.SessionHasPermissionToChannel(c.Session, channelId, model.PERMISSION_REMOVE_REACTION) {
- c.SetPermissionError(model.PERMISSION_REMOVE_REACTION)
- return
- }
-
- postId := params["post_id"]
- if len(postId) != 26 || postId != reaction.PostId {
- c.SetInvalidParam("deleteReaction", "postId")
- return
- }
-
- err := c.App.DeleteReactionForPost(reaction)
- if err != nil {
- c.Err = err
- return
- }
-
- ReturnStatusOK(w)
-}
-
-func listReactions(c *Context, w http.ResponseWriter, r *http.Request) {
- params := mux.Vars(r)
-
- channelId := params["channel_id"]
- if len(channelId) != 26 {
- c.SetInvalidParam("deletePost", "channelId")
- return
- }
-
- postId := params["post_id"]
- if len(postId) != 26 {
- c.SetInvalidParam("listReactions", "postId")
- return
- }
-
- pchan := c.App.Srv.Store.Post().Get(postId)
-
- if !c.App.SessionHasPermissionToChannel(c.Session, channelId, model.PERMISSION_READ_CHANNEL) {
- c.SetPermissionError(model.PERMISSION_READ_CHANNEL)
- return
- }
-
- if result := <-pchan; result.Err != nil {
- c.Err = result.Err
- return
- } else if post := result.Data.(*model.PostList).Posts[postId]; post.ChannelId != channelId {
- c.Err = model.NewAppError("listReactions", "api.reaction.list_reactions.mismatched_channel_id.app_error",
- nil, "channelId="+channelId+", post.ChannelId="+post.ChannelId+", postId="+postId, http.StatusBadRequest)
- return
- }
-
- if result := <-c.App.Srv.Store.Reaction().GetForPost(postId, true); result.Err != nil {
- c.Err = result.Err
- return
- } else {
- reactions := result.Data.([]*model.Reaction)
-
- w.Write([]byte(model.ReactionsToJson(reactions)))
- }
-}
diff --git a/api/reaction_test.go b/api/reaction_test.go
deleted file mode 100644
index 23e02fb7a..000000000
--- a/api/reaction_test.go
+++ /dev/null
@@ -1,317 +0,0 @@
-// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-package api
-
-import (
- "testing"
-
- "github.com/mattermost/mattermost-server/model"
-)
-
-func TestSaveReaction(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- Client := th.BasicClient
-
- user := th.BasicUser
- user2 := th.BasicUser2
-
- channel := th.BasicChannel
- post := th.BasicPost
-
- // saving a reaction
- reaction := &model.Reaction{
- UserId: user.Id,
- PostId: post.Id,
- EmojiName: "smile",
- }
- if returned, err := Client.SaveReaction(channel.Id, reaction); err != nil {
- t.Fatal(err)
- } else {
- reaction = returned
- }
-
- if reactions := Client.MustGeneric(Client.ListReactions(channel.Id, post.Id)).([]*model.Reaction); len(reactions) != 1 || *reactions[0] != *reaction {
- t.Fatal("didn't save reaction correctly")
- }
-
- // saving a duplicate reaction
- if _, err := Client.SaveReaction(channel.Id, reaction); err != nil {
- t.Fatal(err)
- }
-
- // saving a second reaction on a post
- reaction2 := &model.Reaction{
- UserId: user.Id,
- PostId: post.Id,
- EmojiName: "sad",
- }
- if returned, err := Client.SaveReaction(channel.Id, reaction2); err != nil {
- t.Fatal(err)
- } else {
- reaction2 = returned
- }
-
- if reactions := Client.MustGeneric(Client.ListReactions(channel.Id, post.Id)).([]*model.Reaction); len(reactions) != 2 ||
- (*reactions[0] != *reaction && *reactions[1] != *reaction) || (*reactions[0] != *reaction2 && *reactions[1] != *reaction2) {
- t.Fatal("didn't save multiple reactions correctly")
- }
-
- // saving a reaction without a user id
- reaction3 := &model.Reaction{
- PostId: post.Id,
- EmojiName: "smile",
- }
- if _, err := Client.SaveReaction(channel.Id, reaction3); err == nil {
- t.Fatal("should've failed to save reaction without user id")
- }
-
- // saving a reaction without a post id
- reaction4 := &model.Reaction{
- UserId: user.Id,
- EmojiName: "smile",
- }
- if _, err := Client.SaveReaction(channel.Id, reaction4); err == nil {
- t.Fatal("should've failed to save reaction without post id")
- }
-
- // saving a reaction without a emoji name
- reaction5 := &model.Reaction{
- UserId: user.Id,
- PostId: post.Id,
- }
- if _, err := Client.SaveReaction(channel.Id, reaction5); err == nil {
- t.Fatal("should've failed to save reaction without emoji name")
- }
-
- // saving a reaction for another user
- reaction6 := &model.Reaction{
- UserId: user2.Id,
- PostId: post.Id,
- EmojiName: "smile",
- }
- if _, err := Client.SaveReaction(channel.Id, reaction6); err == nil {
- t.Fatal("should've failed to save reaction for another user")
- }
-
- // saving a reaction to a channel we're not a member of
- th.LoginBasic2()
- channel2 := th.CreateChannel(th.BasicClient, th.BasicTeam)
- post2 := th.CreatePost(th.BasicClient, channel2)
- th.LoginBasic()
-
- reaction7 := &model.Reaction{
- UserId: user.Id,
- PostId: post2.Id,
- EmojiName: "smile",
- }
- if _, err := Client.SaveReaction(channel2.Id, reaction7); err == nil {
- t.Fatal("should've failed to save reaction to a channel we're not a member of")
- }
-
- // saving a reaction to a direct channel
- directChannel := Client.Must(Client.CreateDirectChannel(user2.Id)).Data.(*model.Channel)
- directPost := th.CreatePost(th.BasicClient, directChannel)
-
- reaction8 := &model.Reaction{
- UserId: user.Id,
- PostId: directPost.Id,
- EmojiName: "smile",
- }
- if returned, err := Client.SaveReaction(directChannel.Id, reaction8); err != nil {
- t.Fatal(err)
- } else {
- reaction8 = returned
- }
-
- if reactions := Client.MustGeneric(Client.ListReactions(directChannel.Id, directPost.Id)).([]*model.Reaction); len(reactions) != 1 || *reactions[0] != *reaction8 {
- t.Fatal("didn't save reaction correctly")
- }
-
- // saving a reaction for a post in the wrong channel
- reaction9 := &model.Reaction{
- UserId: user.Id,
- PostId: directPost.Id,
- EmojiName: "sad",
- }
- if _, err := Client.SaveReaction(channel.Id, reaction9); err == nil {
- t.Fatal("should've failed to save reaction to a post that isn't in the given channel")
- }
-}
-
-func TestDeleteReaction(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- Client := th.BasicClient
-
- user := th.BasicUser
- user2 := th.BasicUser2
-
- channel := th.BasicChannel
- post := th.BasicPost
-
- reaction1 := &model.Reaction{
- UserId: user.Id,
- PostId: post.Id,
- EmojiName: "smile",
- }
-
- // deleting a reaction that does exist
- Client.MustGeneric(Client.SaveReaction(channel.Id, reaction1))
- if err := Client.DeleteReaction(channel.Id, reaction1); err != nil {
- t.Fatal(err)
- }
-
- if reactions := Client.MustGeneric(Client.ListReactions(channel.Id, post.Id)).([]*model.Reaction); len(reactions) != 0 {
- t.Fatal("should've deleted reaction")
- }
-
- // deleting one reaction when a post has multiple
- reaction2 := &model.Reaction{
- UserId: user.Id,
- PostId: post.Id,
- EmojiName: "sad",
- }
- reaction1 = Client.MustGeneric(Client.SaveReaction(channel.Id, reaction1)).(*model.Reaction)
- reaction2 = Client.MustGeneric(Client.SaveReaction(channel.Id, reaction2)).(*model.Reaction)
- if err := Client.DeleteReaction(channel.Id, reaction2); err != nil {
- t.Fatal(err)
- }
-
- if reactions := Client.MustGeneric(Client.ListReactions(channel.Id, post.Id)).([]*model.Reaction); len(reactions) != 1 || *reactions[0] != *reaction1 {
- t.Fatal("should've deleted only one reaction")
- }
-
- // deleting a reaction made by another user
- reaction3 := &model.Reaction{
- UserId: user2.Id,
- PostId: post.Id,
- EmojiName: "smile",
- }
-
- th.LoginBasic2()
- Client.Must(Client.JoinChannel(channel.Id))
- reaction3 = Client.MustGeneric(Client.SaveReaction(channel.Id, reaction3)).(*model.Reaction)
-
- th.LoginBasic()
- if err := Client.DeleteReaction(channel.Id, reaction3); err == nil {
- t.Fatal("should've failed to delete another user's reaction")
- }
-
- // deleting a reaction for a post we can't see
- channel2 := th.CreateChannel(th.BasicClient, th.BasicTeam)
- post2 := th.CreatePost(th.BasicClient, channel2)
-
- reaction4 := &model.Reaction{
- UserId: user.Id,
- PostId: post2.Id,
- EmojiName: "smile",
- }
-
- reaction4 = Client.MustGeneric(Client.SaveReaction(channel2.Id, reaction4)).(*model.Reaction)
- Client.Must(Client.LeaveChannel(channel2.Id))
-
- if err := Client.DeleteReaction(channel2.Id, reaction4); err == nil {
- t.Fatal("should've failed to delete a reaction from a channel we're not in")
- }
-
- // deleting a reaction for a post with the wrong channel
- channel3 := th.CreateChannel(th.BasicClient, th.BasicTeam)
-
- reaction5 := &model.Reaction{
- UserId: user.Id,
- PostId: post.Id,
- EmojiName: "happy",
- }
- if _, err := Client.SaveReaction(channel3.Id, reaction5); err == nil {
- t.Fatal("should've failed to save reaction to a post that isn't in the given channel")
- }
-}
-
-func TestListReactions(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- Client := th.BasicClient
-
- user := th.BasicUser
- user2 := th.BasicUser2
-
- channel := th.BasicChannel
-
- post := th.BasicPost
-
- userReactions := []*model.Reaction{
- {
- UserId: user.Id,
- PostId: post.Id,
- EmojiName: "smile",
- },
- {
- UserId: user.Id,
- PostId: post.Id,
- EmojiName: "happy",
- },
- {
- UserId: user.Id,
- PostId: post.Id,
- EmojiName: "sad",
- },
- }
-
- for i, reaction := range userReactions {
- userReactions[i] = Client.MustGeneric(Client.SaveReaction(channel.Id, reaction)).(*model.Reaction)
- }
-
- th.LoginBasic2()
- Client.Must(Client.JoinChannel(channel.Id))
-
- userReactions2 := []*model.Reaction{
- {
- UserId: user2.Id,
- PostId: post.Id,
- EmojiName: "smile",
- },
- {
- UserId: user2.Id,
- PostId: post.Id,
- EmojiName: "sad",
- },
- }
-
- for i, reaction := range userReactions2 {
- userReactions2[i] = Client.MustGeneric(Client.SaveReaction(channel.Id, reaction)).(*model.Reaction)
- }
-
- if reactions, err := Client.ListReactions(channel.Id, post.Id); err != nil {
- t.Fatal(err)
- } else if len(reactions) != 5 {
- t.Fatal("should've returned 5 reactions")
- } else {
- checkForReaction := func(expected *model.Reaction) {
- found := false
-
- for _, reaction := range reactions {
- if *reaction == *expected {
- found = true
- break
- }
- }
-
- if !found {
- t.Fatalf("didn't return expected reaction %v", *expected)
- }
- }
-
- for _, reaction := range userReactions {
- checkForReaction(reaction)
- }
-
- for _, reaction := range userReactions2 {
- checkForReaction(reaction)
- }
- }
-}
diff --git a/api/status.go b/api/status.go
deleted file mode 100644
index e1e4de522..000000000
--- a/api/status.go
+++ /dev/null
@@ -1,37 +0,0 @@
-// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-package api
-
-import (
- "net/http"
-
- "github.com/mattermost/mattermost-server/model"
-)
-
-func (api *API) InitStatus() {
- api.BaseRoutes.Users.Handle("/status", api.ApiUserRequired(getStatusesHttp)).Methods("GET")
- api.BaseRoutes.Users.Handle("/status/ids", api.ApiUserRequired(getStatusesByIdsHttp)).Methods("POST")
-}
-
-func getStatusesHttp(c *Context, w http.ResponseWriter, r *http.Request) {
- statusMap := model.StatusMapToInterfaceMap(c.App.GetAllStatuses())
- w.Write([]byte(model.StringInterfaceToJson(statusMap)))
-}
-
-func getStatusesByIdsHttp(c *Context, w http.ResponseWriter, r *http.Request) {
- userIds := model.ArrayFromJson(r.Body)
-
- if len(userIds) == 0 {
- c.SetInvalidParam("getStatusesByIdsHttp", "user_ids")
- return
- }
-
- statusMap, err := c.App.GetStatusesByIds(userIds)
- if err != nil {
- c.Err = err
- return
- }
-
- w.Write([]byte(model.StringInterfaceToJson(statusMap)))
-}
diff --git a/api/status_test.go b/api/status_test.go
deleted file mode 100644
index 6a0ba3937..000000000
--- a/api/status_test.go
+++ /dev/null
@@ -1,234 +0,0 @@
-// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-package api
-
-import (
- "strings"
- "testing"
- "time"
-
- "github.com/mattermost/mattermost-server/model"
- "github.com/mattermost/mattermost-server/store"
-)
-
-func TestStatuses(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- Client := th.BasicClient
- WebSocketClient, err := th.CreateWebSocketClient()
- if err != nil {
- t.Fatal(err)
- }
- defer WebSocketClient.Close()
- WebSocketClient.Listen()
-
- time.Sleep(300 * time.Millisecond)
- if resp := <-WebSocketClient.ResponseChannel; resp.Status != model.STATUS_OK {
- t.Fatal("should have responded OK to authentication challenge")
- }
-
- team := model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
- rteam, _ := Client.CreateTeam(&team)
-
- user := model.User{Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "passwd1"}
- ruser := Client.Must(Client.CreateUser(&user, "")).Data.(*model.User)
- th.LinkUserToTeam(ruser, rteam.Data.(*model.Team))
- store.Must(th.App.Srv.Store.User().VerifyEmail(ruser.Id))
-
- user2 := model.User{Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "passwd1"}
- ruser2 := Client.Must(Client.CreateUser(&user2, "")).Data.(*model.User)
- th.LinkUserToTeam(ruser2, rteam.Data.(*model.Team))
- store.Must(th.App.Srv.Store.User().VerifyEmail(ruser2.Id))
-
- Client.Login(user.Email, user.Password)
- Client.SetTeamId(team.Id)
-
- r1, err := Client.GetStatuses()
- if err != nil {
- t.Fatal(err)
- }
-
- statuses := r1.Data.(map[string]string)
-
- for _, status := range statuses {
- if status != model.STATUS_OFFLINE && status != model.STATUS_AWAY && status != model.STATUS_ONLINE {
- t.Fatal("one of the statuses had an invalid value")
- }
- }
-
- th.LoginBasic2()
-
- WebSocketClient2, err2 := th.CreateWebSocketClient()
- if err2 != nil {
- t.Fatal(err2)
- }
-
- time.Sleep(1000 * time.Millisecond)
-
- WebSocketClient.GetStatuses()
- if resp := <-WebSocketClient.ResponseChannel; resp.Error != nil {
- t.Fatal(resp.Error)
- } else {
- if resp.SeqReply != WebSocketClient.Sequence-1 {
- t.Fatal("bad sequence number")
- }
-
- for _, status := range resp.Data {
- if status != model.STATUS_OFFLINE && status != model.STATUS_AWAY && status != model.STATUS_ONLINE {
- t.Fatal("one of the statuses had an invalid value")
- }
- }
-
- if status, ok := resp.Data[th.BasicUser2.Id]; !ok {
- t.Log(resp.Data)
- t.Fatal("should have had user status")
- } else if status != model.STATUS_ONLINE {
- t.Log(status)
- t.Fatal("status should have been online")
- }
- }
-
- WebSocketClient.GetStatusesByIds([]string{th.BasicUser2.Id})
- if resp := <-WebSocketClient.ResponseChannel; resp.Error != nil {
- t.Fatal(resp.Error)
- } else {
- if resp.SeqReply != WebSocketClient.Sequence-1 {
- t.Fatal("bad sequence number")
- }
-
- for _, status := range resp.Data {
- if status != model.STATUS_OFFLINE && status != model.STATUS_AWAY && status != model.STATUS_ONLINE {
- t.Fatal("one of the statuses had an invalid value")
- }
- }
-
- if status, ok := resp.Data[th.BasicUser2.Id]; !ok {
- t.Log(len(resp.Data))
- t.Fatal("should have had user status")
- } else if status != model.STATUS_ONLINE {
- t.Log(status)
- t.Fatal("status should have been online")
- } else if len(resp.Data) != 1 {
- t.Fatal("only 1 status should be returned")
- }
- }
-
- WebSocketClient.GetStatusesByIds([]string{ruser2.Id, "junk"})
- if resp := <-WebSocketClient.ResponseChannel; resp.Error != nil {
- t.Fatal(resp.Error)
- } else {
- if resp.SeqReply != WebSocketClient.Sequence-1 {
- t.Fatal("bad sequence number")
- }
-
- if len(resp.Data) != 2 {
- t.Fatal("2 statuses should be returned")
- }
- }
-
- WebSocketClient.GetStatusesByIds([]string{})
- if resp := <-WebSocketClient.ResponseChannel; resp.Error == nil {
- if resp.SeqReply != WebSocketClient.Sequence-1 {
- t.Fatal("bad sequence number")
- }
- t.Fatal("should have errored - empty user ids")
- }
-
- WebSocketClient2.Close()
-
- th.App.SetStatusAwayIfNeeded(th.BasicUser.Id, false)
-
- awayTimeout := *th.App.Config().TeamSettings.UserStatusAwayTimeout
- defer func() {
- th.App.UpdateConfig(func(cfg *model.Config) { *cfg.TeamSettings.UserStatusAwayTimeout = awayTimeout })
- }()
- th.App.UpdateConfig(func(cfg *model.Config) { *cfg.TeamSettings.UserStatusAwayTimeout = 1 })
-
- time.Sleep(1500 * time.Millisecond)
-
- th.App.SetStatusAwayIfNeeded(th.BasicUser.Id, false)
- th.App.SetStatusOnline(th.BasicUser.Id, "junk", false)
-
- time.Sleep(1500 * time.Millisecond)
-
- WebSocketClient.GetStatuses()
- if resp := <-WebSocketClient.ResponseChannel; resp.Error != nil {
- t.Fatal(resp.Error)
- } else {
- if resp.SeqReply != WebSocketClient.Sequence-1 {
- t.Fatal("bad sequence number")
- }
-
- if _, ok := resp.Data[th.BasicUser2.Id]; ok {
- t.Fatal("should not have had user status")
- }
- }
-
- stop := make(chan bool)
- onlineHit := false
- awayHit := false
-
- go func() {
- for {
- select {
- case resp := <-WebSocketClient.EventChannel:
- if resp.Event == model.WEBSOCKET_EVENT_STATUS_CHANGE && resp.Data["user_id"].(string) == th.BasicUser.Id {
- status := resp.Data["status"].(string)
- if status == model.STATUS_ONLINE {
- onlineHit = true
- } else if status == model.STATUS_AWAY {
- awayHit = true
- }
- }
- case <-stop:
- return
- }
- }
- }()
-
- time.Sleep(500 * time.Millisecond)
-
- stop <- true
-
- if !onlineHit {
- t.Fatal("didn't get online event")
- }
- if !awayHit {
- t.Fatal("didn't get away event")
- }
-
- time.Sleep(500 * time.Millisecond)
-
- WebSocketClient.Close()
-}
-
-func TestGetStatusesByIds(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- Client := th.BasicClient
-
- if result, err := Client.GetStatusesByIds([]string{th.BasicUser.Id}); err != nil {
- t.Fatal(err)
- } else {
- statuses := result.Data.(map[string]string)
- if len(statuses) != 1 {
- t.Fatal("should only have 1 status")
- }
- }
-
- if result, err := Client.GetStatusesByIds([]string{th.BasicUser.Id, th.BasicUser2.Id, "junk"}); err != nil {
- t.Fatal(err)
- } else {
- statuses := result.Data.(map[string]string)
- if len(statuses) != 3 {
- t.Fatal("should have 3 statuses")
- }
- }
-
- if _, err := Client.GetStatusesByIds([]string{}); err == nil {
- t.Fatal("should have errored")
- }
-}
diff --git a/api/team.go b/api/team.go
deleted file mode 100644
index c3eaab128..000000000
--- a/api/team.go
+++ /dev/null
@@ -1,543 +0,0 @@
-// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-package api
-
-import (
- "bytes"
- "io"
- "net/http"
- "strconv"
- "strings"
-
- "github.com/gorilla/mux"
-
- "github.com/mattermost/mattermost-server/model"
-)
-
-func (api *API) InitTeam() {
- api.BaseRoutes.Teams.Handle("/create", api.ApiUserRequired(createTeam)).Methods("POST")
- api.BaseRoutes.Teams.Handle("/all", api.ApiUserRequired(getAll)).Methods("GET")
- api.BaseRoutes.Teams.Handle("/all_team_listings", api.ApiUserRequired(GetAllTeamListings)).Methods("GET")
- api.BaseRoutes.Teams.Handle("/get_invite_info", api.ApiAppHandler(getInviteInfo)).Methods("POST")
- api.BaseRoutes.Teams.Handle("/find_team_by_name", api.ApiUserRequired(findTeamByName)).Methods("POST")
- api.BaseRoutes.Teams.Handle("/name/{team_name:[A-Za-z0-9\\-]+}", api.ApiUserRequired(getTeamByName)).Methods("GET")
- api.BaseRoutes.Teams.Handle("/members", api.ApiUserRequired(getMyTeamMembers)).Methods("GET")
- api.BaseRoutes.Teams.Handle("/unread", api.ApiUserRequired(getMyTeamsUnread)).Methods("GET")
-
- api.BaseRoutes.NeedTeam.Handle("/me", api.ApiUserRequired(getMyTeam)).Methods("GET")
- api.BaseRoutes.NeedTeam.Handle("/stats", api.ApiUserRequired(getTeamStats)).Methods("GET")
- api.BaseRoutes.NeedTeam.Handle("/members/{offset:[0-9]+}/{limit:[0-9]+}", api.ApiUserRequired(getTeamMembers)).Methods("GET")
- api.BaseRoutes.NeedTeam.Handle("/members/ids", api.ApiUserRequired(getTeamMembersByIds)).Methods("POST")
- api.BaseRoutes.NeedTeam.Handle("/members/{user_id:[A-Za-z0-9]+}", api.ApiUserRequired(getTeamMember)).Methods("GET")
- api.BaseRoutes.NeedTeam.Handle("/update", api.ApiUserRequired(updateTeam)).Methods("POST")
- api.BaseRoutes.NeedTeam.Handle("/update_member_roles", api.ApiUserRequired(updateMemberRoles)).Methods("POST")
-
- api.BaseRoutes.NeedTeam.Handle("/invite_members", api.ApiUserRequired(inviteMembers)).Methods("POST")
-
- api.BaseRoutes.NeedTeam.Handle("/add_user_to_team", api.ApiUserRequired(addUserToTeam)).Methods("POST")
- api.BaseRoutes.NeedTeam.Handle("/remove_user_from_team", api.ApiUserRequired(removeUserFromTeam)).Methods("POST")
-
- // These should be moved to the global admin console
- api.BaseRoutes.NeedTeam.Handle("/import_team", api.ApiUserRequired(importTeam)).Methods("POST")
- api.BaseRoutes.Teams.Handle("/add_user_to_team_from_invite", api.ApiUserRequiredMfa(addUserToTeamFromInvite)).Methods("POST")
-}
-
-func createTeam(c *Context, w http.ResponseWriter, r *http.Request) {
- team := model.TeamFromJson(r.Body)
-
- if team == nil {
- c.SetInvalidParam("createTeam", "team")
- return
- }
-
- if !c.App.SessionHasPermissionTo(c.Session, model.PERMISSION_CREATE_TEAM) {
- c.Err = model.NewAppError("createTeam", "api.team.is_team_creation_allowed.disabled.app_error", nil, "", http.StatusForbidden)
- return
- }
-
- rteam, err := c.App.CreateTeamWithUser(team, c.Session.UserId)
- if err != nil {
- c.Err = err
- return
- }
-
- // Don't sanitize the team here since the user will be a team admin and their session won't reflect that yet
-
- w.Write([]byte(rteam.ToJson()))
-}
-
-func GetAllTeamListings(c *Context, w http.ResponseWriter, r *http.Request) {
- var teams []*model.Team
- var err *model.AppError
-
- if teams, err = c.App.GetAllOpenTeams(); err != nil {
- c.Err = err
- return
- }
-
- m := make(map[string]*model.Team)
- for _, v := range teams {
- m[v.Id] = v
- }
-
- sanitizeTeamMap(c, m)
-
- w.Write([]byte(model.TeamMapToJson(m)))
-}
-
-// Gets all teams which the current user can has access to. If the user is a System Admin, this will be all teams
-// on the server. Otherwise, it will only be the teams of which the user is a member.
-func getAll(c *Context, w http.ResponseWriter, r *http.Request) {
- var teams []*model.Team
- var err *model.AppError
-
- if c.App.HasPermissionTo(c.Session.UserId, model.PERMISSION_MANAGE_SYSTEM) {
- teams, err = c.App.GetAllTeams()
- } else {
- teams, err = c.App.GetTeamsForUser(c.Session.UserId)
- }
-
- if err != nil {
- c.Err = err
- return
- }
-
- m := make(map[string]*model.Team)
- for _, v := range teams {
- m[v.Id] = v
- }
-
- sanitizeTeamMap(c, m)
-
- w.Write([]byte(model.TeamMapToJson(m)))
-}
-
-func inviteMembers(c *Context, w http.ResponseWriter, r *http.Request) {
- invites := model.InvitesFromJson(r.Body)
-
- if !c.App.SessionHasPermissionToTeam(c.Session, c.TeamId, model.PERMISSION_INVITE_USER) {
- c.SetPermissionError(model.PERMISSION_INVITE_USER)
- return
- }
-
- if !c.App.SessionHasPermissionToTeam(c.Session, c.TeamId, model.PERMISSION_ADD_USER_TO_TEAM) {
- c.SetPermissionError(model.PERMISSION_INVITE_USER)
- return
- }
-
- if err := c.App.InviteNewUsersToTeam(invites.ToEmailList(), c.TeamId, c.Session.UserId); err != nil {
- c.Err = err
- return
- }
-
- w.Write([]byte(invites.ToJson()))
-}
-
-func addUserToTeam(c *Context, w http.ResponseWriter, r *http.Request) {
- params := model.MapFromJson(r.Body)
- userId := params["user_id"]
-
- if len(userId) != 26 {
- c.SetInvalidParam("addUserToTeam", "user_id")
- return
- }
-
- if !c.App.SessionHasPermissionToTeam(c.Session, c.TeamId, model.PERMISSION_ADD_USER_TO_TEAM) {
- c.SetPermissionError(model.PERMISSION_ADD_USER_TO_TEAM)
- return
- }
-
- if _, err := c.App.AddUserToTeam(c.TeamId, userId, ""); err != nil {
- c.Err = err
- return
- }
-
- w.Write([]byte(model.MapToJson(params)))
-}
-
-func removeUserFromTeam(c *Context, w http.ResponseWriter, r *http.Request) {
- params := model.MapFromJson(r.Body)
- userId := params["user_id"]
-
- if len(userId) != 26 {
- c.SetInvalidParam("removeUserFromTeam", "user_id")
- return
- }
-
- if c.Session.UserId != userId {
- if !c.App.SessionHasPermissionToTeam(c.Session, c.TeamId, model.PERMISSION_REMOVE_USER_FROM_TEAM) {
- c.SetPermissionError(model.PERMISSION_REMOVE_USER_FROM_TEAM)
- return
- }
- }
-
- if err := c.App.RemoveUserFromTeam(c.TeamId, userId, c.Session.UserId); err != nil {
- c.Err = err
- return
- }
-
- w.Write([]byte(model.MapToJson(params)))
-}
-
-func addUserToTeamFromInvite(c *Context, w http.ResponseWriter, r *http.Request) {
- params := model.MapFromJson(r.Body)
- tokenId := params["token"]
- inviteId := params["invite_id"]
-
- var team *model.Team
- var err *model.AppError
-
- if len(tokenId) > 0 {
- team, err = c.App.AddUserToTeamByToken(c.Session.UserId, tokenId)
- } else if len(inviteId) > 0 {
- team, err = c.App.AddUserToTeamByInviteId(inviteId, c.Session.UserId)
- } else {
- c.Err = model.NewAppError("addUserToTeamFromInvite", "api.user.create_user.signup_link_invalid.app_error", nil, "", http.StatusBadRequest)
- return
- }
-
- if err != nil {
- c.Err = err
- return
- }
-
- c.App.SanitizeTeam(c.Session, team)
-
- w.Write([]byte(team.ToJson()))
-}
-
-func findTeamByName(c *Context, w http.ResponseWriter, r *http.Request) {
-
- m := model.MapFromJson(r.Body)
- name := strings.ToLower(strings.TrimSpace(m["name"]))
-
- found := c.App.FindTeamByName(name)
-
- if found {
- w.Write([]byte("true"))
- } else {
- w.Write([]byte("false"))
- }
-}
-
-func getTeamByName(c *Context, w http.ResponseWriter, r *http.Request) {
- params := mux.Vars(r)
- teamname := params["team_name"]
-
- if team, err := c.App.GetTeamByName(teamname); err != nil {
- c.Err = err
- return
- } else {
- if (!team.AllowOpenInvite || team.Type != model.TEAM_OPEN) && c.Session.GetTeamByTeamId(team.Id) == nil {
- if !c.App.SessionHasPermissionTo(c.Session, model.PERMISSION_MANAGE_SYSTEM) {
- c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM)
- return
- }
- }
-
- c.App.SanitizeTeam(c.Session, team)
-
- w.Write([]byte(team.ToJson()))
- return
- }
-}
-
-func getMyTeamMembers(c *Context, w http.ResponseWriter, r *http.Request) {
- if len(c.Session.TeamMembers) > 0 {
- w.Write([]byte(model.TeamMembersToJson(c.Session.TeamMembers)))
- } else {
- if members, err := c.App.GetTeamMembersForUser(c.Session.UserId); err != nil {
- c.Err = err
- return
- } else {
- w.Write([]byte(model.TeamMembersToJson(members)))
- }
- }
-}
-
-func getMyTeamsUnread(c *Context, w http.ResponseWriter, r *http.Request) {
- teamId := r.URL.Query().Get("id")
-
- if unreads, err := c.App.GetTeamsUnreadForUser(teamId, c.Session.UserId); err != nil {
- c.Err = err
- return
- } else {
- w.Write([]byte(model.TeamsUnreadToJson(unreads)))
- }
-}
-
-func updateTeam(c *Context, w http.ResponseWriter, r *http.Request) {
-
- team := model.TeamFromJson(r.Body)
- if team == nil {
- c.SetInvalidParam("updateTeam", "team")
- return
- }
-
- team.Id = c.TeamId
-
- if !c.App.SessionHasPermissionToTeam(c.Session, team.Id, model.PERMISSION_MANAGE_TEAM) {
- c.SetPermissionError(model.PERMISSION_MANAGE_TEAM)
- return
- }
-
- var err *model.AppError
- var updatedTeam *model.Team
-
- updatedTeam, err = c.App.UpdateTeam(team)
- if err != nil {
- c.Err = err
- return
- }
-
- c.App.SanitizeTeam(c.Session, updatedTeam)
-
- w.Write([]byte(updatedTeam.ToJson()))
-}
-
-func updateMemberRoles(c *Context, w http.ResponseWriter, r *http.Request) {
- props := model.MapFromJson(r.Body)
-
- userId := props["user_id"]
- if len(userId) != 26 {
- c.SetInvalidParam("updateMemberRoles", "user_id")
- return
- }
-
- teamId := c.TeamId
-
- newRoles := props["new_roles"]
- if !(model.IsValidUserRoles(newRoles)) {
- c.SetInvalidParam("updateMemberRoles", "new_roles")
- return
- }
-
- if !c.App.SessionHasPermissionToTeam(c.Session, teamId, model.PERMISSION_MANAGE_TEAM_ROLES) {
- c.SetPermissionError(model.PERMISSION_MANAGE_TEAM_ROLES)
- return
- }
-
- if _, err := c.App.UpdateTeamMemberRoles(teamId, userId, newRoles); err != nil {
- c.Err = err
- return
- }
-
- rdata := map[string]string{}
- rdata["status"] = "ok"
- w.Write([]byte(model.MapToJson(rdata)))
-}
-
-func getMyTeam(c *Context, w http.ResponseWriter, r *http.Request) {
-
- if len(c.TeamId) == 0 {
- return
- }
-
- if team, err := c.App.GetTeam(c.TeamId); err != nil {
- c.Err = err
- return
- } else if c.HandleEtag(team.Etag(), "Get My Team", w, r) {
- return
- } else {
- w.Header().Set(model.HEADER_ETAG_SERVER, team.Etag())
-
- c.App.SanitizeTeam(c.Session, team)
-
- w.Write([]byte(team.ToJson()))
- return
- }
-}
-
-func getTeamStats(c *Context, w http.ResponseWriter, r *http.Request) {
- if c.Session.GetTeamByTeamId(c.TeamId) == nil {
- if !c.App.SessionHasPermissionTo(c.Session, model.PERMISSION_MANAGE_SYSTEM) {
- c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM)
- return
- }
- }
-
- stats, err := c.App.GetTeamStats(c.TeamId)
- if err != nil {
- c.Err = err
- return
- }
-
- w.Write([]byte(stats.ToJson()))
-}
-
-func importTeam(c *Context, w http.ResponseWriter, r *http.Request) {
- if !c.App.SessionHasPermissionToTeam(c.Session, c.TeamId, model.PERMISSION_IMPORT_TEAM) {
- c.SetPermissionError(model.PERMISSION_IMPORT_TEAM)
- return
- }
-
- if err := r.ParseMultipartForm(10000000); err != nil {
- c.Err = model.NewAppError("importTeam", "api.team.import_team.parse.app_error", nil, err.Error(), http.StatusBadRequest)
- return
- }
-
- importFromArray, ok := r.MultipartForm.Value["importFrom"]
- if !ok || len(importFromArray) < 1 {
- c.Err = model.NewAppError("importTeam", "api.team.import_team.no_import_from.app_error", nil, "", http.StatusBadRequest)
- return
- }
- importFrom := importFromArray[0]
-
- fileSizeStr, ok := r.MultipartForm.Value["filesize"]
- if !ok || len(fileSizeStr) < 1 {
- c.Err = model.NewAppError("importTeam", "api.team.import_team.unavailable.app_error", nil, "", http.StatusBadRequest)
- return
- }
-
- fileSize, err := strconv.ParseInt(fileSizeStr[0], 10, 64)
- if err != nil {
- c.Err = model.NewAppError("importTeam", "api.team.import_team.integer.app_error", nil, "", http.StatusBadRequest)
- return
- }
-
- fileInfoArray, ok := r.MultipartForm.File["file"]
- if !ok {
- c.Err = model.NewAppError("importTeam", "api.team.import_team.no_file.app_error", nil, "", http.StatusBadRequest)
- return
- }
-
- if len(fileInfoArray) <= 0 {
- c.Err = model.NewAppError("importTeam", "api.team.import_team.array.app_error", nil, "", http.StatusBadRequest)
- return
- }
-
- fileInfo := fileInfoArray[0]
-
- fileData, err := fileInfo.Open()
- if err != nil {
- c.Err = model.NewAppError("importTeam", "api.team.import_team.open.app_error", nil, err.Error(), http.StatusBadRequest)
- return
- }
- defer fileData.Close()
-
- var log *bytes.Buffer
- switch importFrom {
- case "slack":
- var err *model.AppError
- if err, log = c.App.SlackImport(fileData, fileSize, c.TeamId); err != nil {
- c.Err = err
- c.Err.StatusCode = http.StatusBadRequest
- }
- }
-
- w.Header().Set("Content-Disposition", "attachment; filename=MattermostImportLog.txt")
- w.Header().Set("Content-Type", "application/octet-stream")
- if c.Err != nil {
- w.WriteHeader(c.Err.StatusCode)
- }
- io.Copy(w, bytes.NewReader(log.Bytes()))
- //http.ServeContent(w, r, "MattermostImportLog.txt", time.Now(), bytes.NewReader(log.Bytes()))
-}
-
-func getInviteInfo(c *Context, w http.ResponseWriter, r *http.Request) {
- m := model.MapFromJson(r.Body)
- inviteId := m["invite_id"]
-
- if team, err := c.App.GetTeamByInviteId(inviteId); err != nil {
- c.Err = err
- return
- } else {
- if !(team.Type == model.TEAM_OPEN) {
- c.Err = model.NewAppError("getInviteInfo", "api.team.get_invite_info.not_open_team", nil, "id="+inviteId, http.StatusBadRequest)
- return
- }
-
- result := map[string]string{}
- result["display_name"] = team.DisplayName
- result["description"] = team.Description
- result["name"] = team.Name
- result["id"] = team.Id
- w.Write([]byte(model.MapToJson(result)))
- }
-}
-
-func getTeamMembers(c *Context, w http.ResponseWriter, r *http.Request) {
- params := mux.Vars(r)
-
- offset, err := strconv.Atoi(params["offset"])
- if err != nil {
- c.SetInvalidParam("getTeamMembers", "offset")
- return
- }
-
- limit, err := strconv.Atoi(params["limit"])
- if err != nil {
- c.SetInvalidParam("getTeamMembers", "limit")
- return
- }
-
- if c.Session.GetTeamByTeamId(c.TeamId) == nil {
- if !c.App.SessionHasPermissionToTeam(c.Session, c.TeamId, model.PERMISSION_MANAGE_SYSTEM) {
- c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM)
- return
- }
- }
-
- if members, err := c.App.GetTeamMembers(c.TeamId, offset, limit); err != nil {
- c.Err = err
- return
- } else {
- w.Write([]byte(model.TeamMembersToJson(members)))
- return
- }
-}
-
-func getTeamMember(c *Context, w http.ResponseWriter, r *http.Request) {
- params := mux.Vars(r)
-
- userId := params["user_id"]
- if len(userId) < 26 {
- c.SetInvalidParam("getTeamMember", "user_id")
- return
- }
-
- if c.Session.GetTeamByTeamId(c.TeamId) == nil {
- if !c.App.SessionHasPermissionToTeam(c.Session, c.TeamId, model.PERMISSION_MANAGE_SYSTEM) {
- c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM)
- return
- }
- }
-
- if member, err := c.App.GetTeamMember(c.TeamId, userId); err != nil {
- c.Err = err
- return
- } else {
- w.Write([]byte(member.ToJson()))
- return
- }
-}
-
-func getTeamMembersByIds(c *Context, w http.ResponseWriter, r *http.Request) {
- userIds := model.ArrayFromJson(r.Body)
- if len(userIds) == 0 {
- c.SetInvalidParam("getTeamMembersByIds", "user_ids")
- return
- }
-
- if c.Session.GetTeamByTeamId(c.TeamId) == nil {
- if !c.App.SessionHasPermissionToTeam(c.Session, c.TeamId, model.PERMISSION_MANAGE_SYSTEM) {
- c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM)
- return
- }
- }
-
- if members, err := c.App.GetTeamMembersByIds(c.TeamId, userIds); err != nil {
- c.Err = err
- return
- } else {
- w.Write([]byte(model.TeamMembersToJson(members)))
- return
- }
-}
-
-func sanitizeTeamMap(c *Context, teams map[string]*model.Team) {
- for _, team := range teams {
- c.App.SanitizeTeam(c.Session, team)
- }
-}
diff --git a/api/team_test.go b/api/team_test.go
deleted file mode 100644
index b7af0f1e8..000000000
--- a/api/team_test.go
+++ /dev/null
@@ -1,1196 +0,0 @@
-// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-package api
-
-import (
- "testing"
-
- "github.com/mattermost/mattermost-server/model"
- "github.com/mattermost/mattermost-server/store"
- "github.com/mattermost/mattermost-server/utils"
-)
-
-func TestCreateTeam(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- Client := th.BasicClient
-
- team := model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
- rteam, err := Client.CreateTeam(&team)
- if err != nil {
- t.Fatal(err)
- }
-
- user := &model.User{Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "passwd1"}
- user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
- th.LinkUserToTeam(user, rteam.Data.(*model.Team))
- store.Must(th.App.Srv.Store.User().VerifyEmail(user.Id))
-
- Client.Login(user.Email, "passwd1")
- Client.SetTeamId(rteam.Data.(*model.Team).Id)
-
- c1 := Client.Must(Client.GetChannels("")).Data.(*model.ChannelList)
- if len(*c1) != 2 {
- t.Fatal("default channels not created")
- }
-
- if rteam.Data.(*model.Team).DisplayName != team.DisplayName {
- t.Fatal("full name didn't match")
- }
-
- if _, err := Client.CreateTeam(rteam.Data.(*model.Team)); err == nil {
- t.Fatal("Cannot create an existing")
- }
-
- rteam.Data.(*model.Team).Id = ""
- if _, err := Client.CreateTeam(rteam.Data.(*model.Team)); err != nil {
- if err.Message != "A team with that name already exists" {
- t.Fatal(err)
- }
- }
-
- if _, err := Client.DoApiPost("/teams/create", "garbage"); err == nil {
- t.Fatal("should have been an error")
- }
-}
-
-func TestCreateTeamSanitization(t *testing.T) {
- th := Setup().InitBasic().InitSystemAdmin()
- defer th.TearDown()
-
- // Non-admin users can create a team, but they become a team admin by doing so
-
- t.Run("team admin", func(t *testing.T) {
- team := &model.Team{
- DisplayName: t.Name() + "_1",
- Name: GenerateTestTeamName(),
- Email: th.GenerateTestEmail(),
- Type: model.TEAM_OPEN,
- AllowedDomains: "simulator.amazonses.com",
- }
-
- if res, err := th.BasicClient.CreateTeam(team); err != nil {
- t.Fatal(err)
- } else if rteam := res.Data.(*model.Team); rteam.Email == "" {
- t.Fatal("should not have sanitized email")
- } else if rteam.AllowedDomains == "" {
- t.Fatal("should not have sanitized allowed domains")
- }
- })
-
- t.Run("system admin", func(t *testing.T) {
- team := &model.Team{
- DisplayName: t.Name() + "_2",
- Name: GenerateTestTeamName(),
- Email: th.GenerateTestEmail(),
- Type: model.TEAM_OPEN,
- AllowedDomains: "simulator.amazonses.com",
- }
-
- if res, err := th.SystemAdminClient.CreateTeam(team); err != nil {
- t.Fatal(err)
- } else if rteam := res.Data.(*model.Team); rteam.Email == "" {
- t.Fatal("should not have sanitized email")
- } else if rteam.AllowedDomains == "" {
- t.Fatal("should not have sanitized allowed domains")
- }
- })
-}
-
-func TestAddUserToTeam(t *testing.T) {
- th := Setup().InitSystemAdmin().InitBasic()
- defer th.TearDown()
-
- th.BasicClient.Logout()
-
- // Test adding a user to a team you are not a member of.
- th.SystemAdminClient.SetTeamId(th.BasicTeam.Id)
- th.SystemAdminClient.Must(th.SystemAdminClient.RemoveUserFromTeam(th.BasicTeam.Id, th.BasicUser2.Id))
-
- th.LoginBasic2()
-
- user2 := th.CreateUser(th.BasicClient)
-
- if _, err := th.BasicClient.AddUserToTeam(th.BasicTeam.Id, user2.Id); err == nil {
- t.Fatal("Should have failed because of not being a team member")
- }
-
- // Test adding a user to a team you are a member of.
- th.BasicClient.Logout()
- th.LoginBasic()
-
- if _, err := th.BasicClient.AddUserToTeam(th.BasicTeam.Id, user2.Id); err != nil {
- t.Fatal(err)
- }
-
- // Check it worked properly.
- if result, err := th.BasicClient.AddUserToTeam(th.BasicTeam.Id, user2.Id); err != nil {
- t.Fatal(err)
- } else {
- rm := result.Data.(map[string]string)
- if rm["user_id"] != user2.Id {
- t.Fatal("ids didn't match")
- }
- }
-
- if _, err := th.BasicClient.GetTeamMember(th.BasicTeam.Id, user2.Id); err != nil {
- t.Fatal(err)
- }
-
- // Check the appropriate permissions are enforced.
- defaultRolePermissions := th.SaveDefaultRolePermissions()
- defer func() {
- th.RestoreDefaultRolePermissions(defaultRolePermissions)
- }()
-
- // Set the config so that only team admins can add a user to a team.
- th.AddPermissionToRole(model.PERMISSION_INVITE_USER.Id, model.TEAM_ADMIN_ROLE_ID)
- th.AddPermissionToRole(model.PERMISSION_ADD_USER_TO_TEAM.Id, model.TEAM_ADMIN_ROLE_ID)
- th.RemovePermissionFromRole(model.PERMISSION_INVITE_USER.Id, model.TEAM_USER_ROLE_ID)
- th.RemovePermissionFromRole(model.PERMISSION_ADD_USER_TO_TEAM.Id, model.TEAM_USER_ROLE_ID)
-
- // Check that a regular user can't add someone to the team.
- user4 := th.CreateUser(th.BasicClient)
- if _, err := th.BasicClient.AddUserToTeam(th.BasicTeam.Id, user4.Id); err == nil {
- t.Fatal("should have failed due to permissions error")
- }
-
- // Should work as team admin.
- th.UpdateUserToTeamAdmin(th.BasicUser, th.BasicTeam)
- th.App.InvalidateAllCaches()
-
- // Change permission level to team user
- th.AddPermissionToRole(model.PERMISSION_INVITE_USER.Id, model.TEAM_USER_ROLE_ID)
- th.AddPermissionToRole(model.PERMISSION_ADD_USER_TO_TEAM.Id, model.TEAM_USER_ROLE_ID)
- th.RemovePermissionFromRole(model.PERMISSION_INVITE_USER.Id, model.TEAM_ADMIN_ROLE_ID)
- th.RemovePermissionFromRole(model.PERMISSION_ADD_USER_TO_TEAM.Id, model.TEAM_ADMIN_ROLE_ID)
-
- user5 := th.CreateUser(th.BasicClient)
- if _, err := th.BasicClient.AddUserToTeam(th.BasicTeam.Id, user5.Id); err != nil {
- t.Fatal(err)
- }
-}
-
-func TestRemoveUserFromTeam(t *testing.T) {
- th := Setup().InitSystemAdmin().InitBasic()
- defer th.TearDown()
-
- if _, err := th.BasicClient.RemoveUserFromTeam(th.SystemAdminTeam.Id, th.SystemAdminUser.Id); err == nil {
- t.Fatal("should fail not enough permissions")
- } else {
- if err.Id != "api.context.permissions.app_error" {
- t.Fatal("wrong error. Got: " + err.Id)
- }
- }
-
- if _, err := th.BasicClient.RemoveUserFromTeam("", th.SystemAdminUser.Id); err == nil {
- t.Fatal("should fail not enough permissions")
- } else {
- if err.Id != "api.context.permissions.app_error" {
- t.Fatal("wrong error")
- }
- }
-
- if _, err := th.BasicClient.RemoveUserFromTeam("", th.BasicUser.Id); err != nil {
- t.Fatal("should have removed the user from the team")
- }
-
- th.BasicClient.Logout()
- th.LoginSystemAdmin()
-
- th.SystemAdminClient.Must(th.SystemAdminClient.AddUserToTeam(th.BasicTeam.Id, th.BasicUser.Id))
-
- if _, err := th.SystemAdminClient.RemoveUserFromTeam(th.BasicTeam.Id, th.BasicUser.Id); err != nil {
- t.Fatal("should have removed the user from the team")
- }
-}
-
-func TestAddUserToTeamFromInvite(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- user2 := th.CreateUser(th.BasicClient)
- th.BasicClient.Must(th.BasicClient.Logout())
- th.BasicClient.Must(th.BasicClient.Login(user2.Email, user2.Password))
-
- if result, err := th.BasicClient.AddUserToTeamFromInvite("", "", th.BasicTeam.InviteId); err != nil {
- t.Fatal(err)
- } else {
- rtm := result.Data.(*model.Team)
- if rtm.Id != th.BasicTeam.Id {
- t.Fatal()
- }
- }
-}
-
-func TestGetAllTeams(t *testing.T) {
- th := Setup().InitBasic().InitSystemAdmin()
- defer th.TearDown()
-
- Client := th.BasicClient
-
- team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
- team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
-
- Client.Logout()
-
- user := &model.User{Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "passwd1"}
- user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
- th.LinkUserToTeam(user, team)
- store.Must(th.App.Srv.Store.User().VerifyEmail(user.Id))
-
- Client.Login(user.Email, "passwd1")
- Client.SetTeamId(team.Id)
-
- if r1, err := Client.GetAllTeams(); err != nil {
- t.Fatal(err)
- } else if teams := r1.Data.(map[string]*model.Team); len(teams) != 1 {
- t.Fatal("non admin users only get the teams that they're a member of")
- } else if receivedTeam, ok := teams[team.Id]; !ok || receivedTeam.Id != team.Id {
- t.Fatal("should've received team that the user is a member of")
- }
-
- if r1, err := th.SystemAdminClient.GetAllTeams(); err != nil {
- t.Fatal(err)
- } else if teams := r1.Data.(map[string]*model.Team); len(teams) == 1 {
- t.Fatal("admin users should receive all teams")
- } else if receivedTeam, ok := teams[team.Id]; !ok || receivedTeam.Id != team.Id {
- t.Fatal("admin should've received team that they aren't a member of")
- }
-
- Client.Logout()
- if _, err := Client.GetAllTeams(); err == nil {
- t.Fatal("Should have failed due to not being logged in.")
- }
-}
-
-func TestGetAllTeamsSanitization(t *testing.T) {
- th := Setup().InitBasic().InitSystemAdmin()
- defer th.TearDown()
-
- var team *model.Team
- if res, err := th.BasicClient.CreateTeam(&model.Team{
- DisplayName: t.Name() + "_1",
- Name: GenerateTestTeamName(),
- Email: th.GenerateTestEmail(),
- Type: model.TEAM_OPEN,
- AllowedDomains: "simulator.amazonses.com",
- }); err != nil {
- t.Fatal(err)
- } else {
- team = res.Data.(*model.Team)
- }
-
- var team2 *model.Team
- if res, err := th.SystemAdminClient.CreateTeam(&model.Team{
- DisplayName: t.Name() + "_2",
- Name: GenerateTestTeamName(),
- Email: th.GenerateTestEmail(),
- Type: model.TEAM_OPEN,
- AllowedDomains: "simulator.amazonses.com",
- }); err != nil {
- t.Fatal(err)
- } else {
- team2 = res.Data.(*model.Team)
- }
-
- t.Run("team admin/team user", func(t *testing.T) {
- if res, err := th.BasicClient.GetAllTeams(); err != nil {
- t.Fatal(err)
- } else {
- for _, rteam := range res.Data.(map[string]*model.Team) {
- if rteam.Id == team.Id {
- if rteam.Email == "" {
- t.Fatal("should not have sanitized email for team admin")
- } else if rteam.AllowedDomains == "" {
- t.Fatal("should not have sanitized allowed domains for team admin")
- }
- } else if rteam.Id == team2.Id {
- if rteam.Email != "" {
- t.Fatal("should've sanitized email for non-admin")
- } else if rteam.AllowedDomains != "" {
- t.Fatal("should've sanitized allowed domains for non-admin")
- }
- }
- }
- }
- })
-
- t.Run("system admin", func(t *testing.T) {
- if res, err := th.SystemAdminClient.GetAllTeams(); err != nil {
- t.Fatal(err)
- } else {
- for _, rteam := range res.Data.(map[string]*model.Team) {
- if rteam.Id != team.Id && rteam.Id != team2.Id {
- continue
- }
-
- if rteam.Email == "" {
- t.Fatal("should not have sanitized email")
- } else if rteam.AllowedDomains == "" {
- t.Fatal("should not have sanitized allowed domains")
- }
- }
- }
- })
-}
-
-func TestGetAllTeamListings(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- Client := th.BasicClient
-
- team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN, AllowOpenInvite: true}
- team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
-
- Client.Logout()
-
- user := &model.User{Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "passwd1"}
- user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
- th.LinkUserToTeam(user, team)
- store.Must(th.App.Srv.Store.User().VerifyEmail(user.Id))
-
- Client.Login(user.Email, "passwd1")
- Client.SetTeamId(team.Id)
-
- if r1, err := Client.GetAllTeamListings(); err != nil {
- t.Fatal(err)
- } else {
- teams := r1.Data.(map[string]*model.Team)
- if teams[team.Id].Name != team.Name {
- t.Fatal("team name doesn't match")
- }
- }
-
- th.App.UpdateUserRoles(user.Id, model.SYSTEM_ADMIN_ROLE_ID, false)
-
- Client.Login(user.Email, "passwd1")
- Client.SetTeamId(team.Id)
-
- if r1, err := Client.GetAllTeams(); err != nil {
- t.Fatal(err)
- } else {
- teams := r1.Data.(map[string]*model.Team)
- if teams[team.Id].Name != team.Name {
- t.Fatal("team name doesn't match")
- }
- }
-}
-
-func TestGetAllTeamListingsSanitization(t *testing.T) {
- th := Setup().InitBasic().InitSystemAdmin()
- defer th.TearDown()
-
- var team *model.Team
- if res, err := th.BasicClient.CreateTeam(&model.Team{
- DisplayName: t.Name() + "_1",
- Name: GenerateTestTeamName(),
- Email: th.GenerateTestEmail(),
- Type: model.TEAM_OPEN,
- AllowedDomains: "simulator.amazonses.com",
- AllowOpenInvite: true,
- }); err != nil {
- t.Fatal(err)
- } else {
- team = res.Data.(*model.Team)
- }
-
- var team2 *model.Team
- if res, err := th.SystemAdminClient.CreateTeam(&model.Team{
- DisplayName: t.Name() + "_2",
- Name: GenerateTestTeamName(),
- Email: th.GenerateTestEmail(),
- Type: model.TEAM_OPEN,
- AllowedDomains: "simulator.amazonses.com",
- AllowOpenInvite: true,
- }); err != nil {
- t.Fatal(err)
- } else {
- team2 = res.Data.(*model.Team)
- }
-
- t.Run("team admin/non-admin", func(t *testing.T) {
- if res, err := th.BasicClient.GetAllTeamListings(); err != nil {
- t.Fatal(err)
- } else {
- for _, rteam := range res.Data.(map[string]*model.Team) {
- if rteam.Id == team.Id {
- if rteam.Email == "" {
- t.Fatal("should not have sanitized email for team admin")
- } else if rteam.AllowedDomains == "" {
- t.Fatal("should not have sanitized allowed domains for team admin")
- }
- } else if rteam.Id == team2.Id {
- if rteam.Email != "" {
- t.Fatal("should've sanitized email for non-admin")
- } else if rteam.AllowedDomains != "" {
- t.Fatal("should've sanitized allowed domains for non-admin")
- }
- }
- }
- }
- })
-
- t.Run("system admin", func(t *testing.T) {
- if res, err := th.SystemAdminClient.GetAllTeamListings(); err != nil {
- t.Fatal(err)
- } else {
- for _, rteam := range res.Data.(map[string]*model.Team) {
- if rteam.Id != team.Id && rteam.Id != team2.Id {
- continue
- }
-
- if rteam.Email == "" {
- t.Fatal("should not have sanitized email")
- } else if rteam.AllowedDomains == "" {
- t.Fatal("should not have sanitized allowed domains")
- }
- }
- }
- })
-}
-
-func TestTeamPermDelete(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- Client := th.BasicClient
-
- team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
- team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
-
- Client.Logout()
-
- user1 := &model.User{Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "passwd1"}
- user1 = Client.Must(Client.CreateUser(user1, "")).Data.(*model.User)
- th.LinkUserToTeam(user1, team)
- store.Must(th.App.Srv.Store.User().VerifyEmail(user1.Id))
-
- Client.Login(user1.Email, "passwd1")
- Client.SetTeamId(team.Id)
-
- channel1 := &model.Channel{DisplayName: "TestGetPosts", Name: "zz" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
- channel1 = Client.Must(Client.CreateChannel(channel1)).Data.(*model.Channel)
-
- post1 := &model.Post{ChannelId: channel1.Id, Message: "search for post1"}
- post1 = Client.Must(Client.CreatePost(post1)).Data.(*model.Post)
-
- post2 := &model.Post{ChannelId: channel1.Id, Message: "search for post2"}
- post2 = Client.Must(Client.CreatePost(post2)).Data.(*model.Post)
-
- post3 := &model.Post{ChannelId: channel1.Id, Message: "#hashtag search for post3"}
- post3 = Client.Must(Client.CreatePost(post3)).Data.(*model.Post)
-
- post4 := &model.Post{ChannelId: channel1.Id, Message: "hashtag for post4"}
- post4 = Client.Must(Client.CreatePost(post4)).Data.(*model.Post)
-
- c := &Context{}
- c.RequestId = model.NewId()
- c.IpAddress = "test"
-
- err := th.App.PermanentDeleteTeam(team)
- if err != nil {
- t.Fatal(err)
- }
-
- Client.ClearOAuthToken()
-}
-
-func TestInviteMembers(t *testing.T) {
- th := Setup().InitBasic().InitSystemAdmin()
- defer th.TearDown()
-
- Client := th.BasicClient
-
- team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
- team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
-
- Client.Logout()
-
- user := &model.User{Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "passwd1"}
- user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
- th.LinkUserToTeam(user, team)
- store.Must(th.App.Srv.Store.User().VerifyEmail(user.Id))
-
- Client.Login(user.Email, "passwd1")
- Client.SetTeamId(team.Id)
-
- invite := make(map[string]string)
- invite["email"] = "success+" + model.NewId() + "@simulator.amazonses.com"
- invite["first_name"] = "Test"
- invite["last_name"] = "Guy"
- invites := &model.Invites{Invites: []map[string]string{invite}}
- invites.Invites = append(invites.Invites, invite)
-
- if _, err := Client.InviteMembers(invites); err != nil {
- t.Fatal(err)
- }
-
- invites2 := &model.Invites{Invites: []map[string]string{}}
- if _, err := Client.InviteMembers(invites2); err == nil {
- t.Fatal("Should have errored out on no invites to send")
- }
-
- // Check the appropriate permissions are enforced.
- defaultRolePermissions := th.SaveDefaultRolePermissions()
- defer func() {
- th.RestoreDefaultRolePermissions(defaultRolePermissions)
- }()
-
- // Set the config so that only team admins can add a user to a team.
- th.AddPermissionToRole(model.PERMISSION_INVITE_USER.Id, model.TEAM_ADMIN_ROLE_ID)
- th.AddPermissionToRole(model.PERMISSION_ADD_USER_TO_TEAM.Id, model.TEAM_ADMIN_ROLE_ID)
- th.RemovePermissionFromRole(model.PERMISSION_INVITE_USER.Id, model.TEAM_USER_ROLE_ID)
- th.RemovePermissionFromRole(model.PERMISSION_ADD_USER_TO_TEAM.Id, model.TEAM_USER_ROLE_ID)
-
- th.LoginBasic2()
- th.LinkUserToTeam(th.BasicUser2, team)
-
- if _, err := Client.InviteMembers(invites); err == nil {
- t.Fatal("should have errored not team admin and licensed")
- }
-
- th.UpdateUserToTeamAdmin(th.BasicUser2, team)
- Client.Logout()
- th.LoginBasic2()
- Client.SetTeamId(team.Id)
-
- if _, err := Client.InviteMembers(invites); err != nil {
- t.Fatal(err)
- }
-}
-
-func TestUpdateTeamDisplayName(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- Client := th.BasicClient
-
- team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "success+" + model.NewId() + "@simulator.amazonses.com", Type: model.TEAM_OPEN}
- team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
-
- Client.Logout()
-
- user2 := &model.User{Email: "success+" + model.NewId() + "@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "passwd1"}
- user2 = Client.Must(Client.CreateUser(user2, "")).Data.(*model.User)
- th.LinkUserToTeam(user2, team)
- store.Must(th.App.Srv.Store.User().VerifyEmail(user2.Id))
-
- Client.Login(user2.Email, "passwd1")
- Client.SetTeamId(team.Id)
-
- vteam := &model.Team{DisplayName: team.DisplayName, Name: team.Name, Email: team.Email, Type: team.Type}
- vteam.DisplayName = "NewName"
- if _, err := Client.UpdateTeam(vteam); err == nil {
- t.Fatal("Should have errored, not admin")
- }
-
- th.LoginBasic()
-
- vteam.DisplayName = ""
- if _, err := Client.UpdateTeam(vteam); err == nil {
- t.Fatal("Should have errored, empty name")
- }
-
- vteam.DisplayName = "NewName"
- if _, err := Client.UpdateTeam(vteam); err != nil {
- t.Fatal(err)
- }
-}
-
-func TestUpdateTeamSanitization(t *testing.T) {
- th := Setup().InitBasic().InitSystemAdmin()
- defer th.TearDown()
-
- var team *model.Team
- if res, err := th.BasicClient.CreateTeam(&model.Team{
- DisplayName: t.Name() + "_1",
- Name: GenerateTestTeamName(),
- Email: th.GenerateTestEmail(),
- Type: model.TEAM_OPEN,
- AllowedDomains: "simulator.amazonses.com",
- }); err != nil {
- t.Fatal(err)
- } else {
- team = res.Data.(*model.Team)
- }
-
- // Non-admin users cannot update the team
-
- t.Run("team admin", func(t *testing.T) {
- // API v3 always assumes you're updating the current team
- th.BasicClient.SetTeamId(team.Id)
-
- if res, err := th.BasicClient.UpdateTeam(team); err != nil {
- t.Fatal(err)
- } else if rteam := res.Data.(*model.Team); rteam.Email == "" {
- t.Fatal("should not have sanitized email for admin")
- } else if rteam.AllowedDomains == "" {
- t.Fatal("should not have sanitized allowed domains")
- }
- })
-
- t.Run("system admin", func(t *testing.T) {
- // API v3 always assumes you're updating the current team
- th.SystemAdminClient.SetTeamId(team.Id)
-
- if res, err := th.SystemAdminClient.UpdateTeam(team); err != nil {
- t.Fatal(err)
- } else if rteam := res.Data.(*model.Team); rteam.Email == "" {
- t.Fatal("should not have sanitized email for admin")
- } else if rteam.AllowedDomains == "" {
- t.Fatal("should not have sanitized allowed domains")
- }
- })
-}
-
-func TestFuzzyTeamCreate(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- Client := th.BasicClient
-
- for i := 0; i < len(utils.FUZZY_STRINGS_NAMES) || i < len(utils.FUZZY_STRINGS_EMAILS); i++ {
- testDisplayName := "Name"
- testEmail := "test@nowhere.com"
-
- if i < len(utils.FUZZY_STRINGS_NAMES) {
- testDisplayName = utils.FUZZY_STRINGS_NAMES[i]
- }
- if i < len(utils.FUZZY_STRINGS_EMAILS) {
- testEmail = utils.FUZZY_STRINGS_EMAILS[i]
- }
-
- team := model.Team{DisplayName: testDisplayName, Name: "z-z-" + model.NewId() + "a", Email: testEmail, Type: model.TEAM_OPEN}
-
- _, err := Client.CreateTeam(&team)
- if err != nil {
- t.Fatal(err)
- }
- }
-}
-
-func TestGetMyTeam(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- Client := th.BasicClient
-
- team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
- rteam, _ := Client.CreateTeam(team)
- team = rteam.Data.(*model.Team)
-
- Client.Logout()
-
- user := model.User{Email: "success+" + model.NewId() + "@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "passwd1"}
- ruser, _ := Client.CreateUser(&user, "")
- th.LinkUserToTeam(ruser.Data.(*model.User), rteam.Data.(*model.Team))
- store.Must(th.App.Srv.Store.User().VerifyEmail(ruser.Data.(*model.User).Id))
-
- Client.Login(user.Email, user.Password)
- Client.SetTeamId(team.Id)
-
- if result, err := Client.GetMyTeam(""); err != nil {
- t.Fatal(err)
- } else {
- if result.Data.(*model.Team).DisplayName != team.DisplayName {
- t.Fatal("team names did not match")
- }
- if result.Data.(*model.Team).Name != team.Name {
- t.Fatal("team domains did not match")
- }
- if result.Data.(*model.Team).Type != team.Type {
- t.Fatal("team types did not match")
- }
- }
-}
-
-func TestGetMyTeamSanitization(t *testing.T) {
- th := Setup().InitBasic().InitSystemAdmin()
- defer th.TearDown()
-
- var team *model.Team
- if res, err := th.BasicClient.CreateTeam(&model.Team{
- DisplayName: t.Name() + "_1",
- Name: GenerateTestTeamName(),
- Email: th.GenerateTestEmail(),
- Type: model.TEAM_OPEN,
- AllowedDomains: "simulator.amazonses.com",
- }); err != nil {
- t.Fatal(err)
- } else {
- team = res.Data.(*model.Team)
- }
-
- t.Run("team user", func(t *testing.T) {
- th.LinkUserToTeam(th.BasicUser2, team)
-
- client := th.CreateClient()
- client.Must(client.Login(th.BasicUser2.Email, th.BasicUser2.Password))
-
- client.SetTeamId(team.Id)
-
- if res, err := client.GetMyTeam(""); err != nil {
- t.Fatal(err)
- } else if rteam := res.Data.(*model.Team); rteam.Email != "" {
- t.Fatal("should've sanitized email")
- } else if rteam.AllowedDomains != "" {
- t.Fatal("should've sanitized allowed domains")
- }
- })
-
- t.Run("team admin", func(t *testing.T) {
- th.BasicClient.SetTeamId(team.Id)
-
- if res, err := th.BasicClient.GetMyTeam(""); err != nil {
- t.Fatal(err)
- } else if rteam := res.Data.(*model.Team); rteam.Email == "" {
- t.Fatal("should not have sanitized email")
- } else if rteam.AllowedDomains == "" {
- t.Fatal("should not have sanitized allowed domains")
- }
- })
-
- t.Run("system admin", func(t *testing.T) {
- th.SystemAdminClient.SetTeamId(team.Id)
-
- if res, err := th.SystemAdminClient.GetMyTeam(""); err != nil {
- t.Fatal(err)
- } else if rteam := res.Data.(*model.Team); rteam.Email == "" {
- t.Fatal("should not have sanitized email")
- } else if rteam.AllowedDomains == "" {
- t.Fatal("should not have sanitized allowed domains")
- }
- })
-}
-
-func TestGetTeamMembers(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- if result, err := th.BasicClient.GetTeamMembers(th.BasicTeam.Id, 0, 100); err != nil {
- t.Fatal(err)
- } else {
- members := result.Data.([]*model.TeamMember)
- if len(members) == 0 {
- t.Fatal("should have results")
- }
- }
-
- if _, err := th.BasicClient.GetTeamMembers("junk", 0, 100); err == nil {
- t.Fatal("should have errored - bad team id")
- }
-}
-
-func TestGetMyTeamMembers(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- if result, err := th.BasicClient.GetMyTeamMembers(); err != nil {
- t.Fatal(err)
- } else {
- members := result.Data.([]*model.TeamMember)
- if len(members) == 0 {
- t.Fatal("should have results")
- }
- }
-}
-
-func TestGetMyTeamsUnread(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- if result, err := th.BasicClient.GetMyTeamsUnread(""); err != nil {
- t.Fatal(err)
- } else {
- members := result.Data.([]*model.TeamUnread)
- if len(members) == 0 {
- t.Fatal("should have results")
- }
- }
-
- if result, err := th.BasicClient.GetMyTeamsUnread(th.BasicTeam.Id); err != nil {
- t.Fatal(err)
- } else {
- members := result.Data.([]*model.TeamUnread)
- if len(members) != 0 {
- t.Fatal("should not have results")
- }
- }
-}
-
-func TestGetTeamMember(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- if result, err := th.BasicClient.GetTeamMember(th.BasicTeam.Id, th.BasicUser.Id); err != nil {
- t.Fatal(err)
- } else {
- member := result.Data.(*model.TeamMember)
- if member == nil {
- t.Fatal("should be valid")
- }
- }
-
- if _, err := th.BasicClient.GetTeamMember("junk", th.BasicUser.Id); err == nil {
- t.Fatal("should have errored - bad team id")
- }
-
- if _, err := th.BasicClient.GetTeamMember(th.BasicTeam.Id, ""); err == nil {
- t.Fatal("should have errored - blank user id")
- }
-
- if _, err := th.BasicClient.GetTeamMember(th.BasicTeam.Id, "junk"); err == nil {
- t.Fatal("should have errored - bad user id")
- }
-
- if _, err := th.BasicClient.GetTeamMember(th.BasicTeam.Id, "12345678901234567890123456"); err == nil {
- t.Fatal("should have errored - bad user id")
- }
-}
-
-func TestGetTeamMembersByIds(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- if result, err := th.BasicClient.GetTeamMembersByIds(th.BasicTeam.Id, []string{th.BasicUser.Id}); err != nil {
- t.Fatal(err)
- } else {
- member := result.Data.([]*model.TeamMember)[0]
- if member.UserId != th.BasicUser.Id {
- t.Fatal("user id did not match")
- }
- if member.TeamId != th.BasicTeam.Id {
- t.Fatal("team id did not match")
- }
- }
-
- if result, err := th.BasicClient.GetTeamMembersByIds(th.BasicTeam.Id, []string{th.BasicUser.Id, th.BasicUser2.Id, model.NewId()}); err != nil {
- t.Fatal(err)
- } else {
- members := result.Data.([]*model.TeamMember)
- if len(members) != 2 {
- t.Fatal("length should have been 2")
- }
- }
-
- if _, err := th.BasicClient.GetTeamMembersByIds("junk", []string{th.BasicUser.Id}); err == nil {
- t.Fatal("should have errored - bad team id")
- }
-
- if _, err := th.BasicClient.GetTeamMembersByIds(th.BasicTeam.Id, []string{}); err == nil {
- t.Fatal("should have errored - empty user ids")
- }
-}
-
-func TestUpdateTeamMemberRoles(t *testing.T) {
- th := Setup().InitSystemAdmin().InitBasic()
- defer th.TearDown()
-
- th.SystemAdminClient.SetTeamId(th.BasicTeam.Id)
- th.LinkUserToTeam(th.SystemAdminUser, th.BasicTeam)
-
- const BASIC_MEMBER = "team_user"
- const TEAM_ADMIN = "team_user team_admin"
-
- // user 1 trying to promote user 2
- if _, err := th.BasicClient.UpdateTeamRoles(th.BasicUser2.Id, TEAM_ADMIN); err == nil {
- t.Fatal("Should have errored, not team admin")
- }
-
- // user 1 trying to promote themselves
- if _, err := th.BasicClient.UpdateTeamRoles(th.BasicUser.Id, TEAM_ADMIN); err == nil {
- t.Fatal("Should have errored, not team admin")
- }
-
- // user 1 trying to demote someone
- if _, err := th.BasicClient.UpdateTeamRoles(th.SystemAdminUser.Id, BASIC_MEMBER); err == nil {
- t.Fatal("Should have errored, not team admin")
- }
-
- // system admin promoting user1
- if _, err := th.SystemAdminClient.UpdateTeamRoles(th.BasicUser.Id, TEAM_ADMIN); err != nil {
- t.Fatal("Should have worked: " + err.Error())
- }
-
- // user 1 trying to promote user 2
- if _, err := th.BasicClient.UpdateTeamRoles(th.BasicUser2.Id, TEAM_ADMIN); err != nil {
- t.Fatal("Should have worked, user is team admin: " + th.BasicUser.Id)
- }
-
- // user 1 trying to demote user 2
- if _, err := th.BasicClient.UpdateTeamRoles(th.BasicUser2.Id, BASIC_MEMBER); err != nil {
- t.Fatal("Should have worked, user is team admin")
- }
-
- // user 1 trying to demote a system admin
- if _, err := th.BasicClient.UpdateTeamRoles(th.SystemAdminUser.Id, BASIC_MEMBER); err != nil {
- t.Fatal("Should have worked, user is team admin and has the ability to manage permissions on this team.")
- // Note to anyone who thinks this test is wrong:
- // This operation will not effect the system admin's permissions because they have global access to all teams.
- // Their team level permissions are irrelevant. A team admin should be able to manage team level permissions.
- }
-
- // System admins should be able to manipulate permission no matter what their team level permissions are.
- // systemAdmin trying to promote user 2
- if _, err := th.SystemAdminClient.UpdateTeamRoles(th.BasicUser2.Id, TEAM_ADMIN); err != nil {
- t.Fatal("Should have worked, user is system admin")
- }
-
- // system admin trying to demote user 2
- if _, err := th.SystemAdminClient.UpdateTeamRoles(th.BasicUser2.Id, BASIC_MEMBER); err != nil {
- t.Fatal("Should have worked, user is system admin")
- }
-
- // user 1 trying to demote himself
- if _, err := th.BasicClient.UpdateTeamRoles(th.BasicUser.Id, BASIC_MEMBER); err != nil {
- t.Fatal("Should have worked, user is team admin")
- }
-}
-
-func TestGetTeamStats(t *testing.T) {
- th := Setup().InitBasic().InitSystemAdmin()
- defer th.TearDown()
-
- Client := th.BasicClient
-
- if result, err := th.SystemAdminClient.GetTeamStats(th.BasicTeam.Id); err != nil {
- t.Fatal(err)
- } else {
- if result.Data.(*model.TeamStats).TotalMemberCount != 2 {
- t.Fatal("wrong count")
- }
-
- if result.Data.(*model.TeamStats).ActiveMemberCount != 2 {
- t.Fatal("wrong count")
- }
- }
-
- th.SystemAdminClient.Must(th.SystemAdminClient.UpdateActive(th.BasicUser2.Id, false))
-
- if result, err := th.SystemAdminClient.GetTeamStats(th.BasicTeam.Id); err != nil {
- t.Fatal(err)
- } else {
- if result.Data.(*model.TeamStats).TotalMemberCount != 2 {
- t.Fatal("wrong count")
- }
-
- if result.Data.(*model.TeamStats).ActiveMemberCount != 1 {
- t.Fatal("wrong count")
- }
- }
-
- if _, err := th.SystemAdminClient.GetTeamStats("junk"); err == nil {
- t.Fatal("should fail invalid teamid")
- } else {
- if err.Id != "store.sql_team.get.find.app_error" {
- t.Fatal("wrong error. Got: " + err.Id)
- }
- }
-
- if result, err := th.SystemAdminClient.GetTeamStats(th.BasicTeam.Id); err != nil {
- t.Fatal(err)
- } else {
- if result.Data.(*model.TeamStats).TotalMemberCount != 2 {
- t.Fatal("wrong count")
- }
- }
-
- user := model.User{Email: "success+" + model.NewId() + "@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "passwd1"}
- ruser, _ := Client.CreateUser(&user, "")
- store.Must(th.App.Srv.Store.User().VerifyEmail(ruser.Data.(*model.User).Id))
-
- Client.Login(user.Email, user.Password)
-
- if _, err := Client.GetTeamStats(th.BasicTeam.Id); err == nil {
- t.Fatal("should have errored - not on team")
- }
-}
-
-func TestUpdateTeamDescription(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- Client := th.BasicClient
-
- team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "success+" + model.NewId() + "@simulator.amazonses.com", Type: model.TEAM_OPEN}
- team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
-
- Client.Logout()
-
- user2 := &model.User{Email: "success+" + model.NewId() + "@simulator.amazonses.com", Nickname: "Jabba the Hutt", Password: "passwd1"}
- user2 = Client.Must(Client.CreateUser(user2, "")).Data.(*model.User)
- th.LinkUserToTeam(user2, team)
- store.Must(th.App.Srv.Store.User().VerifyEmail(user2.Id))
-
- Client.Login(user2.Email, "passwd1")
- Client.SetTeamId(team.Id)
-
- vteam := &model.Team{DisplayName: team.DisplayName, Name: team.Name, Description: team.Description, Email: team.Email, Type: team.Type}
- vteam.Description = "yommamma"
- if _, err := Client.UpdateTeam(vteam); err == nil {
- t.Fatal("Should have errored, not admin")
- }
-
- th.LoginBasic()
-
- vteam.Description = ""
- if _, err := Client.UpdateTeam(vteam); err != nil {
- t.Fatal("Should have errored, should save blank Description")
- }
-
- vteam.Description = "yommamma"
- if _, err := Client.UpdateTeam(vteam); err != nil {
- t.Fatal(err)
- }
-}
-
-func TestGetTeamByName(t *testing.T) {
- th := Setup().InitSystemAdmin().InitBasic()
- defer th.TearDown()
-
- Client := th.BasicClient
-
- team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "success+" + model.NewId() + "@simulator.amazonses.com", Type: model.TEAM_OPEN, AllowOpenInvite: false}
- team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
-
- team2 := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "success+" + model.NewId() + "@simulator.amazonses.com", Type: model.TEAM_OPEN, AllowOpenInvite: true}
- team2 = Client.Must(Client.CreateTeam(team2)).Data.(*model.Team)
-
- team3 := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "success+" + model.NewId() + "@simulator.amazonses.com", Type: model.TEAM_INVITE, AllowOpenInvite: true}
- team3 = Client.Must(Client.CreateTeam(team3)).Data.(*model.Team)
-
- if _, err := Client.GetTeamByName(team.Name); err != nil {
- t.Fatal("Failed to get team")
- }
-
- if _, err := Client.GetTeamByName("InvalidTeamName"); err == nil {
- t.Fatal("Should not exist this team")
- }
-
- if _, err := Client.GetTeamByName(team2.Name); err != nil {
- t.Fatal("Failed to get team")
- }
-
- Client.Must(Client.Logout())
-
- user2 := &model.User{Email: "success+" + model.NewId() + "@simulator.amazonses.com", Nickname: "Jabba the Hutt", Password: "passwd1"}
- user2 = Client.Must(Client.CreateUser(user2, "")).Data.(*model.User)
- store.Must(th.App.Srv.Store.User().VerifyEmail(user2.Id))
-
- Client.Login(user2.Email, "passwd1")
-
- // AllowInviteOpen is false and team is open and user is not part of the team
- if _, err := Client.GetTeamByName(team.Name); err == nil {
- t.Fatal("Should fail dont have permissions to get the team")
- }
-
- if _, err := Client.GetTeamByName("InvalidTeamName"); err == nil {
- t.Fatal("Should not exist this team")
- }
-
- // AllowInviteOpen is true and is open and user is not part of the team
- if _, err := Client.GetTeamByName(team2.Name); err != nil {
- t.Fatal("Should not fail team is open")
- }
-
- // AllowInviteOpen is true and is invite only and user is not part of the team
- if _, err := Client.GetTeamByName(team3.Name); err == nil {
- t.Fatal("Should fail team is invite only")
- }
-
- Client.Must(Client.Logout())
- th.BasicClient.Logout()
- th.LoginSystemAdmin()
-
- if _, err := th.SystemAdminClient.GetTeamByName(team.Name); err != nil {
- t.Fatal("Should not fail to get team the user is admin")
- }
-
- if _, err := th.SystemAdminClient.GetTeamByName(team2.Name); err != nil {
- t.Fatal("Should not fail to get team the user is admin and team is open")
- }
-
- if _, err := th.SystemAdminClient.GetTeamByName(team3.Name); err != nil {
- t.Fatal("Should not fail to get team the user is admin and team is invite")
- }
-
- if _, err := Client.GetTeamByName("InvalidTeamName"); err == nil {
- t.Fatal("Should not exist this team")
- }
-
- Client.Logout()
- if _, err := Client.GetTeamByName(th.BasicTeam.Name); err == nil {
- t.Fatal("Should have failed when not logged in.")
- }
-}
-
-func TestGetTeamByNameSanitization(t *testing.T) {
- th := Setup().InitBasic().InitSystemAdmin()
- defer th.TearDown()
-
- var team *model.Team
- if res, err := th.BasicClient.CreateTeam(&model.Team{
- DisplayName: t.Name() + "_1",
- Name: GenerateTestTeamName(),
- Email: th.GenerateTestEmail(),
- Type: model.TEAM_OPEN,
- AllowedDomains: "simulator.amazonses.com",
- }); err != nil {
- t.Fatal(err)
- } else {
- team = res.Data.(*model.Team)
- }
-
- t.Run("team user", func(t *testing.T) {
- th.LinkUserToTeam(th.BasicUser2, team)
-
- client := th.CreateClient()
- client.Must(client.Login(th.BasicUser2.Email, th.BasicUser2.Password))
-
- if res, err := client.GetTeamByName(team.Name); err != nil {
- t.Fatal(err)
- } else if rteam := res.Data.(*model.Team); rteam.Email != "" {
- t.Fatal("should've sanitized email")
- } else if rteam.AllowedDomains != "" {
- t.Fatal("should've sanitized allowed domains")
- }
- })
-
- t.Run("team admin", func(t *testing.T) {
- if res, err := th.BasicClient.GetTeamByName(team.Name); err != nil {
- t.Fatal(err)
- } else if rteam := res.Data.(*model.Team); rteam.Email == "" {
- t.Fatal("should not have sanitized email")
- } else if rteam.AllowedDomains == "" {
- t.Fatal("should not have sanitized allowed domains")
- }
- })
-
- t.Run("system admin", func(t *testing.T) {
- th.SystemAdminClient.SetTeamId(team.Id)
-
- if res, err := th.SystemAdminClient.GetTeamByName(team.Name); err != nil {
- t.Fatal(err)
- } else if rteam := res.Data.(*model.Team); rteam.Email == "" {
- t.Fatal("should not have sanitized email")
- } else if rteam.AllowedDomains == "" {
- t.Fatal("should not have sanitized allowed domains")
- }
- })
-}
-
-func TestFindTeamByName(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- Client := th.BasicClient
- Client.Logout()
-
- if _, err := Client.FindTeamByName(th.BasicTeam.Name); err == nil {
- t.Fatal("Should have failed when not logged in.")
- }
-}
diff --git a/api/user.go b/api/user.go
deleted file mode 100644
index 7592d1119..000000000
--- a/api/user.go
+++ /dev/null
@@ -1,1245 +0,0 @@
-// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-package api
-
-import (
- "fmt"
- "net/http"
- "strconv"
- "time"
-
- "github.com/gorilla/mux"
- "github.com/mattermost/mattermost-server/app"
- "github.com/mattermost/mattermost-server/mlog"
- "github.com/mattermost/mattermost-server/model"
- "github.com/mattermost/mattermost-server/store"
-)
-
-func (api *API) InitUser() {
- api.BaseRoutes.Users.Handle("/create", api.ApiAppHandler(createUser)).Methods("POST")
- api.BaseRoutes.Users.Handle("/update", api.ApiUserRequired(updateUser)).Methods("POST")
- api.BaseRoutes.Users.Handle("/update_active", api.ApiUserRequired(updateActive)).Methods("POST")
- api.BaseRoutes.Users.Handle("/update_notify", api.ApiUserRequired(updateUserNotify)).Methods("POST")
- api.BaseRoutes.Users.Handle("/newpassword", api.ApiUserRequired(updatePassword)).Methods("POST")
- api.BaseRoutes.Users.Handle("/send_password_reset", api.ApiAppHandler(sendPasswordReset)).Methods("POST")
- api.BaseRoutes.Users.Handle("/reset_password", api.ApiAppHandler(resetPassword)).Methods("POST")
- api.BaseRoutes.Users.Handle("/login", api.ApiAppHandler(login)).Methods("POST")
- api.BaseRoutes.Users.Handle("/logout", api.ApiAppHandler(logout)).Methods("POST")
- api.BaseRoutes.Users.Handle("/revoke_session", api.ApiUserRequired(revokeSession)).Methods("POST")
- api.BaseRoutes.Users.Handle("/attach_device", api.ApiUserRequired(attachDeviceId)).Methods("POST")
- //DEPRICATED FOR SECURITY USE APIV4 api.BaseRoutes.Users.Handle("/verify_email", ApiAppHandler(verifyEmail)).Methods("POST")
- //DEPRICATED FOR SECURITY USE APIV4 api.BaseRoutes.Users.Handle("/resend_verification", ApiAppHandler(resendVerification)).Methods("POST")
- api.BaseRoutes.Users.Handle("/newimage", api.ApiUserRequired(uploadProfileImage)).Methods("POST")
- api.BaseRoutes.Users.Handle("/me", api.ApiUserRequired(getMe)).Methods("GET")
- api.BaseRoutes.Users.Handle("/initial_load", api.ApiAppHandler(getInitialLoad)).Methods("GET")
- api.BaseRoutes.Users.Handle("/{offset:[0-9]+}/{limit:[0-9]+}", api.ApiUserRequired(getProfiles)).Methods("GET")
- api.BaseRoutes.NeedTeam.Handle("/users/{offset:[0-9]+}/{limit:[0-9]+}", api.ApiUserRequired(getProfilesInTeam)).Methods("GET")
- api.BaseRoutes.NeedChannel.Handle("/users/{offset:[0-9]+}/{limit:[0-9]+}", api.ApiUserRequired(getProfilesInChannel)).Methods("GET")
- api.BaseRoutes.NeedChannel.Handle("/users/not_in_channel/{offset:[0-9]+}/{limit:[0-9]+}", api.ApiUserRequired(getProfilesNotInChannel)).Methods("GET")
- api.BaseRoutes.Users.Handle("/search", api.ApiUserRequired(searchUsers)).Methods("POST")
- api.BaseRoutes.Users.Handle("/ids", api.ApiUserRequired(getProfilesByIds)).Methods("POST")
- api.BaseRoutes.Users.Handle("/autocomplete", api.ApiUserRequired(autocompleteUsers)).Methods("GET")
-
- api.BaseRoutes.NeedTeam.Handle("/users/autocomplete", api.ApiUserRequired(autocompleteUsersInTeam)).Methods("GET")
- api.BaseRoutes.NeedChannel.Handle("/users/autocomplete", api.ApiUserRequired(autocompleteUsersInChannel)).Methods("GET")
-
- api.BaseRoutes.Users.Handle("/mfa", api.ApiAppHandler(checkMfa)).Methods("POST")
- api.BaseRoutes.Users.Handle("/generate_mfa_secret", api.ApiUserRequiredMfa(generateMfaSecret)).Methods("GET")
- api.BaseRoutes.Users.Handle("/update_mfa", api.ApiUserRequiredMfa(updateMfa)).Methods("POST")
-
- api.BaseRoutes.Users.Handle("/claim/email_to_oauth", api.ApiAppHandler(emailToOAuth)).Methods("POST")
- api.BaseRoutes.Users.Handle("/claim/oauth_to_email", api.ApiUserRequired(oauthToEmail)).Methods("POST")
- api.BaseRoutes.Users.Handle("/claim/email_to_ldap", api.ApiAppHandler(emailToLdap)).Methods("POST")
- api.BaseRoutes.Users.Handle("/claim/ldap_to_email", api.ApiAppHandler(ldapToEmail)).Methods("POST")
-
- api.BaseRoutes.NeedUser.Handle("/get", api.ApiUserRequired(getUser)).Methods("GET")
- api.BaseRoutes.Users.Handle("/name/{username:[A-Za-z0-9_\\-.]+}", api.ApiUserRequired(getByUsername)).Methods("GET")
- api.BaseRoutes.Users.Handle("/email/{email}", api.ApiUserRequired(getByEmail)).Methods("GET")
- api.BaseRoutes.NeedUser.Handle("/sessions", api.ApiUserRequired(getSessions)).Methods("GET")
- api.BaseRoutes.NeedUser.Handle("/audits", api.ApiUserRequired(getAudits)).Methods("GET")
- api.BaseRoutes.NeedUser.Handle("/image", api.ApiUserRequiredTrustRequester(getProfileImage)).Methods("GET")
- api.BaseRoutes.NeedUser.Handle("/update_roles", api.ApiUserRequired(updateRoles)).Methods("POST")
-}
-
-func createUser(c *Context, w http.ResponseWriter, r *http.Request) {
- user := model.UserFromJson(r.Body)
-
- if user == nil {
- c.SetInvalidParam("createUser", "user")
- return
- }
-
- tokenId := r.URL.Query().Get("t")
- inviteId := r.URL.Query().Get("iid")
-
- var ruser *model.User
- var err *model.AppError
- if len(tokenId) > 0 {
- ruser, err = c.App.CreateUserWithToken(user, tokenId)
- } else if len(inviteId) > 0 {
- ruser, err = c.App.CreateUserWithInviteId(user, inviteId)
- } else {
- ruser, err = c.App.CreateUserFromSignup(user)
- }
-
- if err != nil {
- c.Err = err
- return
- }
-
- w.Write([]byte(ruser.ToJson()))
-}
-
-func login(c *Context, w http.ResponseWriter, r *http.Request) {
- props := model.MapFromJson(r.Body)
-
- id := props["id"]
- loginId := props["login_id"]
- password := props["password"]
- mfaToken := props["token"]
- deviceId := props["device_id"]
- ldapOnly := props["ldap_only"] == "true"
-
- c.LogAudit("attempt - user_id=" + id + " login_id=" + loginId)
- user, err := c.App.AuthenticateUserForLogin(id, loginId, password, mfaToken, ldapOnly)
- if err != nil {
- c.LogAudit("failure - user_id=" + id + " login_id=" + loginId)
- c.Err = err
- return
- }
-
- c.LogAuditWithUserId(user.Id, "success")
-
- doLogin(c, w, r, user, deviceId)
- if c.Err != nil {
- return
- }
-
- user.Sanitize(map[string]bool{})
-
- w.Write([]byte(user.ToJson()))
-}
-
-// User MUST be authenticated completely before calling Login
-func doLogin(c *Context, w http.ResponseWriter, r *http.Request, user *model.User, deviceId string) {
- session, err := c.App.DoLogin(w, r, user, deviceId)
- if err != nil {
- c.Err = err
- return
- }
-
- c.Session = *session
-}
-
-func revokeSession(c *Context, w http.ResponseWriter, r *http.Request) {
- props := model.MapFromJson(r.Body)
- id := props["id"]
-
- if err := c.App.RevokeSessionById(id); err != nil {
- c.Err = err
- return
- }
-
- w.Write([]byte(model.MapToJson(props)))
-}
-
-func attachDeviceId(c *Context, w http.ResponseWriter, r *http.Request) {
- props := model.MapFromJson(r.Body)
-
- deviceId := props["device_id"]
- if len(deviceId) == 0 {
- c.SetInvalidParam("attachDevice", "deviceId")
- return
- }
-
- // A special case where we logout of all other sessions with the same device id
- if err := c.App.RevokeSessionsForDeviceId(c.Session.UserId, deviceId, c.Session.Id); err != nil {
- c.Err = err
- c.Err.StatusCode = http.StatusInternalServerError
- return
- }
-
- c.App.ClearSessionCacheForUser(c.Session.UserId)
- c.Session.SetExpireInDays(*c.App.Config().ServiceSettings.SessionLengthMobileInDays)
-
- maxAge := *c.App.Config().ServiceSettings.SessionLengthMobileInDays * 60 * 60 * 24
-
- secure := false
- if app.GetProtocol(r) == "https" {
- secure = true
- }
-
- expiresAt := time.Unix(model.GetMillis()/1000+int64(maxAge), 0)
- sessionCookie := &http.Cookie{
- Name: model.SESSION_COOKIE_TOKEN,
- Value: c.Session.Token,
- Path: "/",
- MaxAge: maxAge,
- Expires: expiresAt,
- HttpOnly: true,
- Secure: secure,
- }
-
- http.SetCookie(w, sessionCookie)
-
- if err := c.App.AttachDeviceId(c.Session.Id, deviceId, c.Session.ExpiresAt); err != nil {
- c.Err = err
- return
- }
-
- w.Write([]byte(model.MapToJson(props)))
-}
-
-func getSessions(c *Context, w http.ResponseWriter, r *http.Request) {
-
- params := mux.Vars(r)
- id := params["user_id"]
-
- if !c.App.SessionHasPermissionToUser(c.Session, id) {
- c.SetPermissionError(model.PERMISSION_EDIT_OTHER_USERS)
- return
- }
-
- if sessions, err := c.App.GetSessions(id); err != nil {
- c.Err = err
- return
- } else {
- for _, session := range sessions {
- session.Sanitize()
- }
-
- w.Write([]byte(model.SessionsToJson(sessions)))
- }
-}
-
-func logout(c *Context, w http.ResponseWriter, r *http.Request) {
- data := make(map[string]string)
- data["user_id"] = c.Session.UserId
-
- Logout(c, w, r)
- if c.Err == nil {
- w.Write([]byte(model.MapToJson(data)))
- }
-}
-
-func Logout(c *Context, w http.ResponseWriter, r *http.Request) {
- c.LogAudit("")
- c.RemoveSessionCookie(w, r)
- if c.Session.Id != "" {
- if err := c.App.RevokeSessionById(c.Session.Id); err != nil {
- c.Err = err
- return
- }
- }
-}
-
-func getMe(c *Context, w http.ResponseWriter, r *http.Request) {
-
- if user, err := c.App.GetUser(c.Session.UserId); err != nil {
- c.Err = err
- c.RemoveSessionCookie(w, r)
- mlog.Error(fmt.Sprintf("Error in getting users profile for id=%v forcing logout", c.Session.UserId), mlog.String("user_id", c.Session.UserId))
- return
- } else if c.HandleEtag(user.Etag(c.App.Config().PrivacySettings.ShowFullName, c.App.Config().PrivacySettings.ShowEmailAddress), "Get Me", w, r) {
- return
- } else {
- user.Sanitize(map[string]bool{})
- w.Header().Set(model.HEADER_ETAG_SERVER, user.Etag(c.App.Config().PrivacySettings.ShowFullName, c.App.Config().PrivacySettings.ShowEmailAddress))
- w.Write([]byte(user.ToJson()))
- return
- }
-}
-
-func getInitialLoad(c *Context, w http.ResponseWriter, r *http.Request) {
-
- il := model.InitialLoad{}
-
- if len(c.Session.UserId) != 0 {
- var err *model.AppError
-
- il.User, err = c.App.GetUser(c.Session.UserId)
- if err != nil {
- c.Err = err
- return
- }
- il.User.Sanitize(map[string]bool{})
-
- il.Preferences, err = c.App.GetPreferencesForUser(c.Session.UserId)
- if err != nil {
- c.Err = err
- return
- }
-
- il.Teams, err = c.App.GetTeamsForUser(c.Session.UserId)
- if err != nil {
- c.Err = err
- return
- }
-
- for _, team := range il.Teams {
- team.Sanitize()
- }
-
- il.TeamMembers = c.Session.TeamMembers
- }
-
- if c.App.SessionCacheLength() == 0 {
- // Below is a special case when intializating a new server
- // Lets check to make sure the server is really empty
-
- il.NoAccounts = c.App.IsFirstUserAccount()
- }
-
- il.ClientCfg = c.App.ClientConfig()
- if c.App.SessionHasPermissionTo(c.Session, model.PERMISSION_MANAGE_SYSTEM) {
- il.LicenseCfg = c.App.ClientLicense()
- } else {
- il.LicenseCfg = c.App.GetSanitizedClientLicense()
- }
-
- w.Write([]byte(il.ToJson()))
-}
-
-func getUser(c *Context, w http.ResponseWriter, r *http.Request) {
- params := mux.Vars(r)
- id := params["user_id"]
-
- var user *model.User
- var err *model.AppError
-
- if user, err = c.App.GetUser(id); err != nil {
- c.Err = err
- return
- }
-
- etag := user.Etag(c.App.Config().PrivacySettings.ShowFullName, c.App.Config().PrivacySettings.ShowEmailAddress)
-
- if c.HandleEtag(etag, "Get User", w, r) {
- return
- } else {
- c.App.SanitizeProfile(user, c.IsSystemAdmin())
- w.Header().Set(model.HEADER_ETAG_SERVER, etag)
- w.Write([]byte(user.ToJson()))
- return
- }
-}
-
-func getByUsername(c *Context, w http.ResponseWriter, r *http.Request) {
- params := mux.Vars(r)
- username := params["username"]
-
- var user *model.User
- var err *model.AppError
-
- if user, err = c.App.GetUserByUsername(username); err != nil {
- c.Err = err
- return
- } else if c.HandleEtag(user.Etag(c.App.Config().PrivacySettings.ShowFullName, c.App.Config().PrivacySettings.ShowEmailAddress), "Get By Username", w, r) {
- return
- } else {
- sanitizeProfile(c, user)
-
- w.Header().Set(model.HEADER_ETAG_SERVER, user.Etag(c.App.Config().PrivacySettings.ShowFullName, c.App.Config().PrivacySettings.ShowEmailAddress))
- w.Write([]byte(user.ToJson()))
- return
- }
-}
-
-func getByEmail(c *Context, w http.ResponseWriter, r *http.Request) {
- params := mux.Vars(r)
- email := params["email"]
-
- if user, err := c.App.GetUserByEmail(email); err != nil {
- c.Err = err
- return
- } else if c.HandleEtag(user.Etag(c.App.Config().PrivacySettings.ShowFullName, c.App.Config().PrivacySettings.ShowEmailAddress), "Get By Email", w, r) {
- return
- } else {
- sanitizeProfile(c, user)
-
- w.Header().Set(model.HEADER_ETAG_SERVER, user.Etag(c.App.Config().PrivacySettings.ShowFullName, c.App.Config().PrivacySettings.ShowEmailAddress))
- w.Write([]byte(user.ToJson()))
- return
- }
-}
-
-func getProfiles(c *Context, w http.ResponseWriter, r *http.Request) {
- params := mux.Vars(r)
-
- offset, err := strconv.Atoi(params["offset"])
- if err != nil {
- c.SetInvalidParam("getProfiles", "offset")
- return
- }
-
- limit, err := strconv.Atoi(params["limit"])
- if err != nil {
- c.SetInvalidParam("getProfiles", "limit")
- return
- }
-
- etag := c.App.GetUsersEtag() + params["offset"] + "." + params["limit"]
- if c.HandleEtag(etag, "Get Profiles", w, r) {
- return
- }
-
- if profiles, err := c.App.GetUsersMap(offset, limit, c.IsSystemAdmin()); err != nil {
- c.Err = err
- return
- } else {
- w.Header().Set(model.HEADER_ETAG_SERVER, etag)
- w.Write([]byte(model.UserMapToJson(profiles)))
- }
-}
-
-func getProfilesInTeam(c *Context, w http.ResponseWriter, r *http.Request) {
- params := mux.Vars(r)
- teamId := params["team_id"]
-
- if c.Session.GetTeamByTeamId(teamId) == nil {
- if !c.App.SessionHasPermissionTo(c.Session, model.PERMISSION_MANAGE_SYSTEM) {
- return
- }
- }
-
- offset, err := strconv.Atoi(params["offset"])
- if err != nil {
- c.SetInvalidParam("getProfilesInTeam", "offset")
- return
- }
-
- limit, err := strconv.Atoi(params["limit"])
- if err != nil {
- c.SetInvalidParam("getProfilesInTeam", "limit")
- return
- }
-
- etag := c.App.GetUsersInTeamEtag(teamId)
- if c.HandleEtag(etag, "Get Profiles In Team", w, r) {
- return
- }
-
- if profiles, err := c.App.GetUsersInTeamMap(teamId, offset, limit, c.IsSystemAdmin()); err != nil {
- c.Err = err
- return
- } else {
- w.Header().Set(model.HEADER_ETAG_SERVER, etag)
- w.Write([]byte(model.UserMapToJson(profiles)))
- }
-}
-
-func getProfilesInChannel(c *Context, w http.ResponseWriter, r *http.Request) {
- params := mux.Vars(r)
- channelId := params["channel_id"]
-
- offset, err := strconv.Atoi(params["offset"])
- if err != nil {
- c.SetInvalidParam("getProfiles", "offset")
- return
- }
-
- limit, err := strconv.Atoi(params["limit"])
- if err != nil {
- c.SetInvalidParam("getProfiles", "limit")
- return
- }
-
- if c.Session.GetTeamByTeamId(c.TeamId) == nil {
- if !c.App.SessionHasPermissionTo(c.Session, model.PERMISSION_MANAGE_SYSTEM) {
- c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM)
- return
- }
- }
-
- if !c.App.SessionHasPermissionToChannel(c.Session, channelId, model.PERMISSION_READ_CHANNEL) {
- c.SetPermissionError(model.PERMISSION_READ_CHANNEL)
- return
- }
-
- if profiles, err := c.App.GetUsersInChannelMap(channelId, offset, limit, c.IsSystemAdmin()); err != nil {
- c.Err = err
- return
- } else {
- w.Write([]byte(model.UserMapToJson(profiles)))
- }
-}
-
-func getProfilesNotInChannel(c *Context, w http.ResponseWriter, r *http.Request) {
- params := mux.Vars(r)
- channelId := params["channel_id"]
-
- if c.Session.GetTeamByTeamId(c.TeamId) == nil {
- if !c.App.SessionHasPermissionTo(c.Session, model.PERMISSION_MANAGE_SYSTEM) {
- c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM)
- return
- }
- }
-
- if !c.App.SessionHasPermissionToChannel(c.Session, channelId, model.PERMISSION_READ_CHANNEL) {
- c.SetPermissionError(model.PERMISSION_READ_CHANNEL)
- return
- }
-
- offset, err := strconv.Atoi(params["offset"])
- if err != nil {
- c.SetInvalidParam("getProfiles", "offset")
- return
- }
-
- limit, err := strconv.Atoi(params["limit"])
- if err != nil {
- c.SetInvalidParam("getProfiles", "limit")
- return
- }
-
- if profiles, err := c.App.GetUsersNotInChannelMap(c.TeamId, channelId, offset, limit, c.IsSystemAdmin()); err != nil {
- c.Err = err
- return
- } else {
- w.Write([]byte(model.UserMapToJson(profiles)))
- }
-}
-
-func getAudits(c *Context, w http.ResponseWriter, r *http.Request) {
- params := mux.Vars(r)
- id := params["user_id"]
-
- if !c.App.SessionHasPermissionToUser(c.Session, id) {
- c.SetPermissionError(model.PERMISSION_EDIT_OTHER_USERS)
- return
- }
-
- if audits, err := c.App.GetAudits(id, 20); err != nil {
- c.Err = err
- return
- } else {
- etag := audits.Etag()
-
- if c.HandleEtag(etag, "Get Audits", w, r) {
- return
- }
-
- if len(etag) > 0 {
- w.Header().Set(model.HEADER_ETAG_SERVER, etag)
- }
-
- w.Write([]byte(audits.ToJson()))
- return
- }
-}
-
-func getProfileImage(c *Context, w http.ResponseWriter, r *http.Request) {
- params := mux.Vars(r)
- id := params["user_id"]
- readFailed := false
-
- var etag string
-
- if users, err := c.App.GetUsersByIds([]string{id}, false); err != nil {
- c.Err = err
- return
- } else {
- if len(users) == 0 {
- c.Err = model.NewAppError("getProfileImage", "store.sql_user.get_profiles.app_error", nil, "", http.StatusInternalServerError)
- return
- }
-
- user := users[0]
- etag = strconv.FormatInt(user.LastPictureUpdate, 10)
- if c.HandleEtag(etag, "Profile Image", w, r) {
- return
- }
-
- var img []byte
- img, readFailed, err = c.App.GetProfileImage(user)
- if err != nil {
- c.Err = err
- return
- }
-
- if readFailed {
- w.Header().Set("Cache-Control", "max-age=300, public") // 5 mins
- } else {
- w.Header().Set("Cache-Control", "max-age=86400, public") // 24 hrs
- w.Header().Set(model.HEADER_ETAG_SERVER, etag)
- }
-
- w.Header().Set("Content-Type", "image/png")
- w.Write(img)
- }
-}
-
-func uploadProfileImage(c *Context, w http.ResponseWriter, r *http.Request) {
- if len(*c.App.Config().FileSettings.DriverName) == 0 {
- c.Err = model.NewAppError("uploadProfileImage", "api.user.upload_profile_user.storage.app_error", nil, "", http.StatusNotImplemented)
- return
- }
-
- if r.ContentLength > *c.App.Config().FileSettings.MaxFileSize {
- c.Err = model.NewAppError("uploadProfileImage", "api.user.upload_profile_user.too_large.app_error", nil, "", http.StatusRequestEntityTooLarge)
- return
- }
-
- if err := r.ParseMultipartForm(*c.App.Config().FileSettings.MaxFileSize); err != nil {
- c.Err = model.NewAppError("uploadProfileImage", "api.user.upload_profile_user.parse.app_error", nil, "", http.StatusBadRequest)
- return
- }
-
- m := r.MultipartForm
-
- imageArray, ok := m.File["image"]
- if !ok {
- c.Err = model.NewAppError("uploadProfileImage", "api.user.upload_profile_user.no_file.app_error", nil, "", http.StatusBadRequest)
- return
- }
-
- if len(imageArray) <= 0 {
- c.Err = model.NewAppError("uploadProfileImage", "api.user.upload_profile_user.array.app_error", nil, "", http.StatusBadRequest)
- return
- }
-
- imageData := imageArray[0]
-
- if err := c.App.SetProfileImage(c.Session.UserId, imageData); err != nil {
- c.Err = err
- return
- }
-
- c.LogAudit("")
-
- // write something as the response since jQuery expects a json response
- w.Write([]byte("true"))
-}
-
-func updateUser(c *Context, w http.ResponseWriter, r *http.Request) {
- user := model.UserFromJson(r.Body)
-
- if user == nil {
- c.SetInvalidParam("updateUser", "user")
- return
- }
-
- if !c.App.SessionHasPermissionToUser(c.Session, user.Id) {
- c.SetPermissionError(model.PERMISSION_EDIT_OTHER_USERS)
- return
- }
-
- if ruser, err := c.App.UpdateUserAsUser(user, c.IsSystemAdmin()); err != nil {
- c.Err = err
- return
- } else {
- c.LogAudit("")
- w.Write([]byte(ruser.ToJson()))
- }
-}
-
-func updatePassword(c *Context, w http.ResponseWriter, r *http.Request) {
- c.LogAudit("attempted")
-
- props := model.MapFromJson(r.Body)
- userId := props["user_id"]
- if len(userId) != 26 {
- c.SetInvalidParam("updatePassword", "user_id")
- return
- }
-
- currentPassword := props["current_password"]
- if len(currentPassword) <= 0 {
- c.SetInvalidParam("updatePassword", "current_password")
- return
- }
-
- newPassword := props["new_password"]
-
- if userId != c.Session.UserId {
- c.Err = model.NewAppError("updatePassword", "api.user.update_password.context.app_error", nil, "", http.StatusForbidden)
- return
- }
-
- if err := c.App.UpdatePasswordAsUser(userId, currentPassword, newPassword); err != nil {
- c.LogAudit("failed")
- c.Err = err
- return
- } else {
- c.LogAudit("completed")
-
- data := make(map[string]string)
- data["user_id"] = c.Session.UserId
- w.Write([]byte(model.MapToJson(data)))
- }
-}
-
-func updateRoles(c *Context, w http.ResponseWriter, r *http.Request) {
- props := model.MapFromJson(r.Body)
- params := mux.Vars(r)
-
- userId := params["user_id"]
- if len(userId) != 26 {
- c.SetInvalidParam("updateMemberRoles", "user_id")
- return
- }
-
- newRoles := props["new_roles"]
- if !(model.IsValidUserRoles(newRoles)) {
- c.SetInvalidParam("updateMemberRoles", "new_roles")
- return
- }
-
- if !c.App.SessionHasPermissionTo(c.Session, model.PERMISSION_MANAGE_ROLES) {
- c.SetPermissionError(model.PERMISSION_MANAGE_ROLES)
- return
- }
-
- if _, err := c.App.UpdateUserRoles(userId, newRoles, true); err != nil {
- return
- } else {
- c.LogAuditWithUserId(userId, "roles="+newRoles)
- }
-
- rdata := map[string]string{}
- rdata["status"] = "ok"
- w.Write([]byte(model.MapToJson(rdata)))
-}
-
-func updateActive(c *Context, w http.ResponseWriter, r *http.Request) {
- props := model.MapFromJson(r.Body)
-
- userId := props["user_id"]
- if len(userId) != 26 {
- c.SetInvalidParam("updateActive", "user_id")
- return
- }
-
- active := props["active"] == "true"
-
- // true when you're trying to de-activate yourself
- isSelfDeactive := !active && userId == c.Session.UserId
-
- if !isSelfDeactive && !c.App.SessionHasPermissionTo(c.Session, model.PERMISSION_MANAGE_SYSTEM) {
- c.Err = model.NewAppError("updateActive", "api.user.update_active.permissions.app_error", nil, "userId="+userId, http.StatusForbidden)
- return
- }
-
- var ruser *model.User
- var err *model.AppError
-
- if ruser, err = c.App.GetUser(userId); err != nil {
- c.Err = err
- return
- }
-
- if _, err := c.App.UpdateActive(ruser, active); err != nil {
- c.Err = err
- } else {
- c.LogAuditWithUserId(ruser.Id, fmt.Sprintf("active=%v", active))
- w.Write([]byte(ruser.ToJson()))
- }
-}
-
-func sendPasswordReset(c *Context, w http.ResponseWriter, r *http.Request) {
- props := model.MapFromJson(r.Body)
-
- email := props["email"]
- if len(email) == 0 {
- c.SetInvalidParam("sendPasswordReset", "email")
- return
- }
-
- if sent, err := c.App.SendPasswordReset(email, c.App.GetSiteURL()); err != nil {
- c.Err = err
- return
- } else if sent {
- c.LogAudit("sent=" + email)
- }
-
- w.Write([]byte(model.MapToJson(props)))
-}
-
-func resetPassword(c *Context, w http.ResponseWriter, r *http.Request) {
- props := model.MapFromJson(r.Body)
-
- code := props["code"]
- if len(code) != model.TOKEN_SIZE {
- c.SetInvalidParam("resetPassword", "code")
- return
- }
-
- newPassword := props["new_password"]
-
- c.LogAudit("attempt - token=" + code)
-
- if err := c.App.ResetPasswordFromToken(code, newPassword); err != nil {
- c.LogAudit("fail - token=" + code)
- c.Err = err
- return
- }
-
- c.LogAudit("success - token=" + code)
-
- rdata := map[string]string{}
- rdata["status"] = "ok"
- w.Write([]byte(model.MapToJson(rdata)))
-}
-
-func updateUserNotify(c *Context, w http.ResponseWriter, r *http.Request) {
- props := model.MapFromJson(r.Body)
-
- userId := props["user_id"]
- if len(userId) != 26 {
- c.SetInvalidParam("updateUserNotify", "user_id")
- return
- }
-
- if !c.App.SessionHasPermissionToUser(c.Session, userId) {
- c.SetPermissionError(model.PERMISSION_EDIT_OTHER_USERS)
- return
- }
-
- delete(props, "user_id")
-
- email := props["email"]
- if len(email) == 0 {
- c.SetInvalidParam("updateUserNotify", "email")
- return
- }
-
- desktop_sound := props["desktop_sound"]
- if len(desktop_sound) == 0 {
- c.SetInvalidParam("updateUserNotify", "desktop_sound")
- return
- }
-
- desktop := props["desktop"]
- if len(desktop) == 0 {
- c.SetInvalidParam("updateUserNotify", "desktop")
- return
- }
-
- comments := props["comments"]
- if len(comments) == 0 {
- c.SetInvalidParam("updateUserNotify", "comments")
- return
- }
-
- ruser, err := c.App.UpdateUserNotifyProps(userId, props)
- if err != nil {
- c.Err = err
- return
- }
-
- c.LogAuditWithUserId(ruser.Id, "")
-
- options := c.App.Config().GetSanitizeOptions()
- options["passwordupdate"] = false
- ruser.Sanitize(options)
- w.Write([]byte(ruser.ToJson()))
-}
-
-func emailToOAuth(c *Context, w http.ResponseWriter, r *http.Request) {
- props := model.MapFromJson(r.Body)
-
- password := props["password"]
- if len(password) == 0 {
- c.SetInvalidParam("emailToOAuth", "password")
- return
- }
-
- mfaToken := props["token"]
-
- service := props["service"]
- if len(service) == 0 {
- c.SetInvalidParam("emailToOAuth", "service")
- return
- }
-
- email := props["email"]
- if len(email) == 0 {
- c.SetInvalidParam("emailToOAuth", "email")
- return
- }
-
- link, err := c.App.SwitchEmailToOAuth(w, r, email, password, mfaToken, service)
- if err != nil {
- c.Err = err
- return
- }
-
- c.LogAudit("success for email=" + email)
- w.Write([]byte(model.MapToJson(map[string]string{"follow_link": link})))
-}
-
-func oauthToEmail(c *Context, w http.ResponseWriter, r *http.Request) {
- props := model.MapFromJson(r.Body)
-
- password := props["password"]
- if err := c.App.IsPasswordValid(password); err != nil {
- c.Err = err
- return
- }
-
- email := props["email"]
- if len(email) == 0 {
- c.SetInvalidParam("oauthToEmail", "email")
- return
- }
-
- link, err := c.App.SwitchOAuthToEmail(email, password, c.Session.UserId)
- if err != nil {
- c.Err = err
- return
- }
-
- c.RemoveSessionCookie(w, r)
- if c.Err != nil {
- return
- }
-
- c.LogAudit("success")
- w.Write([]byte(model.MapToJson(map[string]string{"follow_link": link})))
-}
-
-func emailToLdap(c *Context, w http.ResponseWriter, r *http.Request) {
- props := model.MapFromJson(r.Body)
-
- email := props["email"]
- if len(email) == 0 {
- c.SetInvalidParam("emailToLdap", "email")
- return
- }
-
- emailPassword := props["email_password"]
- if len(emailPassword) == 0 {
- c.SetInvalidParam("emailToLdap", "email_password")
- return
- }
-
- ldapId := props["ldap_id"]
- if len(ldapId) == 0 {
- c.SetInvalidParam("emailToLdap", "ldap_id")
- return
- }
-
- ldapPassword := props["ldap_password"]
- if len(ldapPassword) == 0 {
- c.SetInvalidParam("emailToLdap", "ldap_password")
- return
- }
-
- token := props["token"]
-
- c.LogAudit("attempt")
-
- link, err := c.App.SwitchEmailToLdap(email, emailPassword, token, ldapId, ldapPassword)
- if err != nil {
- c.Err = err
- return
- }
-
- c.RemoveSessionCookie(w, r)
- if c.Err != nil {
- return
- }
-
- c.LogAudit("success")
- w.Write([]byte(model.MapToJson(map[string]string{"follow_link": link})))
-}
-
-func ldapToEmail(c *Context, w http.ResponseWriter, r *http.Request) {
- props := model.MapFromJson(r.Body)
-
- email := props["email"]
- if len(email) == 0 {
- c.SetInvalidParam("ldapToEmail", "email")
- return
- }
-
- emailPassword := props["email_password"]
- if err := c.App.IsPasswordValid(emailPassword); err != nil {
- c.Err = err
- return
- }
-
- ldapPassword := props["ldap_password"]
- if len(ldapPassword) == 0 {
- c.SetInvalidParam("ldapToEmail", "ldap_password")
- return
- }
-
- token := props["token"]
-
- c.LogAudit("attempt")
-
- link, err := c.App.SwitchLdapToEmail(ldapPassword, token, email, emailPassword)
- if err != nil {
- c.Err = err
- return
- }
-
- c.RemoveSessionCookie(w, r)
- if c.Err != nil {
- return
- }
-
- c.LogAudit("success")
- w.Write([]byte(model.MapToJson(map[string]string{"follow_link": link})))
-}
-
-func generateMfaSecret(c *Context, w http.ResponseWriter, r *http.Request) {
- secret, err := c.App.GenerateMfaSecret(c.Session.UserId)
- if err != nil {
- c.Err = err
- return
- }
-
- w.Header().Set("Cache-Control", "no-cache")
- w.Header().Set("Pragma", "no-cache")
- w.Header().Set("Expires", "0")
- w.Write([]byte(secret.ToJson()))
-}
-
-func updateMfa(c *Context, w http.ResponseWriter, r *http.Request) {
- props := model.StringInterfaceFromJson(r.Body)
-
- activate, ok := props["activate"].(bool)
- if !ok {
- c.SetInvalidParam("updateMfa", "activate")
- return
- }
-
- token := ""
- if activate {
- token = props["token"].(string)
- if len(token) == 0 {
- c.SetInvalidParam("updateMfa", "token")
- return
- }
- }
-
- c.LogAudit("attempt")
-
- if activate {
- if err := c.App.ActivateMfa(c.Session.UserId, token); err != nil {
- c.Err = err
- return
- }
- c.LogAudit("success - activated")
- } else {
- if err := c.App.DeactivateMfa(c.Session.UserId); err != nil {
- c.Err = err
- return
- }
- c.LogAudit("success - deactivated")
- }
-
- c.App.Go(func() {
- var user *model.User
- var err *model.AppError
- if user, err = c.App.GetUser(c.Session.UserId); err != nil {
- mlog.Warn(err.Error())
- return
- }
-
- if err := c.App.SendMfaChangeEmail(user.Email, activate, user.Locale, c.App.GetSiteURL()); err != nil {
- mlog.Error(err.Error())
- }
- })
-
- rdata := map[string]string{}
- rdata["status"] = "ok"
- w.Write([]byte(model.MapToJson(rdata)))
-}
-
-func checkMfa(c *Context, w http.ResponseWriter, r *http.Request) {
- if license := c.App.License(); license == nil || !*license.Features.MFA || !*c.App.Config().ServiceSettings.EnableMultifactorAuthentication {
- rdata := map[string]string{}
- rdata["mfa_required"] = "false"
- w.Write([]byte(model.MapToJson(rdata)))
- return
- }
-
- props := model.MapFromJson(r.Body)
-
- loginId := props["login_id"]
- if len(loginId) == 0 {
- c.SetInvalidParam("checkMfa", "login_id")
- return
- }
-
- rdata := map[string]string{}
- if user, err := c.App.GetUserForLogin("", loginId); err != nil {
- rdata["mfa_required"] = "false"
- } else {
- rdata["mfa_required"] = strconv.FormatBool(user.MfaActive)
- }
- w.Write([]byte(model.MapToJson(rdata)))
-}
-
-func sanitizeProfile(c *Context, user *model.User) *model.User {
- options := c.App.Config().GetSanitizeOptions()
-
- if c.App.SessionHasPermissionTo(c.Session, model.PERMISSION_MANAGE_SYSTEM) {
- options["email"] = true
- options["fullname"] = true
- options["authservice"] = true
- }
-
- user.SanitizeProfile(options)
-
- return user
-}
-
-func searchUsers(c *Context, w http.ResponseWriter, r *http.Request) {
- props := model.UserSearchFromJson(r.Body)
- if props == nil {
- c.SetInvalidParam("searchUsers", "")
- return
- }
-
- if len(props.Term) == 0 {
- c.SetInvalidParam("searchUsers", "term")
- return
- }
-
- if props.InChannelId != "" && !c.App.SessionHasPermissionToChannel(c.Session, props.InChannelId, model.PERMISSION_READ_CHANNEL) {
- c.SetPermissionError(model.PERMISSION_READ_CHANNEL)
- return
- }
-
- if props.NotInChannelId != "" && !c.App.SessionHasPermissionToChannel(c.Session, props.NotInChannelId, model.PERMISSION_READ_CHANNEL) {
- c.SetPermissionError(model.PERMISSION_READ_CHANNEL)
- return
- }
-
- searchOptions := map[string]bool{}
- searchOptions[store.USER_SEARCH_OPTION_ALLOW_INACTIVE] = props.AllowInactive
-
- if !c.App.SessionHasPermissionTo(c.Session, model.PERMISSION_MANAGE_SYSTEM) {
- hideFullName := !c.App.Config().PrivacySettings.ShowFullName
- hideEmail := !c.App.Config().PrivacySettings.ShowEmailAddress
-
- if hideFullName && hideEmail {
- searchOptions[store.USER_SEARCH_OPTION_NAMES_ONLY_NO_FULL_NAME] = true
- } else if hideFullName {
- searchOptions[store.USER_SEARCH_OPTION_ALL_NO_FULL_NAME] = true
- } else if hideEmail {
- searchOptions[store.USER_SEARCH_OPTION_NAMES_ONLY] = true
- }
- }
-
- if profiles, err := c.App.SearchUsers(props, searchOptions, c.IsSystemAdmin()); err != nil {
- c.Err = err
- return
- } else {
- w.Write([]byte(model.UserListToJson(profiles)))
- }
-}
-
-func getProfilesByIds(c *Context, w http.ResponseWriter, r *http.Request) {
- userIds := model.ArrayFromJson(r.Body)
-
- if len(userIds) == 0 {
- c.SetInvalidParam("getProfilesByIds", "user_ids")
- return
- }
-
- if profiles, err := c.App.GetUsersByIds(userIds, c.IsSystemAdmin()); err != nil {
- c.Err = err
- return
- } else {
- profileMap := map[string]*model.User{}
- for _, p := range profiles {
- profileMap[p.Id] = p
- }
- w.Write([]byte(model.UserMapToJson(profileMap)))
- }
-}
-
-func autocompleteUsersInChannel(c *Context, w http.ResponseWriter, r *http.Request) {
- params := mux.Vars(r)
- channelId := params["channel_id"]
- teamId := params["team_id"]
-
- term := r.URL.Query().Get("term")
-
- if c.Session.GetTeamByTeamId(teamId) == nil {
- if !c.App.SessionHasPermissionTo(c.Session, model.PERMISSION_MANAGE_SYSTEM) {
- return
- }
- }
-
- if !c.App.SessionHasPermissionToChannel(c.Session, channelId, model.PERMISSION_READ_CHANNEL) {
- c.SetPermissionError(model.PERMISSION_READ_CHANNEL)
- return
- }
-
- searchOptions := map[string]bool{}
-
- hideFullName := !c.App.Config().PrivacySettings.ShowFullName
- if hideFullName && !c.App.SessionHasPermissionTo(c.Session, model.PERMISSION_MANAGE_SYSTEM) {
- searchOptions[store.USER_SEARCH_OPTION_NAMES_ONLY_NO_FULL_NAME] = true
- } else {
- searchOptions[store.USER_SEARCH_OPTION_NAMES_ONLY] = true
- }
-
- autocomplete, err := c.App.AutocompleteUsersInChannel(teamId, channelId, term, searchOptions, c.IsSystemAdmin())
- if err != nil {
- c.Err = err
- return
- }
-
- w.Write([]byte(autocomplete.ToJson()))
-}
-
-func autocompleteUsersInTeam(c *Context, w http.ResponseWriter, r *http.Request) {
- params := mux.Vars(r)
- teamId := params["team_id"]
-
- term := r.URL.Query().Get("term")
-
- if c.Session.GetTeamByTeamId(teamId) == nil {
- if !c.App.SessionHasPermissionTo(c.Session, model.PERMISSION_MANAGE_SYSTEM) {
- return
- }
- }
-
- searchOptions := map[string]bool{}
-
- hideFullName := !c.App.Config().PrivacySettings.ShowFullName
- if hideFullName && !c.App.SessionHasPermissionTo(c.Session, model.PERMISSION_MANAGE_SYSTEM) {
- searchOptions[store.USER_SEARCH_OPTION_NAMES_ONLY_NO_FULL_NAME] = true
- } else {
- searchOptions[store.USER_SEARCH_OPTION_NAMES_ONLY] = true
- }
-
- autocomplete, err := c.App.AutocompleteUsersInTeam(teamId, term, searchOptions, c.IsSystemAdmin())
- if err != nil {
- c.Err = err
- return
- }
-
- w.Write([]byte(autocomplete.ToJson()))
-}
-
-func autocompleteUsers(c *Context, w http.ResponseWriter, r *http.Request) {
- term := r.URL.Query().Get("term")
-
- searchOptions := map[string]bool{}
-
- hideFullName := !c.App.Config().PrivacySettings.ShowFullName
- if hideFullName && !c.App.SessionHasPermissionTo(c.Session, model.PERMISSION_MANAGE_SYSTEM) {
- searchOptions[store.USER_SEARCH_OPTION_NAMES_ONLY_NO_FULL_NAME] = true
- } else {
- searchOptions[store.USER_SEARCH_OPTION_NAMES_ONLY] = true
- }
-
- var profiles []*model.User
- var err *model.AppError
-
- if profiles, err = c.App.SearchUsersInTeam("", term, searchOptions, c.IsSystemAdmin()); err != nil {
- c.Err = err
- return
- }
-
- w.Write([]byte(model.UserListToJson(profiles)))
-}
diff --git a/api/user_test.go b/api/user_test.go
deleted file mode 100644
index 05ec0e096..000000000
--- a/api/user_test.go
+++ /dev/null
@@ -1,2737 +0,0 @@
-// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-package api
-
-import (
- "bytes"
- "image"
- "image/color"
- "io"
- "mime/multipart"
- "net/http"
- "os"
- "path/filepath"
- "strings"
- "testing"
- "time"
-
- "github.com/stretchr/testify/assert"
-
- "github.com/mattermost/mattermost-server/app"
- "github.com/mattermost/mattermost-server/model"
- "github.com/mattermost/mattermost-server/store"
- "github.com/mattermost/mattermost-server/utils"
-)
-
-func TestCreateUser(t *testing.T) {
- th := Setup()
- defer th.TearDown()
-
- Client := th.CreateClient()
-
- user := model.User{Email: strings.ToLower("success+"+model.NewId()) + "@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "hello1", Username: "n" + model.NewId()}
-
- ruser, err := Client.CreateUser(&user, "")
- if err != nil {
- t.Fatal(err)
- }
-
- Client.Login(user.Email, user.Password)
-
- team := model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
- rteam, _ := Client.CreateTeam(&team)
-
- th.LinkUserToTeam(ruser.Data.(*model.User), rteam.Data.(*model.Team))
-
- if ruser.Data.(*model.User).Nickname != user.Nickname {
- t.Fatal("nickname didn't match")
- }
-
- if ruser.Data.(*model.User).Password != "" {
- t.Fatal("password wasn't blank")
- }
-
- if _, err := Client.CreateUser(ruser.Data.(*model.User), ""); err == nil {
- t.Fatal("Cannot create an existing")
- }
-
- ruser.Data.(*model.User).Id = ""
- ruser.Data.(*model.User).Username = "n" + model.NewId()
- ruser.Data.(*model.User).Password = "passwd1"
- if _, err := Client.CreateUser(ruser.Data.(*model.User), ""); err != nil {
- if err.Message != "An account with that email already exists." {
- t.Fatal(err)
- }
- }
-
- ruser.Data.(*model.User).Email = "success+" + model.NewId() + "@simulator.amazonses.com"
- ruser.Data.(*model.User).Username = user.Username
- if _, err := Client.CreateUser(ruser.Data.(*model.User), ""); err != nil {
- if err.Message != "An account with that username already exists." {
- t.Fatal(err)
- }
- }
-
- ruser.Data.(*model.User).Email = ""
- if _, err := Client.CreateUser(ruser.Data.(*model.User), ""); err != nil {
- if err.Message != "Invalid email" {
- t.Fatal(err)
- }
- }
-
- if _, err := Client.DoApiPost("/users/create", "garbage"); err == nil {
- t.Fatal("should have been an error")
- }
-}
-
-func TestLogin(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- Client := th.BasicClient
-
- th.App.UpdateConfig(func(cfg *model.Config) {
- *cfg.EmailSettings.EnableSignInWithEmail = false
- *cfg.EmailSettings.EnableSignInWithUsername = false
- *cfg.LdapSettings.Enable = false
- })
-
- team := model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
- rteam, _ := Client.CreateTeam(&team)
-
- team2 := model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_INVITE}
- rteam2 := Client.Must(Client.CreateTeam(&team2))
-
- Client.Logout()
-
- user := model.User{Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Username: "corey" + model.NewId(), Password: "passwd1"}
- ruser, _ := Client.CreateUser(&user, "")
- th.LinkUserToTeam(ruser.Data.(*model.User), rteam.Data.(*model.Team))
- store.Must(th.App.Srv.Store.User().VerifyEmail(ruser.Data.(*model.User).Id))
-
- if result, err := Client.LoginById(ruser.Data.(*model.User).Id, user.Password); err != nil {
- t.Fatal(err)
- } else {
- if result.Data.(*model.User).Email != user.Email {
- t.Fatal("emails didn't match")
- }
- }
-
- if _, err := Client.Login(user.Email, user.Password); err == nil {
- t.Fatal("shouldn't be able to log in by email when disabled")
- }
-
- th.App.UpdateConfig(func(cfg *model.Config) { *cfg.EmailSettings.EnableSignInWithEmail = true })
- if result, err := Client.Login(user.Email, user.Password); err != nil {
- t.Fatal(err)
- } else {
- if result.Data.(*model.User).Email != user.Email {
- t.Fatal("emails didn't match")
- }
- }
-
- if _, err := Client.Login(user.Username, user.Password); err == nil {
- t.Fatal("shouldn't be able to log in by username when disabled")
- }
-
- th.App.UpdateConfig(func(cfg *model.Config) { *cfg.EmailSettings.EnableSignInWithUsername = true })
- if result, err := Client.Login(user.Username, user.Password); err != nil {
- t.Fatal(err)
- } else {
- if result.Data.(*model.User).Email != user.Email {
- t.Fatal("emails didn't match")
- }
- }
-
- if _, err := Client.Login(user.Email, user.Password+"invalid"); err == nil {
- t.Fatal("Invalid Password")
- }
-
- if _, err := Client.Login(user.Username, user.Password+"invalid"); err == nil {
- t.Fatal("Invalid Password")
- }
-
- if _, err := Client.Login("", user.Password); err == nil {
- t.Fatal("should have failed")
- }
-
- if _, err := Client.Login("", user.Password); err == nil {
- t.Fatal("should have failed")
- }
-
- authToken := Client.AuthToken
- Client.AuthToken = "invalid"
-
- if _, err := Client.GetUser(ruser.Data.(*model.User).Id, ""); err == nil {
- t.Fatal("should have failed")
- }
-
- Client.AuthToken = ""
-
- user2 := model.User{Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "passwd1"}
-
- if _, err := Client.CreateUserFromSignup(&user2, "junk", "1231312"); err == nil {
- t.Fatal("Should have errored, signed up without hashed email")
- }
-
- token := model.NewToken(
- app.TOKEN_TYPE_TEAM_INVITATION,
- model.MapToJson(map[string]string{"teamId": rteam2.Data.(*model.Team).Id, "email": user2.Email}),
- )
- <-th.App.Srv.Store.Token().Save(token)
- props := make(map[string]string)
- props["email"] = user2.Email
- props["display_name"] = rteam2.Data.(*model.Team).DisplayName
- data := model.MapToJson(props)
-
- ruser2, err := Client.CreateUserFromSignup(&user2, data, token.Token)
- if err != nil {
- t.Fatal(err)
- }
- if result := <-th.App.Srv.Store.Token().GetByToken(token.Token); result.Err == nil {
- t.Fatal("The token must be deleted after be used")
- }
-
- if _, err := Client.Login(ruser2.Data.(*model.User).Email, user2.Password); err != nil {
- t.Fatal("From verified token")
- }
-
- Client.AuthToken = authToken
-
- user3 := &model.User{
- Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com",
- Nickname: "Corey Hulen",
- Username: "corey" + model.NewId(),
- Password: "passwd1",
- AuthService: model.USER_AUTH_SERVICE_LDAP,
- }
- ruser3 := Client.Must(Client.CreateUser(user3, "")).Data.(*model.User)
- store.Must(th.App.Srv.Store.User().VerifyEmail(ruser3.Id))
-
- if _, err := Client.Login(ruser3.Id, user3.Password); err == nil {
- t.Fatal("AD/LDAP user should not be able to log in with AD/LDAP disabled")
- }
-}
-
-func TestLoginUnverifiedEmail(t *testing.T) {
- assert := assert.New(t)
-
- th := Setup().InitBasic()
- defer th.TearDown()
-
- Client := th.BasicClient
-
- th.App.UpdateConfig(func(cfg *model.Config) {
- *cfg.EmailSettings.EnableSignInWithEmail = true
- cfg.EmailSettings.RequireEmailVerification = true
- })
-
- Client.Logout()
-
- user := &model.User{
- Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com",
- Nickname: "Corey Hulen",
- Username: "corey" + model.NewId(),
- Password: "passwd1",
- EmailVerified: false,
- }
- user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
-
- _, err := Client.Login(user.Email, user.Password+"invalid")
- if assert.NotNil(err) {
- assert.Equal("api.user.check_user_password.invalid.app_error", err.Id)
- }
-
- _, err = Client.Login(user.Email, "passwd1")
- if assert.NotNil(err) {
- assert.Equal("api.user.login.not_verified.app_error", err.Id)
- }
-}
-
-func TestLoginByLdap(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- Client := th.BasicClient
-
- team := model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
- rteam, _ := Client.CreateTeam(&team)
-
- Client.Logout()
-
- user := model.User{Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Username: "corey" + model.NewId(), Password: "passwd1"}
- ruser, _ := Client.CreateUser(&user, "")
- th.LinkUserToTeam(ruser.Data.(*model.User), rteam.Data.(*model.Team))
- store.Must(th.App.Srv.Store.User().VerifyEmail(ruser.Data.(*model.User).Id))
-
- if _, err := Client.LoginByLdap(ruser.Data.(*model.User).Id, user.Password); err == nil {
- t.Fatal("should have failed to log in with non AD/LDAP user")
- }
-}
-
-func TestLoginWithDeviceId(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- Client := th.BasicClient
- user := th.BasicUser
- Client.Must(Client.Logout())
-
- deviceId := model.NewId()
- if result, err := Client.LoginWithDevice(user.Email, user.Password, deviceId); err != nil {
- t.Fatal(err)
- } else {
- ruser := result.Data.(*model.User)
-
- if ssresult, err := Client.GetSessions(ruser.Id); err != nil {
- t.Fatal(err)
- } else {
- sessions := ssresult.Data.([]*model.Session)
- if _, err := Client.LoginWithDevice(user.Email, user.Password, deviceId); err != nil {
- t.Fatal(err)
- }
-
- if sresult := <-th.App.Srv.Store.Session().Get(sessions[0].Id); sresult.Err == nil {
- t.Fatal("session should have been removed")
- }
- }
- }
-}
-
-func TestPasswordGuessLockout(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- Client := th.BasicClient
- user := th.BasicUser
- Client.Must(Client.Logout())
-
- th.App.UpdateConfig(func(cfg *model.Config) { *cfg.EmailSettings.EnableSignInWithEmail = true })
- th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.MaximumLoginAttempts = 2 })
-
- // OK to log in
- if _, err := Client.Login(user.Username, user.Password); err != nil {
- t.Fatal(err)
- }
-
- Client.Must(Client.Logout())
-
- // Fail twice
- if _, err := Client.Login(user.Email, "notthepassword"); err == nil {
- t.Fatal("Shouldn't be able to login with bad password.")
- }
- if _, err := Client.Login(user.Email, "notthepassword"); err == nil {
- t.Fatal("Shouldn't be able to login with bad password.")
- }
-
- // Locked out
- if _, err := Client.Login(user.Email, user.Password); err == nil {
- t.Fatal("Shouldn't be able to login with password when account is locked out.")
- }
-}
-
-func TestSessions(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- Client := th.BasicClient
- user := th.BasicUser
- Client.Must(Client.Logout())
-
- deviceId := model.NewId()
- Client.LoginWithDevice(user.Email, user.Password, deviceId)
- Client.Login(user.Email, user.Password)
-
- r1, err := Client.GetSessions(user.Id)
- if err != nil {
- t.Fatal(err)
- }
-
- sessions := r1.Data.([]*model.Session)
- otherSession := ""
-
- if len(sessions) != 2 {
- t.Fatal("invalid number of sessions")
- }
-
- for _, session := range sessions {
- if session.DeviceId == deviceId {
- otherSession = session.Id
- }
-
- if len(session.Token) != 0 {
- t.Fatal("shouldn't return session tokens")
- }
- }
-
- if _, err := Client.RevokeSession(otherSession); err != nil {
- t.Fatal(err)
- }
-
- r2, err := Client.GetSessions(user.Id)
- if err != nil {
- t.Fatal(err)
- }
-
- sessions2 := r2.Data.([]*model.Session)
-
- if len(sessions2) != 1 {
- t.Fatal("invalid number of sessions")
- }
-}
-
-func TestGetUser(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- Client := th.BasicClient
-
- team := model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
- rteam, _ := Client.CreateTeam(&team)
-
- team2 := model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
- rteam2, _ := Client.CreateTeam(&team2)
-
- Client.Logout()
-
- user := model.User{Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "passwd1"}
- ruser, _ := Client.CreateUser(&user, "")
- th.LinkUserToTeam(ruser.Data.(*model.User), rteam.Data.(*model.Team))
- store.Must(th.App.Srv.Store.User().VerifyEmail(ruser.Data.(*model.User).Id))
-
- user2 := model.User{Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "passwd1", FirstName: "Corey", LastName: "Hulen"}
- ruser2, _ := Client.CreateUser(&user2, "")
- th.LinkUserToTeam(ruser2.Data.(*model.User), rteam.Data.(*model.Team))
- store.Must(th.App.Srv.Store.User().VerifyEmail(ruser2.Data.(*model.User).Id))
-
- user3 := model.User{Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "passwd1"}
- ruser3, _ := Client.CreateUser(&user3, "")
- th.LinkUserToTeam(ruser3.Data.(*model.User), rteam2.Data.(*model.Team))
- store.Must(th.App.Srv.Store.User().VerifyEmail(ruser3.Data.(*model.User).Id))
-
- Client.Login(user.Email, user.Password)
-
- rId := ruser.Data.(*model.User).Id
- if result, err := Client.GetUser(rId, ""); err != nil {
- t.Fatal("Failed to get user")
- } else {
- if result.Data.(*model.User).Password != "" {
- t.Fatal("User shouldn't have any password data once set")
- }
-
- if cache_result, err := Client.GetUser(rId, result.Etag); err != nil {
- t.Fatal(err)
- } else if cache_result.Data.(*model.User) != nil {
- t.Fatal("cache should be empty")
- }
- }
-
- if result, err := Client.GetMe(""); err != nil {
- t.Fatal("Failed to get user")
- } else {
- if result.Data.(*model.User).Password != "" {
- t.Fatal("User shouldn't have any password data once set")
- }
- }
-
- if _, err := Client.GetUser("FORBIDDENERROR", ""); err == nil {
- t.Fatal("shouldn't exist")
- }
-
- th.App.UpdateConfig(func(cfg *model.Config) { cfg.PrivacySettings.ShowEmailAddress = false })
- th.App.UpdateConfig(func(cfg *model.Config) { cfg.PrivacySettings.ShowFullName = false })
-
- if result, err := Client.GetUser(ruser2.Data.(*model.User).Id, ""); err != nil {
- t.Fatal(err)
- } else {
- u := result.Data.(*model.User)
- if u.Password != "" {
- t.Fatal("password must be empty")
- }
- if *u.AuthData != "" {
- t.Fatal("auth data must be empty")
- }
- if u.Email != "" {
- t.Fatal("email should be sanitized")
- }
- if u.FirstName != "" {
- t.Fatal("full name should be sanitized")
- }
- if u.LastName != "" {
- t.Fatal("full name should be sanitized")
- }
- }
-
- th.App.UpdateConfig(func(cfg *model.Config) { cfg.PrivacySettings.ShowEmailAddress = true })
- th.App.UpdateConfig(func(cfg *model.Config) { cfg.PrivacySettings.ShowFullName = true })
-
- if result, err := Client.GetUser(ruser2.Data.(*model.User).Id, ""); err != nil {
- t.Fatal(err)
- } else {
- u := result.Data.(*model.User)
- if u.Email == "" {
- t.Fatal("email should not be sanitized")
- }
- if u.FirstName == "" {
- t.Fatal("full name should not be sanitized")
- }
- if u.LastName == "" {
- t.Fatal("full name should not be sanitized")
- }
- }
-
- if userMap, err := Client.GetProfilesInTeam(rteam.Data.(*model.Team).Id, 0, 100, ""); err != nil {
- t.Fatal(err)
- } else if len(userMap.Data.(map[string]*model.User)) != 3 {
- t.Fatal("should have been 3")
- } else if userMap.Data.(map[string]*model.User)[rId].Id != rId {
- t.Fatal("should have been valid")
- } else {
-
- // test etag caching
- if cache_result, err := Client.GetProfilesInTeam(rteam.Data.(*model.Team).Id, 0, 100, userMap.Etag); err != nil {
- t.Fatal(err)
- } else if cache_result.Data.(map[string]*model.User) != nil {
- t.Log(cache_result.Data)
- t.Fatal("cache should be empty")
- }
- }
-
- if userMap, err := Client.GetProfilesInTeam(rteam.Data.(*model.Team).Id, 0, 1, ""); err != nil {
- t.Fatal(err)
- } else if len(userMap.Data.(map[string]*model.User)) != 1 {
- t.Fatal("should have been 1")
- }
-
- if userMap, err := Client.GetProfilesInTeam(rteam.Data.(*model.Team).Id, 1, 1, ""); err != nil {
- t.Fatal(err)
- } else if len(userMap.Data.(map[string]*model.User)) != 1 {
- t.Fatal("should have been 1")
- }
-
- if userMap, err := Client.GetProfilesInTeam(rteam.Data.(*model.Team).Id, 10, 10, ""); err != nil {
- t.Fatal(err)
- } else if len(userMap.Data.(map[string]*model.User)) != 0 {
- t.Fatal("should have been 0")
- }
-
- if _, err := Client.GetProfilesInTeam(rteam2.Data.(*model.Team).Id, 0, 100, ""); err == nil {
- t.Fatal("shouldn't have access")
- }
-
- Client.AuthToken = ""
- if _, err := Client.GetUser(ruser2.Data.(*model.User).Id, ""); err == nil {
- t.Fatal("shouldn't have accss")
- }
-
- th.App.UpdateUserRoles(ruser.Data.(*model.User).Id, model.SYSTEM_ADMIN_ROLE_ID, false)
-
- Client.Login(user.Email, "passwd1")
-
- if _, err := Client.GetProfilesInTeam(rteam2.Data.(*model.Team).Id, 0, 100, ""); err != nil {
- t.Fatal(err)
- }
-}
-
-func TestGetProfiles(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- th.BasicClient.Must(th.BasicClient.CreateDirectChannel(th.BasicUser2.Id))
-
- th.App.UpdateConfig(func(cfg *model.Config) { cfg.PrivacySettings.ShowEmailAddress = true })
-
- if result, err := th.BasicClient.GetProfiles(0, 100, ""); err != nil {
- t.Fatal(err)
- } else {
- users := result.Data.(map[string]*model.User)
-
- if len(users) < 1 {
- t.Fatal("map was wrong length")
- }
-
- for _, user := range users {
- if user.Email == "" {
- t.Fatal("problem with show email")
- }
- }
-
- // test etag caching
- if cache_result, err := th.BasicClient.GetProfiles(0, 100, result.Etag); err != nil {
- t.Fatal(err)
- } else if cache_result.Data.(map[string]*model.User) != nil {
- t.Log(cache_result.Etag)
- t.Log(result.Etag)
- t.Fatal("cache should be empty")
- }
- }
-
- th.App.UpdateConfig(func(cfg *model.Config) { cfg.PrivacySettings.ShowEmailAddress = false })
-
- if result, err := th.BasicClient.GetProfiles(0, 100, ""); err != nil {
- t.Fatal(err)
- } else {
- users := result.Data.(map[string]*model.User)
-
- if len(users) < 1 {
- t.Fatal("map was wrong length")
- }
-
- for _, user := range users {
- if user.Email != "" {
- t.Fatal("problem with show email")
- }
- }
- }
-}
-
-func TestGetProfilesByIds(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- th.App.UpdateConfig(func(cfg *model.Config) { cfg.PrivacySettings.ShowEmailAddress = true })
-
- if result, err := th.BasicClient.GetProfilesByIds([]string{th.BasicUser.Id}); err != nil {
- t.Fatal(err)
- } else {
- users := result.Data.(map[string]*model.User)
-
- if len(users) != 1 {
- t.Fatal("map was wrong length")
- }
-
- for _, user := range users {
- if user.Email == "" {
- t.Fatal("problem with show email")
- }
- }
- }
-
- th.App.UpdateConfig(func(cfg *model.Config) { cfg.PrivacySettings.ShowEmailAddress = false })
-
- if result, err := th.BasicClient.GetProfilesByIds([]string{th.BasicUser.Id}); err != nil {
- t.Fatal(err)
- } else {
- users := result.Data.(map[string]*model.User)
-
- if len(users) != 1 {
- t.Fatal("map was wrong length")
- }
-
- for _, user := range users {
- if user.Email != "" {
- t.Fatal("problem with show email")
- }
- }
- }
-
- if result, err := th.BasicClient.GetProfilesByIds([]string{th.BasicUser.Id, th.BasicUser2.Id}); err != nil {
- t.Fatal(err)
- } else {
- users := result.Data.(map[string]*model.User)
-
- if len(users) != 2 {
- t.Fatal("map was wrong length")
- }
- }
-}
-
-func TestGetAudits(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- Client := th.BasicClient
-
- team := model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
- rteam, _ := Client.CreateTeam(&team)
-
- Client.Logout()
-
- user := model.User{Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "passwd1"}
- ruser, _ := Client.CreateUser(&user, "")
- th.LinkUserToTeam(ruser.Data.(*model.User), rteam.Data.(*model.Team))
- store.Must(th.App.Srv.Store.User().VerifyEmail(ruser.Data.(*model.User).Id))
-
- time.Sleep(100 * time.Millisecond)
-
- Client.Login(user.Email, user.Password)
-
- time.Sleep(100 * time.Millisecond)
-
- if result, err := Client.GetAudits(ruser.Data.(*model.User).Id, ""); err != nil {
- t.Fatal(err)
- } else {
-
- if len(result.Data.(model.Audits)) != 1 {
- t.Fatal(result.Data.(model.Audits))
- }
-
- if cache_result, err := Client.GetAudits(ruser.Data.(*model.User).Id, result.Etag); err != nil {
- t.Fatal(err)
- } else if cache_result.Data.(model.Audits) != nil {
- t.Fatal("cache should be empty")
- }
- }
-
- if _, err := Client.GetAudits("FORBIDDENERROR", ""); err == nil {
- t.Fatal("audit log shouldn't exist")
- }
-}
-
-func TestUserCreateImage(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- Client := th.BasicClient
-
- b, err := app.CreateProfileImage("Corey Hulen", "eo1zkdr96pdj98pjmq8zy35wba", th.App.Config().FileSettings.InitialFont)
- if err != nil {
- t.Fatal(err)
- }
-
- rdr := bytes.NewReader(b)
- img, _, err2 := image.Decode(rdr)
- if err2 != nil {
- t.Fatal(err)
- }
-
- colorful := color.RGBA{116, 49, 196, 255}
-
- if img.At(1, 1) != colorful {
- t.Fatal("Failed to create correct color")
- }
-
- team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
- team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
-
- user := &model.User{Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "passwd1"}
- user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
- th.LinkUserToTeam(user, team)
- store.Must(th.App.Srv.Store.User().VerifyEmail(user.Id))
-
- Client.Login(user.Email, "passwd1")
-
- if resp, err := Client.DoApiGet("/users/"+user.Id+"/image", "", ""); err != nil {
- t.Fatal(err)
- } else {
- etag := resp.Header.Get(model.HEADER_ETAG_SERVER)
- resp2, _ := Client.DoApiGet("/users/"+user.Id+"/image", "", etag)
- if resp2.StatusCode == 304 {
- t.Fatal("Shouldn't have hit etag")
- }
- }
-
- if *th.App.Config().FileSettings.DriverName == model.IMAGE_DRIVER_S3 {
- endpoint := th.App.Config().FileSettings.AmazonS3Endpoint
- accessKey := th.App.Config().FileSettings.AmazonS3AccessKeyId
- secretKey := th.App.Config().FileSettings.AmazonS3SecretAccessKey
- secure := *th.App.Config().FileSettings.AmazonS3SSL
- signV2 := *th.App.Config().FileSettings.AmazonS3SignV2
- region := th.App.Config().FileSettings.AmazonS3Region
- s3Clnt, err := s3New(endpoint, accessKey, secretKey, secure, signV2, region)
- if err != nil {
- t.Fatal(err)
- }
- bucket := th.App.Config().FileSettings.AmazonS3Bucket
- if err = s3Clnt.RemoveObject(bucket, "/users/"+user.Id+"/profile.png"); err != nil {
- t.Fatal(err)
- }
- } else {
- path := th.App.Config().FileSettings.Directory + "/users/" + user.Id + "/profile.png"
- if err := os.Remove(path); err != nil {
- t.Fatal("Couldn't remove file at " + path)
- }
- }
-}
-
-func TestUserUploadProfileImage(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- Client := th.BasicClient
-
- team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
- team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
-
- Client.Logout()
-
- user := &model.User{Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "passwd1"}
- user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
- th.LinkUserToTeam(user, team)
- store.Must(th.App.Srv.Store.User().VerifyEmail(user.Id))
-
- if *th.App.Config().FileSettings.DriverName != "" {
-
- body := &bytes.Buffer{}
- writer := multipart.NewWriter(body)
-
- if _, upErr := Client.UploadProfileFile(body.Bytes(), writer.FormDataContentType()); upErr == nil {
- t.Fatal("Should have errored")
- }
-
- Client.Login(user.Email, "passwd1")
- Client.SetTeamId(team.Id)
-
- if _, upErr := Client.UploadProfileFile(body.Bytes(), writer.FormDataContentType()); upErr == nil {
- t.Fatal("Should have errored")
- }
-
- part, err := writer.CreateFormFile("blargh", "test.png")
- if err != nil {
- t.Fatal(err)
- }
-
- path, _ := utils.FindDir("tests")
- file, err := os.Open(filepath.Join(path, "test.png"))
- if err != nil {
- t.Fatal(err)
- }
- defer file.Close()
-
- _, err = io.Copy(part, file)
- if err != nil {
- t.Fatal(err)
- }
-
- if err := writer.Close(); err != nil {
- t.Fatal(err)
- }
-
- if _, upErr := Client.UploadProfileFile(body.Bytes(), writer.FormDataContentType()); upErr == nil {
- t.Fatal("Should have errored")
- }
-
- file2, err := os.Open(path + "/test.png")
- if err != nil {
- t.Fatal(err)
- }
- defer file2.Close()
-
- body = &bytes.Buffer{}
- writer = multipart.NewWriter(body)
-
- part, err = writer.CreateFormFile("image", "test.png")
- if err != nil {
- t.Fatal(err)
- }
-
- if _, err := io.Copy(part, file2); err != nil {
- t.Fatal(err)
- }
-
- if err := writer.Close(); err != nil {
- t.Fatal(err)
- }
-
- if _, upErr := Client.UploadProfileFile(body.Bytes(), writer.FormDataContentType()); upErr != nil {
- t.Fatal(upErr)
- }
-
- Client.DoApiGet("/users/"+user.Id+"/image", "", "")
-
- if *th.App.Config().FileSettings.DriverName == model.IMAGE_DRIVER_S3 {
- endpoint := th.App.Config().FileSettings.AmazonS3Endpoint
- accessKey := th.App.Config().FileSettings.AmazonS3AccessKeyId
- secretKey := th.App.Config().FileSettings.AmazonS3SecretAccessKey
- secure := *th.App.Config().FileSettings.AmazonS3SSL
- signV2 := *th.App.Config().FileSettings.AmazonS3SignV2
- region := th.App.Config().FileSettings.AmazonS3Region
- s3Clnt, err := s3New(endpoint, accessKey, secretKey, secure, signV2, region)
- if err != nil {
- t.Fatal(err)
- }
- bucket := th.App.Config().FileSettings.AmazonS3Bucket
- if err = s3Clnt.RemoveObject(bucket, "/users/"+user.Id+"/profile.png"); err != nil {
- t.Fatal(err)
- }
- } else {
- path := th.App.Config().FileSettings.Directory + "users/" + user.Id + "/profile.png"
- if err := os.Remove(path); err != nil {
- t.Fatal("Couldn't remove file at " + path)
- }
- }
- } else {
- body := &bytes.Buffer{}
- writer := multipart.NewWriter(body)
- if _, upErr := Client.UploadProfileFile(body.Bytes(), writer.FormDataContentType()); upErr.StatusCode != http.StatusNotImplemented {
- t.Fatal("Should have failed with 501 - Not Implemented")
- }
- }
-}
-
-func TestUserUpdate(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- Client := th.BasicClient
-
- team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
- team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
-
- Client.Logout()
-
- user := &model.User{Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "passwd1", Roles: ""}
- user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
- th.LinkUserToTeam(user, team)
- store.Must(th.App.Srv.Store.User().VerifyEmail(user.Id))
-
- if _, err := Client.UpdateUser(user); err == nil {
- t.Fatal("Should have errored")
- }
-
- Client.Login(user.Email, "passwd1")
- Client.SetTeamId(team.Id)
-
- user.Nickname = "Jim Jimmy"
- user.Roles = model.SYSTEM_ADMIN_ROLE_ID
- user.LastPasswordUpdate = 123
-
- if result, err := Client.UpdateUser(user); err != nil {
- t.Fatal(err)
- } else {
- if result.Data.(*model.User).Nickname != "Jim Jimmy" {
- t.Fatal("Nickname did not update properly")
- }
- if result.Data.(*model.User).Roles != model.SYSTEM_USER_ROLE_ID {
- t.Fatal("Roles should not have updated")
- }
- if result.Data.(*model.User).LastPasswordUpdate == 123 {
- t.Fatal("LastPasswordUpdate should not have updated")
- }
- }
-
- user2 := &model.User{Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "passwd1"}
- user2 = Client.Must(Client.CreateUser(user2, "")).Data.(*model.User)
- th.LinkUserToTeam(user2, team)
- store.Must(th.App.Srv.Store.User().VerifyEmail(user2.Id))
-
- Client.Login(user2.Email, "passwd1")
- Client.SetTeamId(team.Id)
-
- user.Nickname = "Tim Timmy"
-
- if _, err := Client.UpdateUser(user); err == nil {
- t.Fatal("Should have errored")
- }
-}
-
-func TestUserUpdatePassword(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- Client := th.BasicClient
-
- team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
- team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
-
- Client.Logout()
- Client.SetTeamId(team.Id)
-
- user := &model.User{Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "passwd1"}
- user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
- th.LinkUserToTeam(user, team)
- store.Must(th.App.Srv.Store.User().VerifyEmail(user.Id))
-
- if _, err := Client.UpdateUserPassword(user.Id, "passwd1", "newpasswd1"); err == nil {
- t.Fatal("Should have errored")
- }
-
- Client.Login(user.Email, "passwd1")
-
- if _, err := Client.UpdateUserPassword("123", "passwd1", "newpwd"); err == nil {
- t.Fatal("Should have errored")
- }
-
- if _, err := Client.UpdateUserPassword(user.Id, "", "newpwd"); err == nil {
- t.Fatal("Should have errored")
- }
-
- if _, err := Client.UpdateUserPassword(user.Id, "passwd1", "npwd"); err == nil {
- t.Fatal("Should have errored")
- }
-
- if _, err := Client.UpdateUserPassword("12345678901234567890123456", "passwd1", "newpwd1"); err == nil {
- t.Fatal("Should have errored")
- }
-
- if _, err := Client.UpdateUserPassword(user.Id, "badpwd", "newpwd"); err == nil {
- t.Fatal("Should have errored")
- }
-
- if _, err := Client.UpdateUserPassword(user.Id, "passwd1", "newpwd1"); err != nil {
- t.Fatal(err)
- }
-
- updatedUser := Client.Must(Client.GetUser(user.Id, "")).Data.(*model.User)
- if updatedUser.LastPasswordUpdate == user.LastPasswordUpdate {
- t.Fatal("LastPasswordUpdate should have changed")
- }
-
- if _, err := Client.Login(user.Email, "newpwd1"); err != nil {
- t.Fatal(err)
- }
-
- // Test lockout
- th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.MaximumLoginAttempts = 2 })
-
- // Fail twice
- if _, err := Client.UpdateUserPassword(user.Id, "badpwd", "newpwd"); err == nil {
- t.Fatal("Should have errored")
- }
- if _, err := Client.UpdateUserPassword(user.Id, "badpwd", "newpwd"); err == nil {
- t.Fatal("Should have errored")
- }
-
- // Should fail because account is locked out
- if _, err := Client.UpdateUserPassword(user.Id, "newpwd1", "newpwd2"); err == nil {
- t.Fatal("Should have errored")
- }
-
- user2 := &model.User{Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "passwd1"}
- user2 = Client.Must(Client.CreateUser(user2, "")).Data.(*model.User)
- th.LinkUserToTeam(user2, team)
-
- Client.Login(user2.Email, "passwd1")
-
- if _, err := Client.UpdateUserPassword(user.Id, "passwd1", "newpwd"); err == nil {
- t.Fatal("Should have errored")
- }
-}
-
-func TestUserUpdateRoles(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- Client := th.BasicClient
-
- team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
- team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
-
- Client.Logout()
-
- user := &model.User{Email: "success+" + model.NewId() + "@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "passwd1"}
- user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
- th.LinkUserToTeam(user, team)
- store.Must(th.App.Srv.Store.User().VerifyEmail(user.Id))
-
- user2 := &model.User{Email: "success+" + model.NewId() + "@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "passwd1"}
- user2 = Client.Must(Client.CreateUser(user2, "")).Data.(*model.User)
- th.LinkUserToTeam(user2, team)
- store.Must(th.App.Srv.Store.User().VerifyEmail(user2.Id))
-
- if _, err := Client.UpdateUserRoles(user.Id, ""); err == nil {
- t.Fatal("Should have errored, not logged in")
- }
-
- Client.Login(user2.Email, "passwd1")
- Client.SetTeamId(team.Id)
-
- if _, err := Client.UpdateUserRoles(user.Id, ""); err == nil {
- t.Fatal("Should have errored, not admin")
- }
-
- team2 := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
- team2 = Client.Must(Client.CreateTeam(team2)).Data.(*model.Team)
-
- user3 := &model.User{Email: "success+" + model.NewId() + "@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "passwd1"}
- user3 = Client.Must(Client.CreateUser(user3, "")).Data.(*model.User)
- th.LinkUserToTeam(user3, team2)
- store.Must(th.App.Srv.Store.User().VerifyEmail(user3.Id))
-
- Client.Login(user3.Email, "passwd1")
- Client.SetTeamId(team2.Id)
-
- if _, err := Client.UpdateUserRoles(user2.Id, ""); err == nil {
- t.Fatal("Should have errored, wrong team")
- }
-
- Client.Login(user.Email, "passwd1")
-
- if _, err := Client.UpdateUserRoles("junk", ""); err == nil {
- t.Fatal("Should have errored, bad id")
- }
-
- if _, err := Client.UpdateUserRoles("system_admin", ""); err == nil {
- t.Fatal("Should have errored, we want to avoid this mistake")
- }
-
- if _, err := Client.UpdateUserRoles("12345678901234567890123456", ""); err == nil {
- t.Fatal("Should have errored, bad id")
- }
-
- if _, err := Client.UpdateUserRoles(user2.Id, "junk"); err == nil {
- t.Fatal("Should have errored, bad role")
- }
-}
-
-func TestUserUpdateRolesMoreCases(t *testing.T) {
- th := Setup().InitSystemAdmin().InitBasic()
- defer th.TearDown()
-
- th.SystemAdminClient.SetTeamId(th.BasicTeam.Id)
- th.LinkUserToTeam(th.SystemAdminUser, th.BasicTeam)
-
- const BASIC_USER = "system_user"
- const SYSTEM_ADMIN = "system_user system_admin"
-
- // user 1 is trying to promote user 2
- if _, err := th.BasicClient.UpdateUserRoles(th.BasicUser2.Id, SYSTEM_ADMIN); err == nil {
- t.Fatal("Should have errored, basic user is not a system admin")
- }
-
- // user 1 is trying to demote system admin
- if _, err := th.BasicClient.UpdateUserRoles(th.SystemAdminUser.Id, BASIC_USER); err == nil {
- t.Fatal("Should have errored, can only be system admin")
- }
-
- // user 1 is trying to promote himself
- if _, err := th.BasicClient.UpdateUserRoles(th.BasicUser.Id, SYSTEM_ADMIN); err == nil {
- t.Fatal("Should have errored, can only be system admin")
- }
-
- // System admin promoting user 2
- if _, err := th.SystemAdminClient.UpdateUserRoles(th.BasicUser2.Id, SYSTEM_ADMIN); err != nil {
- t.Fatal("Should have succeeded since they are system admin")
- }
-
- // System admin demoting user 2
- if _, err := th.SystemAdminClient.UpdateUserRoles(th.BasicUser2.Id, BASIC_USER); err != nil {
- t.Fatal("Should have succeeded since they are system admin")
- }
-
- // Setting user to team admin should have no effect on results
- th.BasicClient.Must(th.SystemAdminClient.UpdateTeamRoles(th.BasicUser.Id, "team_user team_admin"))
-
- // user 1 is trying to promote user 2
- if _, err := th.BasicClient.UpdateUserRoles(th.BasicUser2.Id, SYSTEM_ADMIN); err == nil {
- t.Fatal("Should have errored, basic user is not a system admin")
- }
-
- // user 1 is trying to demote system admin
- if _, err := th.BasicClient.UpdateUserRoles(th.SystemAdminUser.Id, BASIC_USER); err == nil {
- t.Fatal("Should have errored, can only be system admin")
- }
-
- // user 1 is trying to promote himself
- if _, err := th.BasicClient.UpdateUserRoles(th.BasicUser.Id, SYSTEM_ADMIN); err == nil {
- t.Fatal("Should have errored, can only be system admin")
- }
-
- // system admin demoting himself
- if _, err := th.SystemAdminClient.UpdateUserRoles(th.SystemAdminUser.Id, BASIC_USER); err != nil {
- t.Fatal("Should have succeeded since they are system admin")
- }
-}
-
-func TestUserUpdateDeviceId(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- Client := th.BasicClient
-
- team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
- team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
-
- user := &model.User{Email: "success+" + model.NewId() + "@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "passwd1"}
- user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
- th.LinkUserToTeam(user, team)
- store.Must(th.App.Srv.Store.User().VerifyEmail(user.Id))
-
- Client.Login(user.Email, "passwd1")
- Client.SetTeamId(team.Id)
- deviceId := model.PUSH_NOTIFY_APPLE + ":1234567890"
-
- if _, err := Client.AttachDeviceId(deviceId); err != nil {
- t.Fatal(err)
- }
-
- if result := <-th.App.Srv.Store.Session().GetSessions(user.Id); result.Err != nil {
- t.Fatal(result.Err)
- } else {
- sessions := result.Data.([]*model.Session)
-
- if sessions[0].DeviceId != deviceId {
- t.Fatal("Missing device Id")
- }
- }
-}
-
-func TestUserUpdateDeviceId2(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- Client := th.BasicClient
-
- team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
- team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
-
- user := &model.User{Email: "success+" + model.NewId() + "@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "passwd1"}
- user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
- th.LinkUserToTeam(user, team)
- store.Must(th.App.Srv.Store.User().VerifyEmail(user.Id))
-
- Client.Login(user.Email, "passwd1")
- Client.SetTeamId(team.Id)
- deviceId := model.PUSH_NOTIFY_APPLE_REACT_NATIVE + ":1234567890"
-
- if _, err := Client.AttachDeviceId(deviceId); err != nil {
- t.Fatal(err)
- }
-
- if result := <-th.App.Srv.Store.Session().GetSessions(user.Id); result.Err != nil {
- t.Fatal(result.Err)
- } else {
- sessions := result.Data.([]*model.Session)
-
- if sessions[0].DeviceId != deviceId {
- t.Fatal("Missing device Id")
- }
- }
-}
-
-func TestUserUpdateActive(t *testing.T) {
- th := Setup().InitBasic().InitSystemAdmin()
- defer th.TearDown()
-
- Client := th.BasicClient
- SystemAdminClient := th.SystemAdminClient
-
- team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
- team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
-
- team2 := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
- team2 = Client.Must(Client.CreateTeam(team2)).Data.(*model.Team)
-
- Client.Logout()
-
- user := &model.User{Email: "success+" + model.NewId() + "@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "passwd1"}
- user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
- th.LinkUserToTeam(user, team)
- store.Must(th.App.Srv.Store.User().VerifyEmail(user.Id))
-
- user2 := &model.User{Email: "success+" + model.NewId() + "@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "passwd1"}
- user2 = Client.Must(Client.CreateUser(user2, "")).Data.(*model.User)
- th.LinkUserToTeam(user2, team)
- store.Must(th.App.Srv.Store.User().VerifyEmail(user2.Id))
-
- if _, err := Client.UpdateActive(user.Id, false); err == nil {
- t.Fatal("Should have errored, not logged in")
- }
-
- Client.Login(user2.Email, "passwd1")
- Client.SetTeamId(team.Id)
-
- if _, err := Client.UpdateActive(user.Id, false); err == nil {
- t.Fatal("Should have errored, not admin")
- }
-
- Client.Must(Client.Logout())
-
- user3 := &model.User{Email: "success+" + model.NewId() + "@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "passwd1"}
- user3 = Client.Must(Client.CreateUser(user3, "")).Data.(*model.User)
- th.LinkUserToTeam(user2, team2)
- store.Must(th.App.Srv.Store.User().VerifyEmail(user3.Id))
-
- Client.Login(user3.Email, "passwd1")
- Client.SetTeamId(team2.Id)
-
- if _, err := Client.UpdateActive(user.Id, false); err == nil {
- t.Fatal("Should have errored, not yourself")
- }
-
- Client.Login(user.Email, "passwd1")
- Client.SetTeamId(team.Id)
-
- if _, err := Client.UpdateActive("junk", false); err == nil {
- t.Fatal("Should have errored, bad id")
- }
-
- if _, err := Client.UpdateActive("12345678901234567890123456", false); err == nil {
- t.Fatal("Should have errored, bad id")
- }
-
- th.App.SetStatusOnline(user3.Id, "", false)
-
- if _, err := SystemAdminClient.UpdateActive(user3.Id, false); err != nil {
- t.Fatal(err)
- }
-
- if status, err := th.App.GetStatus(user3.Id); err != nil {
- t.Fatal(err)
- } else if status.Status != model.STATUS_OFFLINE {
- t.Fatal("status should have been set to offline")
- }
-}
-
-func TestUserPermDelete(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- Client := th.BasicClient
-
- team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
- team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
-
- user1 := &model.User{Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "passwd1"}
- user1 = Client.Must(Client.CreateUser(user1, "")).Data.(*model.User)
- th.LinkUserToTeam(user1, team)
- store.Must(th.App.Srv.Store.User().VerifyEmail(user1.Id))
-
- Client.Login(user1.Email, "passwd1")
- Client.SetTeamId(team.Id)
-
- channel1 := &model.Channel{DisplayName: "TestGetPosts", Name: "zz" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
- channel1 = Client.Must(Client.CreateChannel(channel1)).Data.(*model.Channel)
-
- post1 := &model.Post{ChannelId: channel1.Id, Message: "search for post1"}
- post1 = Client.Must(Client.CreatePost(post1)).Data.(*model.Post)
-
- post2 := &model.Post{ChannelId: channel1.Id, Message: "search for post2"}
- post2 = Client.Must(Client.CreatePost(post2)).Data.(*model.Post)
-
- post3 := &model.Post{ChannelId: channel1.Id, Message: "#hashtag search for post3"}
- post3 = Client.Must(Client.CreatePost(post3)).Data.(*model.Post)
-
- post4 := &model.Post{ChannelId: channel1.Id, Message: "hashtag for post4"}
- post4 = Client.Must(Client.CreatePost(post4)).Data.(*model.Post)
-
- c := &Context{}
- c.RequestId = model.NewId()
- c.IpAddress = "test"
-
- err := th.App.PermanentDeleteUser(user1)
- if err != nil {
- t.Fatal(err)
- }
-
- Client.ClearOAuthToken()
-}
-
-func TestSendPasswordReset(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- Client := th.BasicClient
-
- team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
- team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
-
- user := &model.User{Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "passwd1"}
- user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
- th.LinkUserToTeam(user, team)
- store.Must(th.App.Srv.Store.User().VerifyEmail(user.Id))
-
- Client.Logout()
-
- if result, err := Client.SendPasswordReset(user.Email); err != nil {
- t.Fatal(err)
- } else {
- resp := result.Data.(map[string]string)
- if resp["email"] != user.Email {
- t.Fatal("wrong email")
- }
- }
-
- if _, err := Client.SendPasswordReset("junk@junk.com"); err != nil {
- t.Fatal("Should have errored - bad email")
- }
-
- if _, err := Client.SendPasswordReset(""); err == nil {
- t.Fatal("Should have errored - no email")
- }
-
- authData := model.NewId()
- user2 := &model.User{Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", AuthData: &authData, AuthService: "random"}
- user2 = Client.Must(Client.CreateUser(user2, "")).Data.(*model.User)
- th.LinkUserToTeam(user2, team)
- store.Must(th.App.Srv.Store.User().VerifyEmail(user2.Id))
-
- if _, err := Client.SendPasswordReset(user2.Email); err == nil {
- t.Fatal("should have errored - SSO user can't send reset password link")
- }
-}
-
-/*func TestResetPassword(t *testing.T) {
- th := Setup().InitSystemAdmin()
- Client := th.SystemAdminClient
- team := th.SystemAdminTeam
-
- user := &model.User{Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "passwd1"}
- user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
- th.LinkUserToTeam(user, team)
- store.Must(th.App.Srv.Store.User().VerifyEmail(user.Id))
-
- //Delete all the messages before check the reset password
- utils.DeleteMailBox(user.Email)
-
- Client.Must(Client.SendPasswordReset(user.Email))
-
- //Check if the email was send to the rigth email address and the recovery key match
- var resultsMailbox utils.JSONMessageHeaderInbucket
- err := utils.RetryInbucket(5, func() error {
- var err error
- resultsMailbox, err = utils.GetMailBox(user.Email)
- return err
- })
- if err != nil {
- t.Log(err)
- t.Log("No email was received, maybe due load on the server. Disabling this verification")
- }
-
- var recoveryTokenString string
- if err == nil && len(resultsMailbox) > 0 {
- if !strings.ContainsAny(resultsMailbox[0].To[0], user.Email) {
- t.Fatal("Wrong To recipient")
- } else {
- if resultsEmail, err := utils.GetMessageFromMailbox(user.Email, resultsMailbox[0].ID); err == nil {
- loc := strings.Index(resultsEmail.Body.Text, "token=")
- if loc == -1 {
- t.Log(recoveryTokenString)
- t.Log(resultsEmail.Body.Text)
- t.Fatal("Code not found in email")
- }
- loc += 6
- recoveryTokenString = resultsEmail.Body.Text[loc : loc+model.TOKEN_SIZE]
- t.Log(resultsEmail.Body.Text)
- }
- }
- }
-
- var recoveryToken *model.Token
- if result := <-th.App.Srv.Store.Token().GetByToken(recoveryTokenString); result.Err != nil {
- t.Log(recoveryTokenString)
- t.Fatal(result.Err)
- } else {
- recoveryToken = result.Data.(*model.Token)
- }
-
- if recoveryToken.Token != recoveryTokenString {
- t.Fatal("Did not send the correct token. DB: "+recoveryToken.Token, " Sent: "+recoveryTokenString)
- }
-
- if _, err := Client.ResetPassword(recoveryToken.Token, ""); err == nil {
- t.Fatal("Should have errored - no password")
- }
-
- if _, err := Client.ResetPassword(recoveryToken.Token, "newp"); err == nil {
- t.Fatal("Should have errored - password too short")
- }
-
- if _, err := Client.ResetPassword("", "newpwd"); err == nil {
- t.Fatal("Should have errored - no code")
- }
-
- if _, err := Client.ResetPassword("junk", "newpwd"); err == nil {
- t.Fatal("Should have errored - bad code")
- }
-
- code := ""
- for i := 0; i < model.TOKEN_SIZE; i++ {
- code += "a"
- }
- if _, err := Client.ResetPassword(code, "newpwd1"); err == nil {
- t.Fatal("Should have errored - bad code")
- }
-
- if _, err := Client.ResetPassword(recoveryToken.Token, "newpwd1"); err != nil {
- t.Log(recoveryToken.Token)
- t.Fatal(err)
- }
-
-}*/
-
-func TestUserUpdateNotify(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- Client := th.BasicClient
-
- team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
- team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
-
- Client.Logout()
-
- user := &model.User{Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "passwd1", Roles: ""}
- user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
- th.LinkUserToTeam(user, team)
- store.Must(th.App.Srv.Store.User().VerifyEmail(user.Id))
-
- data := make(map[string]string)
- data["user_id"] = user.Id
- data["email"] = "true"
- data["desktop"] = "all"
- data["desktop_sound"] = "false"
- data["comments"] = "any"
-
- if _, err := Client.UpdateUserNotify(data); err == nil {
- t.Fatal("Should have errored - not logged in")
- }
-
- Client.Login(user.Email, "passwd1")
- Client.SetTeamId(team.Id)
-
- if result, err := Client.UpdateUserNotify(data); err != nil {
- t.Fatal(err)
- } else {
- if result.Data.(*model.User).NotifyProps["desktop"] != data["desktop"] {
- t.Fatal("NotifyProps did not update properly - desktop")
- }
- if result.Data.(*model.User).NotifyProps["desktop_sound"] != data["desktop_sound"] {
- t.Fatal("NotifyProps did not update properly - desktop_sound")
- }
- if result.Data.(*model.User).NotifyProps["email"] != data["email"] {
- t.Fatal("NotifyProps did not update properly - email")
- }
- if result.Data.(*model.User).NotifyProps["comments"] != data["comments"] {
- t.Fatal("NotifyProps did not update properly - comments")
- }
- }
-
- if _, err := Client.UpdateUserNotify(nil); err == nil {
- t.Fatal("Should have errored")
- }
-
- data["user_id"] = "junk"
- if _, err := Client.UpdateUserNotify(data); err == nil {
- t.Fatal("Should have errored - junk user id")
- }
-
- data["user_id"] = "12345678901234567890123456"
- if _, err := Client.UpdateUserNotify(data); err == nil {
- t.Fatal("Should have errored - bad user id")
- }
-
- data["user_id"] = user.Id
- data["desktop"] = ""
- if _, err := Client.UpdateUserNotify(data); err == nil {
- t.Fatal("Should have errored - empty desktop notify")
- }
-
- data["desktop"] = "all"
- data["desktop_sound"] = ""
- if _, err := Client.UpdateUserNotify(data); err == nil {
- t.Fatal("Should have errored - empty desktop sound")
- }
-
- data["desktop_sound"] = "false"
- data["email"] = ""
- if _, err := Client.UpdateUserNotify(data); err == nil {
- t.Fatal("Should have errored - empty email")
- }
-
- data["email"] = "true"
- data["comments"] = ""
- if _, err := Client.UpdateUserNotify(data); err == nil {
- t.Fatal("Should have errored - empty comments")
- }
-}
-
-func TestFuzzyUserCreate(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- Client := th.BasicClient
-
- team := model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
- rteam, _ := Client.CreateTeam(&team)
-
- Client.Logout()
-
- for i := 0; i < len(utils.FUZZY_STRINGS_NAMES) || i < len(utils.FUZZY_STRINGS_EMAILS); i++ {
- testName := "Name"
- testEmail := "test@nowhere.com"
-
- if i < len(utils.FUZZY_STRINGS_NAMES) {
- testName = utils.FUZZY_STRINGS_NAMES[i]
- }
- if i < len(utils.FUZZY_STRINGS_EMAILS) {
- testEmail = utils.FUZZY_STRINGS_EMAILS[i]
- }
-
- user := model.User{Email: strings.ToLower(model.NewId()) + testEmail, Nickname: testName, Password: "hello1"}
-
- ruser, err := Client.CreateUser(&user, "")
- if err != nil {
- t.Fatal(err)
- }
-
- th.LinkUserToTeam(ruser.Data.(*model.User), rteam.Data.(*model.Team))
- }
-}
-
-func TestEmailToOAuth(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- Client := th.BasicClient
-
- team := model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
- rteam, _ := Client.CreateTeam(&team)
-
- Client.Logout()
-
- user := model.User{Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "passwd1"}
- ruser := Client.Must(Client.CreateUser(&user, "")).Data.(*model.User)
- th.LinkUserToTeam(ruser, rteam.Data.(*model.Team))
- store.Must(th.App.Srv.Store.User().VerifyEmail(ruser.Id))
-
- m := map[string]string{}
- if _, err := Client.EmailToOAuth(m); err == nil {
- t.Fatal("should have failed - empty data")
- }
-
- m["password"] = "passwd1"
- _, err := Client.EmailToOAuth(m)
- if err == nil {
- t.Fatal("should have failed - missing team_name, service, email")
- }
-
- m["team_name"] = team.Name
- if _, err := Client.EmailToOAuth(m); err == nil {
- t.Fatal("should have failed - missing service, email")
- }
-
- m["service"] = "someservice"
- if _, err := Client.EmailToOAuth(m); err == nil {
- t.Fatal("should have failed - missing email")
- }
-
- m["team_name"] = "junk"
- if _, err := Client.EmailToOAuth(m); err == nil {
- t.Fatal("should have failed - bad team name")
- }
-
- m["team_name"] = team.Name
- m["email"] = "junk"
- if _, err := Client.EmailToOAuth(m); err == nil {
- t.Fatal("should have failed - bad email")
- }
-
- m["email"] = ruser.Email
- m["password"] = "junk"
- if _, err := Client.EmailToOAuth(m); err == nil {
- t.Fatal("should have failed - bad password")
- }
-}
-
-func TestOAuthToEmail(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- Client := th.BasicClient
-
- team := model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
- rteam, _ := Client.CreateTeam(&team)
-
- Client.Logout()
-
- user := model.User{Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "passwd1"}
- ruser := Client.Must(Client.CreateUser(&user, "")).Data.(*model.User)
- th.LinkUserToTeam(ruser, rteam.Data.(*model.Team))
- store.Must(th.App.Srv.Store.User().VerifyEmail(ruser.Id))
-
- user2 := model.User{Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "passwd1"}
- ruser2 := Client.Must(Client.CreateUser(&user2, "")).Data.(*model.User)
- th.LinkUserToTeam(ruser2, rteam.Data.(*model.Team))
- store.Must(th.App.Srv.Store.User().VerifyEmail(ruser2.Id))
-
- m := map[string]string{}
- if _, err := Client.OAuthToEmail(m); err == nil {
- t.Fatal("should have failed - not logged in")
- }
-
- Client.Login(user.Email, user.Password)
-
- if _, err := Client.OAuthToEmail(m); err == nil {
- t.Fatal("should have failed - empty data")
- }
-
- m["password"] = "passwd1"
- _, err := Client.OAuthToEmail(m)
- if err == nil {
- t.Fatal("should have failed - missing team_name, service, email")
- }
-
- m["team_name"] = team.Name
- if _, err := Client.OAuthToEmail(m); err == nil {
- t.Fatal("should have failed - missing email")
- }
-
- m["team_name"] = team.Name
- m["email"] = "junk"
- if _, err := Client.OAuthToEmail(m); err == nil {
- t.Fatal("should have failed - bad email")
- }
-
- m["email"] = ruser2.Email
- if _, err := Client.OAuthToEmail(m); err == nil {
- t.Fatal("should have failed - wrong user")
- }
-}
-
-func TestLDAPToEmail(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- Client := th.BasicClient
-
- team := model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
- rteam, _ := Client.CreateTeam(&team)
-
- user := model.User{Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "passwd1"}
- ruser := Client.Must(Client.CreateUser(&user, "")).Data.(*model.User)
- th.LinkUserToTeam(ruser, rteam.Data.(*model.Team))
- store.Must(th.App.Srv.Store.User().VerifyEmail(ruser.Id))
-
- Client.Login(user.Email, user.Password)
-
- m := map[string]string{}
- if _, err := Client.LDAPToEmail(m); err == nil {
- t.Fatal("should have failed - empty data")
- }
-
- m["email_password"] = "passwd1"
- _, err := Client.LDAPToEmail(m)
- if err == nil {
- t.Fatal("should have failed - missing team_name, ldap_password, email")
- }
-
- m["team_name"] = team.Name
- if _, err := Client.LDAPToEmail(m); err == nil {
- t.Fatal("should have failed - missing email, ldap_password")
- }
-
- m["ldap_password"] = "passwd1"
- if _, err := Client.LDAPToEmail(m); err == nil {
- t.Fatal("should have failed - missing email")
- }
-
- m["email"] = ruser.Email
- m["team_name"] = "junk"
- if _, err := Client.LDAPToEmail(m); err == nil {
- t.Fatal("should have failed - bad team name")
- }
-
- m["team_name"] = team.Name
- m["email"] = "junk"
- if _, err := Client.LDAPToEmail(m); err == nil {
- t.Fatal("should have failed - bad email")
- }
-
- m["email"] = user.Email
- if _, err := Client.LDAPToEmail(m); err == nil {
- t.Fatal("should have failed - user is not an AD/LDAP user")
- }
-}
-
-func TestEmailToLDAP(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- Client := th.BasicClient
-
- team := model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
- rteam, _ := Client.CreateTeam(&team)
-
- user := model.User{Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "passwd1"}
- ruser := Client.Must(Client.CreateUser(&user, "")).Data.(*model.User)
- th.LinkUserToTeam(ruser, rteam.Data.(*model.Team))
- store.Must(th.App.Srv.Store.User().VerifyEmail(ruser.Id))
-
- Client.Login(user.Email, user.Password)
-
- m := map[string]string{}
- if _, err := Client.EmailToLDAP(m); err == nil {
- t.Fatal("should have failed - empty data")
- }
-
- m["email_password"] = "passwd1"
- _, err := Client.EmailToLDAP(m)
- if err == nil {
- t.Fatal("should have failed - missing team_name, ldap_id, ldap_password, email")
- }
-
- m["team_name"] = team.Name
- if _, err := Client.EmailToLDAP(m); err == nil {
- t.Fatal("should have failed - missing email, ldap_password, ldap_id")
- }
-
- m["ldap_id"] = "someid"
- if _, err := Client.EmailToLDAP(m); err == nil {
- t.Fatal("should have failed - missing email, ldap_password")
- }
-
- m["ldap_password"] = "passwd1"
- if _, err := Client.EmailToLDAP(m); err == nil {
- t.Fatal("should have failed - missing email")
- }
-
- m["email"] = ruser.Email
- m["team_name"] = "junk"
- if _, err := Client.EmailToLDAP(m); err == nil {
- t.Fatal("should have failed - bad team name")
- }
-
- m["team_name"] = team.Name
- m["email"] = "junk"
- if _, err := Client.EmailToLDAP(m); err == nil {
- t.Fatal("should have failed - bad email")
- }
-
- m["email"] = user.Email
- m["email_password"] = "junk"
- if _, err := Client.EmailToLDAP(m); err == nil {
- t.Fatal("should have failed - bad password")
- }
-
- m["email_password"] = "passwd1"
- if _, err := Client.EmailToLDAP(m); err == nil {
- t.Fatal("should have failed - missing ldap bits or user")
- }
-}
-
-func TestMeInitialLoad(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- if result, err := th.BasicClient.GetInitialLoad(); err != nil {
- t.Fatal(err)
- } else {
- il := result.Data.(*model.InitialLoad)
-
- if il.User == nil {
- t.Fatal("should be valid")
- }
-
- if il.Preferences == nil {
- t.Fatal("should be valid")
- }
-
- if len(il.Teams) != 1 {
- t.Fatal("should be valid")
- }
-
- if len(il.TeamMembers) != 1 {
- t.Fatal("should be valid")
- }
-
- if len(il.ClientCfg) == 0 {
- t.Fatal("should be valid")
- }
-
- if len(il.LicenseCfg) == 0 {
- t.Fatal("should be valid")
- }
- }
-
- th.BasicClient.Logout()
-
- if result, err := th.BasicClient.GetInitialLoad(); err != nil {
- t.Fatal(err)
- } else {
- il := result.Data.(*model.InitialLoad)
-
- if il.User != nil {
- t.Fatal("should be valid")
- }
-
- if il.Preferences != nil {
- t.Fatal("should be valid")
- }
-
- if len(il.Teams) != 0 {
- t.Fatal("should be valid")
- }
-
- if len(il.TeamMembers) != 0 {
- t.Fatal("should be valid")
- }
-
- if len(il.ClientCfg) == 0 {
- t.Fatal("should be valid")
- }
-
- if len(il.LicenseCfg) == 0 {
- t.Fatal("should be valid")
- }
- }
-
-}
-
-func TestGenerateMfaSecret(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- Client := th.BasicClient
-
- team := model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
- rteam, _ := Client.CreateTeam(&team)
-
- user := model.User{Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "passwd1"}
- ruser, _ := Client.CreateUser(&user, "")
- th.LinkUserToTeam(ruser.Data.(*model.User), rteam.Data.(*model.Team))
- store.Must(th.App.Srv.Store.User().VerifyEmail(ruser.Data.(*model.User).Id))
-
- Client.Logout()
-
- if _, err := Client.GenerateMfaSecret(); err == nil {
- t.Fatal("should have failed - not logged in")
- }
-
- Client.Login(user.Email, user.Password)
-
- if _, err := Client.GenerateMfaSecret(); err == nil {
- t.Fatal("should have failed - not licensed")
- }
-
- // need to add more test cases when license and config can be configured for tests
-}
-
-func TestUpdateMfa(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- Client := th.BasicClient
-
- th.App.SetLicense(nil)
-
- team := model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
- rteam, _ := Client.CreateTeam(&team)
-
- user := model.User{Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "passwd1"}
- ruser, _ := Client.CreateUser(&user, "")
- th.LinkUserToTeam(ruser.Data.(*model.User), rteam.Data.(*model.Team))
- store.Must(th.App.Srv.Store.User().VerifyEmail(ruser.Data.(*model.User).Id))
-
- Client.Logout()
-
- if _, err := Client.UpdateMfa(true, "123456"); err == nil {
- t.Fatal("should have failed - not logged in")
- }
-
- Client.Login(user.Email, user.Password)
-
- if _, err := Client.UpdateMfa(true, ""); err == nil {
- t.Fatal("should have failed - no token")
- }
-
- if _, err := Client.UpdateMfa(true, "123456"); err == nil {
- t.Fatal("should have failed - not licensed")
- }
-
- th.App.SetLicense(model.NewTestLicense("mfa"))
- th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableMultifactorAuthentication = true })
-
- if _, err := Client.UpdateMfa(true, "123456"); err == nil {
- t.Fatal("should have failed - bad token")
- }
-
- // need to add more test cases when enterprise bits can be loaded into tests
-}
-
-func TestCheckMfa(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- Client := th.BasicClient
-
- team := model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
- rteam, _ := Client.CreateTeam(&team)
-
- Client.Logout()
-
- user := model.User{Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "passwd1"}
- ruser, _ := Client.CreateUser(&user, "")
- th.LinkUserToTeam(ruser.Data.(*model.User), rteam.Data.(*model.Team))
- store.Must(th.App.Srv.Store.User().VerifyEmail(ruser.Data.(*model.User).Id))
-
- if result, err := Client.CheckMfa(user.Email); err != nil {
- t.Fatal(err)
- } else {
- resp := result.Data.(map[string]string)
- if resp["mfa_required"] != "false" {
- t.Fatal("mfa should not be required")
- }
- }
-
- // need to add more test cases when enterprise bits can be loaded into tests
-}
-
-func TestUserTyping(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- Client := th.BasicClient
- WebSocketClient, err := th.CreateWebSocketClient()
- if err != nil {
- t.Fatal(err)
- }
- defer WebSocketClient.Close()
- WebSocketClient.Listen()
-
- time.Sleep(300 * time.Millisecond)
- if resp := <-WebSocketClient.ResponseChannel; resp.Status != model.STATUS_OK {
- t.Fatal("should have responded OK to authentication challenge")
- }
-
- WebSocketClient.UserTyping("", "")
- time.Sleep(300 * time.Millisecond)
- if resp := <-WebSocketClient.ResponseChannel; resp.Error.Id != "api.websocket_handler.invalid_param.app_error" {
- t.Fatal("should have been invalid param response")
- }
-
- th.LoginBasic2()
- Client.Must(Client.JoinChannel(th.BasicChannel.Id))
-
- WebSocketClient2, err2 := th.CreateWebSocketClient()
- if err2 != nil {
- t.Fatal(err2)
- }
- defer WebSocketClient2.Close()
- WebSocketClient2.Listen()
-
- time.Sleep(300 * time.Millisecond)
-
- WebSocketClient.UserTyping(th.BasicChannel.Id, "")
-
- time.Sleep(300 * time.Millisecond)
-
- stop := make(chan bool)
- eventHit := false
-
- go func() {
- for {
- select {
- case resp := <-WebSocketClient2.EventChannel:
- if resp.Event == model.WEBSOCKET_EVENT_TYPING && resp.Data["user_id"].(string) == th.BasicUser.Id {
- eventHit = true
- }
- case <-stop:
- return
- }
- }
- }()
-
- time.Sleep(1000 * time.Millisecond)
-
- stop <- true
-
- if !eventHit {
- t.Fatal("did not receive typing event")
- }
-
- WebSocketClient.UserTyping(th.BasicChannel.Id, "someparentid")
-
- time.Sleep(300 * time.Millisecond)
-
- eventHit = false
-
- go func() {
- for {
- select {
- case resp := <-WebSocketClient2.EventChannel:
- if resp.Event == model.WEBSOCKET_EVENT_TYPING && resp.Data["parent_id"] == "someparentid" {
- eventHit = true
- }
- case <-stop:
- return
- }
- }
- }()
-
- time.Sleep(300 * time.Millisecond)
-
- stop <- true
-
- if !eventHit {
- t.Fatal("did not receive typing event")
- }
-}
-
-func TestGetProfilesInChannel(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- Client := th.BasicClient
-
- th.App.UpdateConfig(func(cfg *model.Config) { cfg.PrivacySettings.ShowEmailAddress = true })
-
- if result, err := Client.GetProfilesInChannel(th.BasicChannel.Id, 0, 100, ""); err != nil {
- t.Fatal(err)
- } else {
- users := result.Data.(map[string]*model.User)
-
- if len(users) < 1 {
- t.Fatal("map was wrong length")
- }
-
- for _, user := range users {
- if user.Email == "" {
- t.Fatal("problem with show email")
- }
- }
- }
-
- th.LoginBasic2()
-
- if _, err := Client.GetProfilesInChannel(th.BasicChannel.Id, 0, 100, ""); err == nil {
- t.Fatal("should not have access")
- }
-
- Client.Must(Client.JoinChannel(th.BasicChannel.Id))
-
- th.App.UpdateConfig(func(cfg *model.Config) { cfg.PrivacySettings.ShowEmailAddress = false })
-
- if result, err := Client.GetProfilesInChannel(th.BasicChannel.Id, 0, 100, ""); err != nil {
- t.Fatal(err)
- } else {
- users := result.Data.(map[string]*model.User)
-
- if len(users) < 1 {
- t.Fatal("map was wrong length")
- }
-
- found := false
- for _, user := range users {
- if user.Email != "" {
- t.Fatal("problem with show email")
- }
- if user.Id == th.BasicUser2.Id {
- found = true
- }
- }
-
- if !found {
- t.Fatal("should have found profile")
- }
- }
-
- user := model.User{Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "passwd1"}
- Client.Must(Client.CreateUser(&user, ""))
-
- Client.Login(user.Email, "passwd1")
- Client.SetTeamId("junk")
-
- if _, err := Client.GetProfilesInChannel(th.BasicChannel.Id, 0, 100, ""); err == nil {
- t.Fatal("should not have access")
- }
-}
-
-func TestGetProfilesNotInChannel(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- Client := th.BasicClient
-
- th.App.UpdateConfig(func(cfg *model.Config) { cfg.PrivacySettings.ShowEmailAddress = true })
-
- if result, err := Client.GetProfilesNotInChannel(th.BasicChannel.Id, 0, 100, ""); err != nil {
- t.Fatal(err)
- } else {
- users := result.Data.(map[string]*model.User)
-
- if len(users) < 1 {
- t.Fatal("map was wrong length")
- }
-
- found := false
- for _, user := range users {
- if user.Email == "" {
- t.Fatal("problem with show email")
- }
- if user.Id == th.BasicUser2.Id {
- found = true
- }
- }
-
- if !found {
- t.Fatal("should have found profile")
- }
- }
-
- user := &model.User{Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "passwd1"}
- user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
- th.LinkUserToTeam(user, th.BasicTeam)
-
- th.LoginBasic2()
-
- if _, err := Client.GetProfilesNotInChannel(th.BasicChannel.Id, 0, 100, ""); err == nil {
- t.Fatal("should not have access")
- }
-
- Client.Must(Client.JoinChannel(th.BasicChannel.Id))
-
- th.App.UpdateConfig(func(cfg *model.Config) { cfg.PrivacySettings.ShowEmailAddress = false })
-
- if result, err := Client.GetProfilesNotInChannel(th.BasicChannel.Id, 0, 100, ""); err != nil {
- t.Fatal(err)
- } else {
- users := result.Data.(map[string]*model.User)
-
- if len(users) < 1 {
- t.Fatal("map was wrong length")
- }
-
- found := false
- for _, user := range users {
- if user.Email != "" {
- t.Fatal("problem with show email")
- }
- if user.Id == th.BasicUser2.Id {
- found = true
- }
- }
-
- if found {
- t.Fatal("should not have found profile")
- }
- }
-
- user2 := model.User{Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "passwd1"}
- Client.Must(Client.CreateUser(&user2, ""))
-
- Client.Login(user2.Email, "passwd1")
- Client.SetTeamId(th.BasicTeam.Id)
-
- if _, err := Client.GetProfilesNotInChannel(th.BasicChannel.Id, 0, 100, ""); err == nil {
- t.Fatal("should not have access")
- }
-}
-
-func TestSearchUsers(t *testing.T) {
- th := Setup().InitBasic().InitSystemAdmin()
- defer th.TearDown()
-
- Client := th.BasicClient
-
- inactiveUser := th.CreateUser(Client)
- th.LinkUserToTeam(inactiveUser, th.BasicTeam)
- th.SystemAdminClient.Must(th.SystemAdminClient.UpdateActive(inactiveUser.Id, false))
-
- if result, err := Client.SearchUsers(model.UserSearch{Term: th.BasicUser.Username}); err != nil {
- t.Fatal(err)
- } else {
- users := result.Data.([]*model.User)
-
- found := false
- for _, user := range users {
- if user.Id == th.BasicUser.Id {
- found = true
- }
- }
-
- if !found {
- t.Fatal("should have found profile")
- }
- }
-
- if result, err := Client.SearchUsers(model.UserSearch{Term: inactiveUser.Username, TeamId: th.BasicTeam.Id}); err != nil {
- t.Fatal(err)
- } else {
- users := result.Data.([]*model.User)
-
- found := false
- for _, user := range users {
- if user.Id == inactiveUser.Id {
- found = true
- }
- }
-
- if found {
- t.Fatal("should not have found inactive user")
- }
- }
-
- if result, err := Client.SearchUsers(model.UserSearch{Term: inactiveUser.Username, TeamId: th.BasicTeam.Id, AllowInactive: true}); err != nil {
- t.Fatal(err)
- } else {
- users := result.Data.([]*model.User)
-
- found := false
- for _, user := range users {
- if user.Id == inactiveUser.Id {
- found = true
- }
- }
-
- if !found {
- t.Fatal("should have found inactive user")
- }
- }
-
- if result, err := Client.SearchUsers(model.UserSearch{Term: th.BasicUser.Username, InChannelId: th.BasicChannel.Id}); err != nil {
- t.Fatal(err)
- } else {
- users := result.Data.([]*model.User)
-
- if len(users) != 1 {
- t.Fatal("map was wrong length")
- }
-
- found := false
- for _, user := range users {
- if user.Id == th.BasicUser.Id {
- found = true
- }
- }
-
- if !found {
- t.Fatal("should have found profile")
- }
- }
-
- if result, err := Client.SearchUsers(model.UserSearch{Term: th.BasicUser2.Username, NotInChannelId: th.BasicChannel.Id}); err != nil {
- t.Fatal(err)
- } else {
- users := result.Data.([]*model.User)
-
- if len(users) != 1 {
- t.Fatal("map was wrong length")
- }
-
- found1 := false
- found2 := false
- for _, user := range users {
- if user.Id == th.BasicUser.Id {
- found1 = true
- } else if user.Id == th.BasicUser2.Id {
- found2 = true
- }
- }
-
- if found1 {
- t.Fatal("should not have found profile")
- }
- if !found2 {
- t.Fatal("should have found profile")
- }
- }
-
- if result, err := Client.SearchUsers(model.UserSearch{Term: th.BasicUser2.Username, TeamId: th.BasicTeam.Id, NotInChannelId: th.BasicChannel.Id}); err != nil {
- t.Fatal(err)
- } else {
- users := result.Data.([]*model.User)
-
- if len(users) != 1 {
- t.Fatal("map was wrong length")
- }
-
- found1 := false
- found2 := false
- for _, user := range users {
- if user.Id == th.BasicUser.Id {
- found1 = true
- } else if user.Id == th.BasicUser2.Id {
- found2 = true
- }
- }
-
- if found1 {
- t.Fatal("should not have found profile")
- }
- if !found2 {
- t.Fatal("should have found profile")
- }
- }
-
- if result, err := Client.SearchUsers(model.UserSearch{Term: th.BasicUser.Username, TeamId: "junk", NotInChannelId: th.BasicChannel.Id}); err != nil {
- t.Fatal(err)
- } else {
- users := result.Data.([]*model.User)
-
- if len(users) != 0 {
- t.Fatal("map was wrong length")
- }
- }
-
- th.App.UpdateConfig(func(cfg *model.Config) { cfg.PrivacySettings.ShowEmailAddress = false })
- th.App.UpdateConfig(func(cfg *model.Config) { cfg.PrivacySettings.ShowFullName = false })
-
- privacyEmailPrefix := strings.ToLower(model.NewId())
- privacyUser := &model.User{Email: privacyEmailPrefix + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "passwd1", FirstName: model.NewId(), LastName: "Jimmers"}
- privacyUser = Client.Must(Client.CreateUser(privacyUser, "")).Data.(*model.User)
- th.LinkUserToTeam(privacyUser, th.BasicTeam)
-
- if result, err := Client.SearchUsers(model.UserSearch{Term: privacyUser.FirstName}); err != nil {
- t.Fatal(err)
- } else {
- users := result.Data.([]*model.User)
-
- found := false
- for _, user := range users {
- if user.Id == privacyUser.Id {
- found = true
- }
- }
-
- if found {
- t.Fatal("should not have found profile")
- }
- }
-
- th.App.UpdateConfig(func(cfg *model.Config) { cfg.PrivacySettings.ShowEmailAddress = true })
-
- if result, err := Client.SearchUsers(model.UserSearch{Term: privacyUser.FirstName}); err != nil {
- t.Fatal(err)
- } else {
- users := result.Data.([]*model.User)
-
- found := false
- for _, user := range users {
- if user.Id == privacyUser.Id {
- found = true
- }
- }
-
- if found {
- t.Fatal("should not have found profile")
- }
- }
-
- th.App.UpdateConfig(func(cfg *model.Config) { cfg.PrivacySettings.ShowEmailAddress = false })
- th.App.UpdateConfig(func(cfg *model.Config) { cfg.PrivacySettings.ShowFullName = true })
-
- if result, err := Client.SearchUsers(model.UserSearch{Term: privacyUser.FirstName}); err != nil {
- t.Fatal(err)
- } else {
- users := result.Data.([]*model.User)
-
- found := false
- for _, user := range users {
- if user.Id == privacyUser.Id {
- found = true
- }
- }
-
- if !found {
- t.Fatal("should have found profile")
- }
- }
-
- if result, err := Client.SearchUsers(model.UserSearch{Term: privacyEmailPrefix}); err != nil {
- t.Fatal(err)
- } else {
- users := result.Data.([]*model.User)
-
- found := false
- for _, user := range users {
- if user.Id == privacyUser.Id {
- found = true
- }
- }
-
- if found {
- t.Fatal("should not have found profile")
- }
- }
-
- th.App.UpdateConfig(func(cfg *model.Config) { cfg.PrivacySettings.ShowEmailAddress = true })
-
- if result, err := Client.SearchUsers(model.UserSearch{Term: privacyEmailPrefix}); err != nil {
- t.Fatal(err)
- } else {
- users := result.Data.([]*model.User)
-
- found := false
- for _, user := range users {
- if user.Id == privacyUser.Id {
- found = true
- }
- }
-
- if !found {
- t.Fatal("should have found profile")
- }
- }
-
- th.LoginBasic2()
-
- if result, err := Client.SearchUsers(model.UserSearch{Term: th.BasicUser.Username}); err != nil {
- t.Fatal(err)
- } else {
- users := result.Data.([]*model.User)
-
- found := false
- for _, user := range users {
- if user.Id == th.BasicUser.Id {
- found = true
- }
- }
-
- if !found {
- t.Fatal("should have found profile")
- }
- }
-
- if _, err := Client.SearchUsers(model.UserSearch{}); err == nil {
- t.Fatal("should have errored - blank term")
- }
-
- if _, err := Client.SearchUsers(model.UserSearch{Term: th.BasicUser.Username, InChannelId: th.BasicChannel.Id}); err == nil {
- t.Fatal("should not have access")
- }
-
- if _, err := Client.SearchUsers(model.UserSearch{Term: th.BasicUser.Username, NotInChannelId: th.BasicChannel.Id}); err == nil {
- t.Fatal("should not have access")
- }
-
- userWithoutTeam := th.CreateUser(Client)
- if result, err := Client.SearchUsers(model.UserSearch{Term: userWithoutTeam.Username}); err != nil {
- t.Fatal(err)
- } else {
- users := result.Data.([]*model.User)
-
- found := false
- for _, user := range users {
- if user.Id == userWithoutTeam.Id {
- found = true
- }
- }
-
- if !found {
- t.Fatal("should have found user without team")
- }
- }
-
- if result, err := Client.SearchUsers(model.UserSearch{Term: userWithoutTeam.Username, WithoutTeam: true}); err != nil {
- t.Fatal(err)
- } else {
- users := result.Data.([]*model.User)
-
- found := false
- for _, user := range users {
- if user.Id == userWithoutTeam.Id {
- found = true
- }
- }
-
- if !found {
- t.Fatal("should have found user without team")
- }
- }
-
- if result, err := Client.SearchUsers(model.UserSearch{Term: th.BasicUser.Username, WithoutTeam: true}); err != nil {
- t.Fatal(err)
- } else {
- users := result.Data.([]*model.User)
-
- found := false
- for _, user := range users {
- if user.Id == th.BasicUser.Id {
- found = true
- }
- }
-
- if found {
- t.Fatal("should not have found user with team")
- }
- }
-}
-
-func TestAutocompleteUsers(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- Client := th.BasicClient
-
- if result, err := Client.AutocompleteUsers(th.BasicUser.Username); err != nil {
- t.Fatal(err)
- } else {
- users := result.Data.([]*model.User)
- if len(users) != 1 {
- t.Fatal("should have returned 1 user in")
- }
- }
-
- if result, err := Client.AutocompleteUsers("amazonses"); err != nil {
- t.Fatal(err)
- } else {
- users := result.Data.([]*model.User)
- if len(users) != 0 {
- t.Fatal("should have returned 0 users - email should not autocomplete")
- }
- }
-
- if result, err := Client.AutocompleteUsers(""); err != nil {
- t.Fatal(err)
- } else {
- users := result.Data.([]*model.User)
- if len(users) == 0 {
- t.Fatal("should have many users")
- }
- }
-
- notInTeamUser := th.CreateUser(Client)
-
- if result, err := Client.AutocompleteUsers(notInTeamUser.Username); err != nil {
- t.Fatal(err)
- } else {
- users := result.Data.([]*model.User)
- if len(users) != 1 {
- t.Fatal("should have returned 1 user in")
- }
- }
-
- if result, err := Client.AutocompleteUsersInTeam(notInTeamUser.Username); err != nil {
- t.Fatal(err)
- } else {
- autocomplete := result.Data.(*model.UserAutocompleteInTeam)
- if len(autocomplete.InTeam) != 0 {
- t.Fatal("should have returned 0 users")
- }
- }
-
- if result, err := Client.AutocompleteUsersInTeam(th.BasicUser.Username); err != nil {
- t.Fatal(err)
- } else {
- autocomplete := result.Data.(*model.UserAutocompleteInTeam)
- if len(autocomplete.InTeam) != 1 {
- t.Fatal("should have returned 1 user in")
- }
- }
-
- if result, err := Client.AutocompleteUsersInTeam(th.BasicUser.Username[0:5]); err != nil {
- t.Fatal(err)
- } else {
- autocomplete := result.Data.(*model.UserAutocompleteInTeam)
- if len(autocomplete.InTeam) < 1 {
- t.Fatal("should have returned at least 1 user in")
- }
- }
-
- if result, err := Client.AutocompleteUsersInChannel(th.BasicUser.Username, th.BasicChannel.Id); err != nil {
- t.Fatal(err)
- } else {
- autocomplete := result.Data.(*model.UserAutocompleteInChannel)
- if len(autocomplete.InChannel) != 1 {
- t.Fatal("should have returned 1 user in")
- }
- if len(autocomplete.OutOfChannel) != 0 {
- t.Fatal("should have returned no users out")
- }
- }
-
- if result, err := Client.AutocompleteUsersInChannel("", th.BasicChannel.Id); err != nil {
- t.Fatal(err)
- } else {
- autocomplete := result.Data.(*model.UserAutocompleteInChannel)
- if len(autocomplete.InChannel) != 1 && autocomplete.InChannel[0].Id != th.BasicUser2.Id {
- t.Fatal("should have returned at 1 user in")
- }
- if len(autocomplete.OutOfChannel) != 1 && autocomplete.OutOfChannel[0].Id != th.BasicUser2.Id {
- t.Fatal("should have returned 1 user out")
- }
- }
-
- if result, err := Client.AutocompleteUsersInTeam(""); err != nil {
- t.Fatal(err)
- } else {
- autocomplete := result.Data.(*model.UserAutocompleteInTeam)
- if len(autocomplete.InTeam) != 2 {
- t.Fatal("should have returned 2 users in")
- }
- }
-
- th.App.UpdateConfig(func(cfg *model.Config) { cfg.PrivacySettings.ShowFullName = false })
-
- privacyUser := &model.User{Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "passwd1", FirstName: model.NewId(), LastName: "Jimmers"}
- privacyUser = Client.Must(Client.CreateUser(privacyUser, "")).Data.(*model.User)
- th.LinkUserToTeam(privacyUser, th.BasicTeam)
-
- if result, err := Client.AutocompleteUsersInChannel(privacyUser.FirstName, th.BasicChannel.Id); err != nil {
- t.Fatal(err)
- } else {
- autocomplete := result.Data.(*model.UserAutocompleteInChannel)
- if len(autocomplete.InChannel) != 0 {
- t.Fatal("should have returned no users")
- }
- if len(autocomplete.OutOfChannel) != 0 {
- t.Fatal("should have returned no users")
- }
- }
-
- if result, err := Client.AutocompleteUsersInTeam(privacyUser.FirstName); err != nil {
- t.Fatal(err)
- } else {
- autocomplete := result.Data.(*model.UserAutocompleteInTeam)
- if len(autocomplete.InTeam) != 0 {
- t.Fatal("should have returned no users")
- }
- }
-
- if _, err := Client.AutocompleteUsersInChannel("", "junk"); err == nil {
- t.Fatal("should have errored - bad channel id")
- }
-
- Client.SetTeamId("junk")
- if _, err := Client.AutocompleteUsersInChannel("", th.BasicChannel.Id); err == nil {
- t.Fatal("should have errored - bad team id")
- }
-
- if _, err := Client.AutocompleteUsersInTeam(""); err == nil {
- t.Fatal("should have errored - bad team id")
- }
-}
-
-func TestGetByUsername(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- Client := th.BasicClient
-
- if result, err := Client.GetByUsername(th.BasicUser.Username, ""); err != nil {
- t.Fatal("Failed to get user")
- } else {
- if result.Data.(*model.User).Password != "" {
- t.Fatal("User shouldn't have any password data once set")
- }
- }
-
- th.App.UpdateConfig(func(cfg *model.Config) { cfg.PrivacySettings.ShowEmailAddress = false })
- th.App.UpdateConfig(func(cfg *model.Config) { cfg.PrivacySettings.ShowFullName = false })
-
- if result, err := Client.GetByUsername(th.BasicUser2.Username, ""); err != nil {
- t.Fatal(err)
- } else {
- u := result.Data.(*model.User)
- if u.Password != "" {
- t.Fatal("password must be empty")
- }
- if *u.AuthData != "" {
- t.Fatal("auth data must be empty")
- }
- if u.Email != "" {
- t.Fatal("email should be sanitized")
- }
- }
-
-}
-
-func TestGetByEmail(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- Client := th.BasicClient
-
- if _, respMetdata := Client.GetByEmail(th.BasicUser.Email, ""); respMetdata.Error != nil {
- t.Fatal("Failed to get user by email")
- }
-
- th.App.UpdateConfig(func(cfg *model.Config) { cfg.PrivacySettings.ShowEmailAddress = false })
- th.App.UpdateConfig(func(cfg *model.Config) { cfg.PrivacySettings.ShowFullName = false })
-
- if user, respMetdata := Client.GetByEmail(th.BasicUser2.Email, ""); respMetdata.Error != nil {
- t.Fatal(respMetdata.Error)
- } else {
- if user.Password != "" {
- t.Fatal("password must be empty")
- }
- if *user.AuthData != "" {
- t.Fatal("auth data must be empty")
- }
- if user.Email != "" {
- t.Fatal("email should be sanitized")
- }
- }
-}
diff --git a/api/webhook.go b/api/webhook.go
deleted file mode 100644
index e3e12816a..000000000
--- a/api/webhook.go
+++ /dev/null
@@ -1,328 +0,0 @@
-// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-package api
-
-import (
- "net/http"
-
- "github.com/mattermost/mattermost-server/model"
-)
-
-func (api *API) InitWebhook() {
- api.BaseRoutes.Hooks.Handle("/incoming/create", api.ApiUserRequired(createIncomingHook)).Methods("POST")
- api.BaseRoutes.Hooks.Handle("/incoming/update", api.ApiUserRequired(updateIncomingHook)).Methods("POST")
- api.BaseRoutes.Hooks.Handle("/incoming/delete", api.ApiUserRequired(deleteIncomingHook)).Methods("POST")
- api.BaseRoutes.Hooks.Handle("/incoming/list", api.ApiUserRequired(getIncomingHooks)).Methods("GET")
-
- api.BaseRoutes.Hooks.Handle("/outgoing/create", api.ApiUserRequired(createOutgoingHook)).Methods("POST")
- api.BaseRoutes.Hooks.Handle("/outgoing/update", api.ApiUserRequired(updateOutgoingHook)).Methods("POST")
- api.BaseRoutes.Hooks.Handle("/outgoing/regen_token", api.ApiUserRequired(regenOutgoingHookToken)).Methods("POST")
- api.BaseRoutes.Hooks.Handle("/outgoing/delete", api.ApiUserRequired(deleteOutgoingHook)).Methods("POST")
- api.BaseRoutes.Hooks.Handle("/outgoing/list", api.ApiUserRequired(getOutgoingHooks)).Methods("GET")
-}
-
-func createIncomingHook(c *Context, w http.ResponseWriter, r *http.Request) {
- hook := model.IncomingWebhookFromJson(r.Body)
- if hook == nil {
- c.SetInvalidParam("createIncomingHook", "webhook")
- return
- }
-
- channel, err := c.App.GetChannel(hook.ChannelId)
- if err != nil {
- c.Err = err
- return
- }
-
- c.LogAudit("attempt")
-
- if !c.App.SessionHasPermissionToTeam(c.Session, channel.TeamId, model.PERMISSION_MANAGE_WEBHOOKS) {
- c.SetPermissionError(model.PERMISSION_MANAGE_WEBHOOKS)
- return
- }
-
- if channel.Type != model.CHANNEL_OPEN && !c.App.SessionHasPermissionToChannel(c.Session, channel.Id, model.PERMISSION_READ_CHANNEL) {
- c.LogAudit("fail - bad channel permissions")
- c.SetPermissionError(model.PERMISSION_READ_CHANNEL)
- return
- }
-
- if incomingHook, err := c.App.CreateIncomingWebhookForChannel(c.Session.UserId, channel, hook); err != nil {
- c.Err = err
- return
- } else {
- c.LogAudit("success")
- w.Write([]byte(incomingHook.ToJson()))
- }
-}
-
-func updateIncomingHook(c *Context, w http.ResponseWriter, r *http.Request) {
-
- hook := model.IncomingWebhookFromJson(r.Body)
-
- if hook == nil {
- c.SetInvalidParam("updateIncomingHook", "webhook")
- return
- }
-
- c.LogAudit("attempt")
-
- oldHook, err := c.App.GetIncomingWebhook(hook.Id)
- if err != nil {
- c.Err = err
- return
- }
-
- if c.TeamId != oldHook.TeamId {
- c.Err = model.NewAppError("updateIncomingHook", "api.webhook.team_mismatch.app_error", nil, "user_id="+c.Session.UserId, http.StatusBadRequest)
- return
- }
-
- if !c.App.SessionHasPermissionToTeam(c.Session, oldHook.TeamId, model.PERMISSION_MANAGE_WEBHOOKS) {
- c.SetPermissionError(model.PERMISSION_MANAGE_WEBHOOKS)
- return
- }
-
- if c.Session.UserId != oldHook.UserId && !c.App.SessionHasPermissionToTeam(c.Session, oldHook.TeamId, model.PERMISSION_MANAGE_OTHERS_WEBHOOKS) {
- c.LogAudit("fail - inappropriate permissions")
- c.SetPermissionError(model.PERMISSION_MANAGE_OTHERS_WEBHOOKS)
- return
- }
-
- channel, err := c.App.GetChannel(hook.ChannelId)
- if err != nil {
- c.Err = err
- return
- }
-
- if channel.Type != model.CHANNEL_OPEN && !c.App.SessionHasPermissionToChannel(c.Session, channel.Id, model.PERMISSION_READ_CHANNEL) {
- c.LogAudit("fail - bad channel permissions")
- c.SetPermissionError(model.PERMISSION_READ_CHANNEL)
- return
- }
-
- rhook, err := c.App.UpdateIncomingWebhook(oldHook, hook)
- if err != nil {
- c.Err = err
- return
- }
-
- c.LogAudit("success")
- w.Write([]byte(rhook.ToJson()))
-}
-
-func deleteIncomingHook(c *Context, w http.ResponseWriter, r *http.Request) {
- props := model.MapFromJson(r.Body)
-
- id := props["id"]
- if len(id) == 0 {
- c.SetInvalidParam("deleteIncomingHook", "id")
- return
- }
-
- hook, err := c.App.GetIncomingWebhook(id)
- if err != nil {
- c.Err = err
- return
- }
-
- if !c.App.SessionHasPermissionToTeam(c.Session, c.TeamId, model.PERMISSION_MANAGE_WEBHOOKS) {
- c.SetPermissionError(model.PERMISSION_MANAGE_WEBHOOKS)
- return
- }
-
- c.LogAudit("attempt")
-
- if c.Session.UserId != hook.UserId && !c.App.SessionHasPermissionToTeam(c.Session, c.TeamId, model.PERMISSION_MANAGE_OTHERS_WEBHOOKS) {
- c.LogAudit("fail - inappropriate permissions")
- c.SetPermissionError(model.PERMISSION_MANAGE_OTHERS_WEBHOOKS)
- return
- }
-
- if err := c.App.DeleteIncomingWebhook(id); err != nil {
- c.LogAudit("fail")
- c.Err = err
- return
- }
-
- c.LogAudit("success")
- w.Write([]byte(model.MapToJson(props)))
-}
-
-func getIncomingHooks(c *Context, w http.ResponseWriter, r *http.Request) {
- if !c.App.SessionHasPermissionToTeam(c.Session, c.TeamId, model.PERMISSION_MANAGE_WEBHOOKS) {
- c.SetPermissionError(model.PERMISSION_MANAGE_WEBHOOKS)
- return
- }
-
- if hooks, err := c.App.GetIncomingWebhooksForTeamPage(c.TeamId, 0, 100); err != nil {
- c.Err = err
- return
- } else {
- w.Write([]byte(model.IncomingWebhookListToJson(hooks)))
- }
-}
-
-func createOutgoingHook(c *Context, w http.ResponseWriter, r *http.Request) {
- hook := model.OutgoingWebhookFromJson(r.Body)
- if hook == nil {
- c.SetInvalidParam("createOutgoingHook", "webhook")
- return
- }
-
- c.LogAudit("attempt")
-
- hook.TeamId = c.TeamId
- hook.CreatorId = c.Session.UserId
-
- if !c.App.SessionHasPermissionToTeam(c.Session, hook.TeamId, model.PERMISSION_MANAGE_WEBHOOKS) {
- c.SetPermissionError(model.PERMISSION_MANAGE_WEBHOOKS)
- return
- }
-
- if rhook, err := c.App.CreateOutgoingWebhook(hook); err != nil {
- c.LogAudit("fail")
- c.Err = err
- return
- } else {
- c.LogAudit("success")
- w.Write([]byte(rhook.ToJson()))
- }
-}
-
-func getOutgoingHooks(c *Context, w http.ResponseWriter, r *http.Request) {
- if !c.App.SessionHasPermissionToTeam(c.Session, c.TeamId, model.PERMISSION_MANAGE_WEBHOOKS) {
- c.SetPermissionError(model.PERMISSION_MANAGE_WEBHOOKS)
- return
- }
-
- if hooks, err := c.App.GetOutgoingWebhooksForTeamPage(c.TeamId, 0, 100); err != nil {
- c.Err = err
- return
- } else {
- w.Write([]byte(model.OutgoingWebhookListToJson(hooks)))
- }
-}
-
-func updateOutgoingHook(c *Context, w http.ResponseWriter, r *http.Request) {
- c.LogAudit("attempt")
-
- hook := model.OutgoingWebhookFromJson(r.Body)
-
- if hook == nil {
- c.SetInvalidParam("updateOutgoingHook", "webhook")
- return
- }
-
- oldHook, err := c.App.GetOutgoingWebhook(hook.Id)
- if err != nil {
- c.Err = err
- return
- }
-
- if c.TeamId != oldHook.TeamId {
- c.Err = model.NewAppError("updateOutgoingHook", "api.webhook.team_mismatch.app_error", nil, "user_id="+c.Session.UserId, http.StatusForbidden)
- return
- }
-
- if !c.App.SessionHasPermissionToTeam(c.Session, oldHook.TeamId, model.PERMISSION_MANAGE_WEBHOOKS) {
- c.LogAudit("fail - inappropriate permissions")
- c.SetPermissionError(model.PERMISSION_MANAGE_WEBHOOKS)
- return
- }
-
- if c.Session.UserId != oldHook.CreatorId && !c.App.SessionHasPermissionToTeam(c.Session, oldHook.TeamId, model.PERMISSION_MANAGE_OTHERS_WEBHOOKS) {
- c.LogAudit("fail - inappropriate permissions")
- c.SetPermissionError(model.PERMISSION_MANAGE_OTHERS_WEBHOOKS)
- return
- }
-
- rhook, err := c.App.UpdateOutgoingWebhook(oldHook, hook)
- if err != nil {
- c.Err = err
- return
- }
-
- c.LogAudit("success")
- w.Write([]byte(rhook.ToJson()))
-}
-
-func deleteOutgoingHook(c *Context, w http.ResponseWriter, r *http.Request) {
- props := model.MapFromJson(r.Body)
-
- id := props["id"]
- if len(id) == 0 {
- c.SetInvalidParam("deleteIncomingHook", "id")
- return
- }
-
- c.LogAudit("attempt")
-
- if !c.App.SessionHasPermissionToTeam(c.Session, c.TeamId, model.PERMISSION_MANAGE_WEBHOOKS) {
- c.SetPermissionError(model.PERMISSION_MANAGE_WEBHOOKS)
- return
- }
-
- hook, err := c.App.GetOutgoingWebhook(id)
- if err != nil {
- c.Err = err
- return
- }
-
- if c.Session.UserId != hook.CreatorId && !c.App.SessionHasPermissionToTeam(c.Session, hook.TeamId, model.PERMISSION_MANAGE_OTHERS_WEBHOOKS) {
- c.LogAudit("fail - inappropriate permissions")
- c.SetPermissionError(model.PERMISSION_MANAGE_OTHERS_WEBHOOKS)
- return
- }
-
- if err := c.App.DeleteOutgoingWebhook(id); err != nil {
- c.LogAudit("fail")
- c.Err = err
- return
- }
-
- c.LogAudit("success")
- w.Write([]byte(model.MapToJson(props)))
-}
-
-func regenOutgoingHookToken(c *Context, w http.ResponseWriter, r *http.Request) {
- props := model.MapFromJson(r.Body)
-
- id := props["id"]
- if len(id) == 0 {
- c.SetInvalidParam("regenOutgoingHookToken", "id")
- return
- }
-
- hook, err := c.App.GetOutgoingWebhook(id)
- if err != nil {
- c.Err = err
- return
- }
-
- c.LogAudit("attempt")
-
- if c.TeamId != hook.TeamId {
- c.Err = model.NewAppError("regenOutgoingHookToken", "api.webhook.team_mismatch.app_error", nil, "user_id="+c.Session.UserId, http.StatusForbidden)
- return
- }
-
- if !c.App.SessionHasPermissionToTeam(c.Session, hook.TeamId, model.PERMISSION_MANAGE_WEBHOOKS) {
- c.SetPermissionError(model.PERMISSION_MANAGE_WEBHOOKS)
- return
- }
-
- if c.Session.UserId != hook.CreatorId && !c.App.SessionHasPermissionToTeam(c.Session, c.TeamId, model.PERMISSION_MANAGE_OTHERS_WEBHOOKS) {
- c.LogAudit("fail - inappropriate permissions")
- c.SetPermissionError(model.PERMISSION_MANAGE_OTHERS_WEBHOOKS)
- return
- }
-
- if rhook, err := c.App.RegenOutgoingWebhookToken(hook); err != nil {
- c.Err = err
- return
- } else {
- w.Write([]byte(rhook.ToJson()))
- }
-}
diff --git a/api/webhook_test.go b/api/webhook_test.go
deleted file mode 100644
index c9ca7d783..000000000
--- a/api/webhook_test.go
+++ /dev/null
@@ -1,968 +0,0 @@
-// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-package api
-
-import (
- "testing"
-
- "github.com/mattermost/mattermost-server/model"
-)
-
-func TestCreateIncomingHook(t *testing.T) {
- th := Setup().InitSystemAdmin()
- defer th.TearDown()
-
- Client := th.SystemAdminClient
- user := th.SystemAdminUser
- team := th.SystemAdminTeam
- channel1 := th.CreateChannel(Client, team)
- channel2 := th.CreatePrivateChannel(Client, team)
- channel3 := th.CreateChannel(Client, team)
- user2 := th.CreateUser(Client)
- th.LinkUserToTeam(user2, team)
-
- defaultRolePermissions := th.SaveDefaultRolePermissions()
- defer func() {
- th.RestoreDefaultRolePermissions(defaultRolePermissions)
- }()
- th.AddPermissionToRole(model.PERMISSION_MANAGE_WEBHOOKS.Id, model.TEAM_ADMIN_ROLE_ID)
-
- th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableIncomingWebhooks = true })
-
- // Revoke permission from regular users.
- th.RemovePermissionFromRole(model.PERMISSION_MANAGE_WEBHOOKS.Id, model.TEAM_USER_ROLE_ID)
-
- hook := &model.IncomingWebhook{ChannelId: channel1.Id}
-
- var rhook *model.IncomingWebhook
- if result, err := Client.CreateIncomingWebhook(hook); err != nil {
- t.Fatal(err)
- } else {
- rhook = result.Data.(*model.IncomingWebhook)
- }
-
- if hook.ChannelId != rhook.ChannelId {
- t.Fatal("channel ids didn't match")
- }
-
- if rhook.UserId != user.Id {
- t.Fatal("user ids didn't match")
- }
-
- if rhook.TeamId != team.Id {
- t.Fatal("team ids didn't match")
- }
-
- hook = &model.IncomingWebhook{ChannelId: "junk"}
- if _, err := Client.CreateIncomingWebhook(hook); err == nil {
- t.Fatal("should have failed - bad channel id")
- }
-
- hook = &model.IncomingWebhook{ChannelId: channel2.Id, UserId: "123", TeamId: "456"}
- if result, err := Client.CreateIncomingWebhook(hook); err != nil {
- t.Fatal(err)
- } else {
- if result.Data.(*model.IncomingWebhook).UserId != user.Id {
- t.Fatal("bad user id wasn't overwritten")
- }
- if result.Data.(*model.IncomingWebhook).TeamId != team.Id {
- t.Fatal("bad team id wasn't overwritten")
- }
- }
-
- Client.Must(Client.LeaveChannel(channel3.Id))
-
- hook = &model.IncomingWebhook{ChannelId: channel3.Id, UserId: user.Id, TeamId: team.Id}
- if _, err := Client.CreateIncomingWebhook(hook); err != nil {
- t.Fatal(err)
- }
-
- Client.Logout()
- Client.Must(Client.LoginById(user2.Id, user2.Password))
- Client.SetTeamId(team.Id)
-
- hook = &model.IncomingWebhook{ChannelId: channel1.Id}
-
- if _, err := Client.CreateIncomingWebhook(hook); err == nil {
- t.Fatal("should have failed - not system/team admin")
- }
-
- Client.Logout()
- th.UpdateUserToTeamAdmin(user2, team)
- Client.Must(Client.LoginById(user2.Id, user2.Password))
- Client.SetTeamId(team.Id)
-
- if _, err := Client.CreateIncomingWebhook(hook); err != nil {
- t.Fatal(err)
- }
-
- // Grant permission to regular users.
- th.AddPermissionToRole(model.PERMISSION_MANAGE_WEBHOOKS.Id, model.TEAM_USER_ROLE_ID)
-
- if _, err := Client.CreateIncomingWebhook(hook); err != nil {
- t.Fatal(err)
- }
-
- hook = &model.IncomingWebhook{ChannelId: channel2.Id}
-
- if _, err := Client.CreateIncomingWebhook(hook); err == nil {
- t.Fatal("should have failed - channel is private and not a member")
- }
-
- th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableIncomingWebhooks = false })
-
- if _, err := Client.CreateIncomingWebhook(hook); err == nil {
- t.Fatal("should have errored - webhooks turned off")
- }
-}
-
-func TestUpdateIncomingHook(t *testing.T) {
- th := Setup().InitSystemAdmin()
- defer th.TearDown()
-
- Client := th.SystemAdminClient
- team := th.SystemAdminTeam
-
- channel1 := th.CreateChannel(Client, team)
- channel2 := th.CreatePrivateChannel(Client, team)
- channel3 := th.CreateChannel(Client, team)
-
- user2 := th.CreateUser(Client)
- th.LinkUserToTeam(user2, team)
-
- team2 := th.CreateTeam(Client)
- user3 := th.CreateUser(Client)
- th.LinkUserToTeam(user3, team2)
- th.UpdateUserToTeamAdmin(user3, team2)
-
- th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableIncomingWebhooks = true })
-
- defaultRolePermissions := th.SaveDefaultRolePermissions()
- defer func() {
- th.RestoreDefaultRolePermissions(defaultRolePermissions)
- }()
- th.AddPermissionToRole(model.PERMISSION_MANAGE_WEBHOOKS.Id, model.TEAM_ADMIN_ROLE_ID)
-
- hook := createIncomingWebhook(channel1.Id, Client, t)
-
- t.Run("UpdateIncomingHook", func(t *testing.T) {
- hook.DisplayName = "hook2"
- hook.Description = "description"
- hook.ChannelId = channel3.Id
-
- if result, err := Client.UpdateIncomingWebhook(hook); err != nil {
- t.Fatal("Update hook should not fail")
- } else {
- updatedHook := result.Data.(*model.IncomingWebhook)
-
- if updatedHook.DisplayName != "hook2" {
- t.Fatal("Hook name is not updated")
- }
-
- if updatedHook.Description != "description" {
- t.Fatal("Hook description is not updated")
- }
-
- if updatedHook.ChannelId != channel3.Id {
- t.Fatal("Hook channel is not updated")
- }
- }
- })
-
- t.Run("RetainCreateAt", func(t *testing.T) {
- hook2 := &model.IncomingWebhook{ChannelId: channel1.Id, CreateAt: 100}
-
- if result, err := Client.CreateIncomingWebhook(hook2); err != nil {
- t.Fatal("hook creation failed")
- } else {
- createdHook := result.Data.(*model.IncomingWebhook)
- createdHook.DisplayName = "Name2"
-
- if result, err := Client.UpdateIncomingWebhook(createdHook); err != nil {
- t.Fatal("Update hook should not fail")
- } else {
- updatedHook := result.Data.(*model.IncomingWebhook)
-
- if updatedHook.CreateAt != createdHook.CreateAt {
- t.Fatal("failed - hook create at should not be changed")
- }
- }
- }
- })
-
- t.Run("ModifyUpdateAt", func(t *testing.T) {
- hook.DisplayName = "Name3"
-
- if result, err := Client.UpdateIncomingWebhook(hook); err != nil {
- t.Fatal("Update hook should not fail")
- } else {
- updatedHook := result.Data.(*model.IncomingWebhook)
-
- if updatedHook.UpdateAt == hook.UpdateAt {
- t.Fatal("failed - hook updateAt is not updated")
- }
- }
- })
-
- t.Run("UpdateNonExistentHook", func(t *testing.T) {
- nonExistentHook := &model.IncomingWebhook{ChannelId: channel1.Id}
-
- if _, err := Client.UpdateIncomingWebhook(nonExistentHook); err == nil {
- t.Fatal("should have failed - update a non-existent hook")
- }
- })
-
- Client.Logout()
- Client.Must(Client.LoginById(user2.Id, user2.Password))
- Client.SetTeamId(team.Id)
- t.Run("UserIsNotAdminOfTeam", func(t *testing.T) {
- if _, err := Client.UpdateIncomingWebhook(hook); err == nil {
- t.Fatal("should have failed - user is not admin of team")
- }
- })
-
- th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableIncomingWebhooks = true })
-
- t.Run("OnlyAdminIntegrationsDisabled", func(t *testing.T) {
-
- // Grant permission to regular users.
- th.AddPermissionToRole(model.PERMISSION_MANAGE_WEBHOOKS.Id, model.TEAM_USER_ROLE_ID)
-
- t.Run("UpdateHookOfSameUser", func(t *testing.T) {
- sameUserHook := &model.IncomingWebhook{ChannelId: channel1.Id, UserId: user2.Id}
- if result, err := Client.CreateIncomingWebhook(sameUserHook); err != nil {
- t.Fatal("Hook creation failed")
- } else {
- sameUserHook = result.Data.(*model.IncomingWebhook)
- }
-
- if _, err := Client.UpdateIncomingWebhook(sameUserHook); err != nil {
- t.Fatal("should not fail - only admin integrations are disabled & hook of same user")
- }
- })
-
- t.Run("UpdateHookOfDifferentUser", func(t *testing.T) {
- if _, err := Client.UpdateIncomingWebhook(hook); err == nil {
- t.Fatal("should have failed - user does not have permissions to update other user's hooks")
- }
- })
- })
-
- // Revoke permission from regular users.
- th.RemovePermissionFromRole(model.PERMISSION_MANAGE_WEBHOOKS.Id, model.TEAM_USER_ROLE_ID)
-
- Client.Logout()
- th.UpdateUserToTeamAdmin(user2, team)
- Client.Must(Client.LoginById(user2.Id, user2.Password))
- Client.SetTeamId(team.Id)
- t.Run("UpdateByDifferentUser", func(t *testing.T) {
- if result, err := Client.UpdateIncomingWebhook(hook); err != nil {
- t.Fatal("Update hook should not fail")
- } else {
- updatedHook := result.Data.(*model.IncomingWebhook)
-
- if updatedHook.UserId == user2.Id {
- t.Fatal("Hook's creator userId is not retained")
- }
- }
- })
-
- t.Run("IncomingHooksDisabled", func(t *testing.T) {
- th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableIncomingWebhooks = false })
- if _, err := Client.UpdateIncomingWebhook(hook); err == nil {
- t.Fatal("should have failed - incoming hooks are disabled")
- }
- })
-
- t.Run("PrivateChannel", func(t *testing.T) {
- hook.ChannelId = channel2.Id
-
- if _, err := Client.UpdateIncomingWebhook(hook); err == nil {
- t.Fatal("should have failed - updating to a private channel where the user is not a member")
- }
- })
-
- t.Run("UpdateToNonExistentChannel", func(t *testing.T) {
- hook.ChannelId = "junk"
- if _, err := Client.UpdateIncomingWebhook(hook); err == nil {
- t.Fatal("should have failed - bad channel id")
- }
- })
-
- Client.Logout()
- Client.Must(Client.LoginById(user3.Id, user3.Password))
- Client.SetTeamId(team2.Id)
- t.Run("UpdateToADifferentTeam", func(t *testing.T) {
- if _, err := Client.UpdateIncomingWebhook(hook); err == nil {
- t.Fatal("should have failed - update to a different team is not allowed")
- }
- })
-}
-
-func createIncomingWebhook(channelID string, Client *model.Client, t *testing.T) *model.IncomingWebhook {
- hook := &model.IncomingWebhook{ChannelId: channelID}
- if result, err := Client.CreateIncomingWebhook(hook); err != nil {
- t.Fatal("Hook creation failed")
- } else {
- hook = result.Data.(*model.IncomingWebhook)
- }
-
- return hook
-}
-
-func createOutgoingWebhook(channelID string, callbackURLs []string, triggerWords []string, Client *model.Client, t *testing.T) *model.OutgoingWebhook {
- hook := &model.OutgoingWebhook{ChannelId: channelID, CallbackURLs: callbackURLs, TriggerWords: triggerWords}
- if result, err := Client.CreateOutgoingWebhook(hook); err != nil {
- t.Fatal("Hook creation failed")
- } else {
- hook = result.Data.(*model.OutgoingWebhook)
- }
-
- return hook
-}
-
-func TestListIncomingHooks(t *testing.T) {
- th := Setup().InitSystemAdmin()
- defer th.TearDown()
-
- Client := th.SystemAdminClient
- team := th.SystemAdminTeam
- channel1 := th.CreateChannel(Client, team)
- user2 := th.CreateUser(Client)
- th.LinkUserToTeam(user2, team)
-
- th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableIncomingWebhooks = true })
-
- defaultRolePermissions := th.SaveDefaultRolePermissions()
- defer func() {
- th.RestoreDefaultRolePermissions(defaultRolePermissions)
- }()
- th.AddPermissionToRole(model.PERMISSION_MANAGE_WEBHOOKS.Id, model.TEAM_ADMIN_ROLE_ID)
-
- // Revoke permission from regular users.
- th.RemovePermissionFromRole(model.PERMISSION_MANAGE_WEBHOOKS.Id, model.TEAM_USER_ROLE_ID)
-
- hook1 := &model.IncomingWebhook{ChannelId: channel1.Id}
- hook1 = Client.Must(Client.CreateIncomingWebhook(hook1)).Data.(*model.IncomingWebhook)
-
- hook2 := &model.IncomingWebhook{ChannelId: channel1.Id}
- hook2 = Client.Must(Client.CreateIncomingWebhook(hook2)).Data.(*model.IncomingWebhook)
-
- if result, err := Client.ListIncomingWebhooks(); err != nil {
- t.Fatal(err)
- } else {
- hooks := result.Data.([]*model.IncomingWebhook)
-
- if len(hooks) != 2 {
- t.Fatal("incorrect number of hooks")
- }
- }
-
- Client.Logout()
- Client.Must(Client.LoginById(user2.Id, user2.Password))
- Client.SetTeamId(team.Id)
-
- if _, err := Client.ListIncomingWebhooks(); err == nil {
- t.Fatal("should have errored - not system/team admin")
- }
-
- // Grant permission to regular users.
- th.AddPermissionToRole(model.PERMISSION_MANAGE_WEBHOOKS.Id, model.TEAM_USER_ROLE_ID)
-
- if _, err := Client.ListIncomingWebhooks(); err != nil {
- t.Fatal(err)
- }
-
- th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableIncomingWebhooks = false })
-
- if _, err := Client.ListIncomingWebhooks(); err == nil {
- t.Fatal("should have errored - webhooks turned off")
- }
-}
-
-func TestDeleteIncomingHook(t *testing.T) {
- th := Setup().InitSystemAdmin()
- defer th.TearDown()
-
- Client := th.SystemAdminClient
- team := th.SystemAdminTeam
- channel1 := th.CreateChannel(Client, team)
- user2 := th.CreateUser(Client)
- th.LinkUserToTeam(user2, team)
-
- th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableIncomingWebhooks = true })
-
- defaultRolePermissions := th.SaveDefaultRolePermissions()
- defer func() {
- th.RestoreDefaultRolePermissions(defaultRolePermissions)
- }()
- th.AddPermissionToRole(model.PERMISSION_MANAGE_WEBHOOKS.Id, model.TEAM_ADMIN_ROLE_ID)
-
- // Revoke permission from regular users.
- th.RemovePermissionFromRole(model.PERMISSION_MANAGE_WEBHOOKS.Id, model.TEAM_USER_ROLE_ID)
-
- hook := &model.IncomingWebhook{ChannelId: channel1.Id}
- hook = Client.Must(Client.CreateIncomingWebhook(hook)).Data.(*model.IncomingWebhook)
-
- if _, err := Client.DeleteIncomingWebhook(hook.Id); err != nil {
- t.Fatal(err)
- }
-
- if _, err := Client.DeleteIncomingWebhook("junk"); err == nil {
- t.Fatal("should have failed - bad id")
- }
-
- if _, err := Client.DeleteIncomingWebhook(""); err == nil {
- t.Fatal("should have failed - empty id")
- }
-
- hooks := Client.Must(Client.ListIncomingWebhooks()).Data.([]*model.IncomingWebhook)
- if len(hooks) != 0 {
- t.Fatal("delete didn't work properly")
- }
-
- hook = &model.IncomingWebhook{ChannelId: channel1.Id}
- hook = Client.Must(Client.CreateIncomingWebhook(hook)).Data.(*model.IncomingWebhook)
-
- Client.Logout()
- Client.Must(Client.LoginById(user2.Id, user2.Password))
- Client.SetTeamId(team.Id)
-
- if _, err := Client.DeleteIncomingWebhook(hook.Id); err == nil {
- t.Fatal("should have failed - not system/team admin")
- }
-
- // Grant permission to regular users.
- th.AddPermissionToRole(model.PERMISSION_MANAGE_WEBHOOKS.Id, model.TEAM_USER_ROLE_ID)
-
- if _, err := Client.DeleteIncomingWebhook(hook.Id); err == nil {
- t.Fatal("should have failed - not creator or team admin")
- }
-
- hook = &model.IncomingWebhook{ChannelId: channel1.Id}
- hook = Client.Must(Client.CreateIncomingWebhook(hook)).Data.(*model.IncomingWebhook)
-
- if _, err := Client.DeleteIncomingWebhook(hook.Id); err != nil {
- t.Fatal(err)
- }
-
- th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableIncomingWebhooks = false })
-
- if _, err := Client.DeleteIncomingWebhook(hook.Id); err == nil {
- t.Fatal("should have errored - webhooks turned off")
- }
-}
-
-func TestCreateOutgoingHook(t *testing.T) {
- th := Setup().InitSystemAdmin()
- defer th.TearDown()
-
- Client := th.SystemAdminClient
- user := th.SystemAdminUser
- team := th.SystemAdminTeam
- team2 := th.CreateTeam(Client)
- channel1 := th.CreateChannel(Client, team)
- channel2 := th.CreatePrivateChannel(Client, team)
- user2 := th.CreateUser(Client)
- th.LinkUserToTeam(user2, team)
- user3 := th.CreateUser(Client)
- th.LinkUserToTeam(user3, team2)
-
- th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableOutgoingWebhooks = true })
-
- defaultRolePermissions := th.SaveDefaultRolePermissions()
- defer func() {
- th.RestoreDefaultRolePermissions(defaultRolePermissions)
- }()
- th.AddPermissionToRole(model.PERMISSION_MANAGE_WEBHOOKS.Id, model.TEAM_ADMIN_ROLE_ID)
-
- // Revoke permission from regular users.
- th.RemovePermissionFromRole(model.PERMISSION_MANAGE_WEBHOOKS.Id, model.TEAM_USER_ROLE_ID)
-
- hook := &model.OutgoingWebhook{ChannelId: channel1.Id, CallbackURLs: []string{"http://nowhere.com"}}
-
- var rhook *model.OutgoingWebhook
- if result, err := Client.CreateOutgoingWebhook(hook); err != nil {
- t.Fatal(err)
- } else {
- rhook = result.Data.(*model.OutgoingWebhook)
- }
-
- if hook.ChannelId != rhook.ChannelId {
- t.Fatal("channel ids didn't match")
- }
-
- if rhook.CreatorId != user.Id {
- t.Fatal("user ids didn't match")
- }
-
- if rhook.TeamId != team.Id {
- t.Fatal("team ids didn't match")
- }
-
- hook = &model.OutgoingWebhook{ChannelId: channel1.Id, TriggerWords: []string{"cats", "dogs"}, CallbackURLs: []string{"http://nowhere.com", "http://cats.com"}}
- hook1 := &model.OutgoingWebhook{ChannelId: channel1.Id, TriggerWords: []string{"cats"}, CallbackURLs: []string{"http://nowhere.com"}}
-
- if _, err := Client.CreateOutgoingWebhook(hook); err != nil {
- t.Fatal("multiple trigger words and urls failed")
- }
-
- if _, err := Client.CreateOutgoingWebhook(hook1); err == nil {
- t.Fatal("should have failed - duplicate trigger words and urls")
- }
-
- hook = &model.OutgoingWebhook{ChannelId: "junk", CallbackURLs: []string{"http://nowhere.com"}}
- if _, err := Client.CreateOutgoingWebhook(hook); err == nil {
- t.Fatal("should have failed - bad channel id")
- }
-
- hook = &model.OutgoingWebhook{ChannelId: channel1.Id, CreatorId: "123", TeamId: "456", CallbackURLs: []string{"http://nowhere.com"}}
- if result, err := Client.CreateOutgoingWebhook(hook); err != nil {
- t.Fatal(err)
- } else {
- if result.Data.(*model.OutgoingWebhook).CreatorId != user.Id {
- t.Fatal("bad user id wasn't overwritten")
- }
- if result.Data.(*model.OutgoingWebhook).TeamId != team.Id {
- t.Fatal("bad team id wasn't overwritten")
- }
- }
-
- hook = &model.OutgoingWebhook{ChannelId: channel2.Id, CallbackURLs: []string{"http://nowhere.com"}}
- if _, err := Client.CreateOutgoingWebhook(hook); err == nil {
- t.Fatal("should have failed - private channel")
- }
-
- hook = &model.OutgoingWebhook{CallbackURLs: []string{"http://nowhere.com"}}
- if _, err := Client.CreateOutgoingWebhook(hook); err == nil {
- t.Fatal("should have failed - blank channel and trigger words")
- }
-
- Client.Logout()
- Client.Must(Client.LoginById(user2.Id, user2.Password))
- Client.SetTeamId(team.Id)
-
- hook = &model.OutgoingWebhook{ChannelId: channel1.Id, CallbackURLs: []string{"http://nowhere.com"}}
- if _, err := Client.CreateOutgoingWebhook(hook); err == nil {
- t.Fatal("should have failed - not system/team admin")
- }
-
- // Grant permission to regular users.
- th.AddPermissionToRole(model.PERMISSION_MANAGE_WEBHOOKS.Id, model.TEAM_USER_ROLE_ID)
-
- if _, err := Client.CreateOutgoingWebhook(hook); err != nil {
- t.Fatal(err)
- }
-
- Client.Logout()
- Client.Must(Client.LoginById(user3.Id, user3.Password))
- Client.SetTeamId(team2.Id)
-
- if _, err := Client.CreateOutgoingWebhook(hook); err == nil {
- t.Fatal("should have failed - wrong team")
- }
-
- th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableOutgoingWebhooks = false })
-
- if _, err := Client.CreateOutgoingWebhook(hook); err == nil {
- t.Fatal("should have errored - webhooks turned off")
- }
-}
-
-func TestListOutgoingHooks(t *testing.T) {
- th := Setup().InitSystemAdmin()
- defer th.TearDown()
-
- Client := th.SystemAdminClient
- team := th.SystemAdminTeam
- channel1 := th.CreateChannel(Client, team)
- user2 := th.CreateUser(Client)
- th.LinkUserToTeam(user2, team)
-
- th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableOutgoingWebhooks = true })
-
- defaultRolePermissions := th.SaveDefaultRolePermissions()
- defer func() {
- th.RestoreDefaultRolePermissions(defaultRolePermissions)
- }()
- th.AddPermissionToRole(model.PERMISSION_MANAGE_WEBHOOKS.Id, model.TEAM_ADMIN_ROLE_ID)
-
- // Revoke permission from regular users.
- th.RemovePermissionFromRole(model.PERMISSION_MANAGE_WEBHOOKS.Id, model.TEAM_USER_ROLE_ID)
-
- hook1 := &model.OutgoingWebhook{ChannelId: channel1.Id, CallbackURLs: []string{"http://nowhere.com"}}
- hook1 = Client.Must(Client.CreateOutgoingWebhook(hook1)).Data.(*model.OutgoingWebhook)
-
- hook2 := &model.OutgoingWebhook{TriggerWords: []string{"trigger"}, CallbackURLs: []string{"http://nowhere.com"}}
- hook2 = Client.Must(Client.CreateOutgoingWebhook(hook2)).Data.(*model.OutgoingWebhook)
-
- if result, err := Client.ListOutgoingWebhooks(); err != nil {
- t.Fatal(err)
- } else {
- hooks := result.Data.([]*model.OutgoingWebhook)
-
- if len(hooks) != 2 {
- t.Fatal("incorrect number of hooks")
- }
- }
-
- Client.Logout()
- Client.Must(Client.LoginById(user2.Id, user2.Password))
- Client.SetTeamId(team.Id)
-
- if _, err := Client.ListOutgoingWebhooks(); err == nil {
- t.Fatal("should have failed - not system/team admin")
- }
-
- // Grant permission to regular users.
- th.AddPermissionToRole(model.PERMISSION_MANAGE_WEBHOOKS.Id, model.TEAM_USER_ROLE_ID)
-
- if _, err := Client.ListOutgoingWebhooks(); err != nil {
- t.Fatal(err)
- }
-
- th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableOutgoingWebhooks = false })
-
- if _, err := Client.ListOutgoingWebhooks(); err == nil {
- t.Fatal("should have errored - webhooks turned off")
- }
-}
-
-func TestUpdateOutgoingHook(t *testing.T) {
- th := Setup().InitSystemAdmin()
- defer th.TearDown()
-
- Client := th.SystemAdminClient
- user := th.SystemAdminUser
- team := th.SystemAdminTeam
- team2 := th.CreateTeam(Client)
- channel1 := th.CreateChannel(Client, team)
- channel2 := th.CreatePrivateChannel(Client, team)
- channel3 := th.CreateChannel(Client, team)
- user2 := th.CreateUser(Client)
- th.LinkUserToTeam(user2, team)
- user3 := th.CreateUser(Client)
- th.LinkUserToTeam(user3, team2)
-
- th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableOutgoingWebhooks = true })
-
- defaultRolePermissions := th.SaveDefaultRolePermissions()
- defer func() {
- th.RestoreDefaultRolePermissions(defaultRolePermissions)
- }()
- th.AddPermissionToRole(model.PERMISSION_MANAGE_WEBHOOKS.Id, model.TEAM_ADMIN_ROLE_ID)
-
- // Revoke permission from regular users.
- th.RemovePermissionFromRole(model.PERMISSION_MANAGE_WEBHOOKS.Id, model.TEAM_USER_ROLE_ID)
-
- hook := createOutgoingWebhook(channel1.Id, []string{"http://nowhere.com"}, []string{"cats"}, Client, t)
- createOutgoingWebhook(channel1.Id, []string{"http://nowhere.com"}, []string{"dogs"}, Client, t)
-
- hook.DisplayName = "Cats"
- hook.Description = "Get me some cats"
- t.Run("OutgoingHooksDisabled", func(t *testing.T) {
- th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableOutgoingWebhooks = false })
- if _, err := Client.UpdateOutgoingWebhook(hook); err == nil {
- t.Fatal("should have failed - outgoing webhooks disabled")
- }
- })
-
- th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableOutgoingWebhooks = true })
- t.Run("UpdateOutgoingWebhook", func(t *testing.T) {
- if result, err := Client.UpdateOutgoingWebhook(hook); err != nil {
- t.Fatal("failed to update outgoing web hook")
- } else {
- updatedHook := result.Data.(*model.OutgoingWebhook)
-
- if updatedHook.DisplayName != hook.DisplayName {
- t.Fatal("Hook display name did not get updated")
- }
-
- if updatedHook.Description != hook.Description {
- t.Fatal("Hook description did not get updated")
- }
- }
- })
-
- t.Run("RetainCreateAt", func(t *testing.T) {
- hook2 := &model.OutgoingWebhook{ChannelId: channel1.Id, CallbackURLs: []string{"http://nowhere.com"}, TriggerWords: []string{"rats"}}
-
- if result, err := Client.CreateOutgoingWebhook(hook2); err != nil {
- t.Fatal("hook creation failed")
- } else {
- createdHook := result.Data.(*model.OutgoingWebhook)
- createdHook.DisplayName = "Name2"
-
- if result, err := Client.UpdateOutgoingWebhook(createdHook); err != nil {
- t.Fatal("Update hook should not fail")
- } else {
- updatedHook := result.Data.(*model.OutgoingWebhook)
-
- if updatedHook.CreateAt != createdHook.CreateAt {
- t.Fatal("failed - hook create at should not be changed")
- }
- }
- }
- })
-
- t.Run("ModifyUpdateAt", func(t *testing.T) {
- hook.DisplayName = "Name3"
-
- if result, err := Client.UpdateOutgoingWebhook(hook); err != nil {
- t.Fatal("Update hook should not fail")
- } else {
- updatedHook := result.Data.(*model.OutgoingWebhook)
-
- if updatedHook.UpdateAt == hook.UpdateAt {
- t.Fatal("failed - hook updateAt is not updated")
- }
- }
- })
-
- Client.Logout()
- Client.Must(Client.LoginById(user2.Id, user2.Password))
- Client.SetTeamId(team.Id)
- if _, err := Client.UpdateOutgoingWebhook(hook); err == nil {
- t.Fatal("should have failed - user does not have permissions to manage webhooks")
- }
-
- // Grant permission to regular users.
- th.AddPermissionToRole(model.PERMISSION_MANAGE_WEBHOOKS.Id, model.TEAM_USER_ROLE_ID)
-
- hook2 := createOutgoingWebhook(channel1.Id, []string{"http://nowhereelse.com"}, []string{"dogs"}, Client, t)
-
- if _, err := Client.UpdateOutgoingWebhook(hook2); err != nil {
- t.Fatal("update webhook failed when admin only integrations is turned off")
- }
-
- // Revoke permission from regular users.
- th.RemovePermissionFromRole(model.PERMISSION_MANAGE_WEBHOOKS.Id, model.TEAM_USER_ROLE_ID)
-
- Client.Logout()
- th.LinkUserToTeam(user3, team)
- th.UpdateUserToTeamAdmin(user3, team)
- Client.Must(Client.LoginById(user3.Id, user3.Password))
- Client.SetTeamId(team.Id)
- t.Run("RetainHookCreator", func(t *testing.T) {
- if result, err := Client.UpdateOutgoingWebhook(hook); err != nil {
- t.Fatal("failed to update outgoing web hook")
- } else {
- updatedHook := result.Data.(*model.OutgoingWebhook)
-
- if updatedHook.CreatorId != user.Id {
- t.Fatal("hook creator should not be changed")
- }
- }
- })
-
- Client.Logout()
- Client.Must(Client.LoginById(user.Id, user.Password))
- Client.SetTeamId(team.Id)
- t.Run("UpdateToExistingTriggerWordAndCallback", func(t *testing.T) {
- t.Run("OnSameChannel", func(t *testing.T) {
- hook.TriggerWords = []string{"dogs"}
-
- if _, err := Client.UpdateOutgoingWebhook(hook); err == nil {
- t.Fatal("should have failed - duplicate trigger words & channel urls")
- }
- })
-
- t.Run("OnDifferentChannel", func(t *testing.T) {
- hook.TriggerWords = []string{"dogs"}
- hook.ChannelId = channel3.Id
-
- if _, err := Client.UpdateOutgoingWebhook(hook); err != nil {
- t.Fatal("update of hook failed with duplicate trigger word but different channel")
- }
- })
- })
-
- t.Run("UpdateToNonExistentChannel", func(t *testing.T) {
- hook.ChannelId = "junk"
-
- if _, err := Client.UpdateOutgoingWebhook(hook); err == nil {
- t.Fatal("should have failed - non existent channel")
- }
- })
-
- t.Run("UpdateToPrivateChannel", func(t *testing.T) {
- hook.ChannelId = channel2.Id
-
- if _, err := Client.UpdateOutgoingWebhook(hook); err == nil {
- t.Fatal("should have failed - update to a private channel")
- }
- })
-
- t.Run("UpdateToBlankTriggerWordAndChannel", func(t *testing.T) {
- hook.ChannelId = ""
- hook.TriggerWords = nil
-
- if _, err := Client.UpdateOutgoingWebhook(hook); err == nil {
- t.Fatal("should have failed - update to blank trigger words & channel")
- }
- })
-
- Client.Logout()
- Client.Must(Client.LoginById(user3.Id, user3.Password))
- Client.SetTeamId(team2.Id)
- t.Run("UpdateToADifferentTeam", func(t *testing.T) {
- if _, err := Client.UpdateOutgoingWebhook(hook); err == nil {
- t.Fatal("should have failed - update to a different team is not allowed")
- }
- })
-}
-
-func TestDeleteOutgoingHook(t *testing.T) {
- th := Setup().InitSystemAdmin()
- defer th.TearDown()
-
- Client := th.SystemAdminClient
- team := th.SystemAdminTeam
- channel1 := th.CreateChannel(Client, team)
- user2 := th.CreateUser(Client)
- th.LinkUserToTeam(user2, team)
-
- th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableOutgoingWebhooks = true })
-
- defaultRolePermissions := th.SaveDefaultRolePermissions()
- defer func() {
- th.RestoreDefaultRolePermissions(defaultRolePermissions)
- }()
- th.AddPermissionToRole(model.PERMISSION_MANAGE_WEBHOOKS.Id, model.TEAM_ADMIN_ROLE_ID)
-
- // Revoke permission from regular users.
- th.RemovePermissionFromRole(model.PERMISSION_MANAGE_WEBHOOKS.Id, model.TEAM_USER_ROLE_ID)
-
- hook := &model.OutgoingWebhook{ChannelId: channel1.Id, CallbackURLs: []string{"http://nowhere.com"}}
- hook = Client.Must(Client.CreateOutgoingWebhook(hook)).Data.(*model.OutgoingWebhook)
-
- if _, err := Client.DeleteOutgoingWebhook("junk"); err == nil {
- t.Fatal("should have failed - bad hook id")
- }
-
- if _, err := Client.DeleteOutgoingWebhook(""); err == nil {
- t.Fatal("should have failed - empty hook id")
- }
-
- if _, err := Client.DeleteOutgoingWebhook(hook.Id); err != nil {
- t.Fatal(err)
- }
-
- hooks := Client.Must(Client.ListOutgoingWebhooks()).Data.([]*model.OutgoingWebhook)
- if len(hooks) != 0 {
- t.Fatal("delete didn't work properly")
- }
-
- hook = &model.OutgoingWebhook{ChannelId: channel1.Id, CallbackURLs: []string{"http://nowhere.com"}}
- hook = Client.Must(Client.CreateOutgoingWebhook(hook)).Data.(*model.OutgoingWebhook)
-
- Client.Logout()
- Client.Must(Client.LoginById(user2.Id, user2.Password))
- Client.SetTeamId(team.Id)
-
- if _, err := Client.DeleteOutgoingWebhook(hook.Id); err == nil {
- t.Fatal("should have failed - not system/team admin")
- }
-
- // Grant permission to regular users.
- th.AddPermissionToRole(model.PERMISSION_MANAGE_WEBHOOKS.Id, model.TEAM_USER_ROLE_ID)
-
- if _, err := Client.DeleteOutgoingWebhook(hook.Id); err == nil {
- t.Fatal("should have failed - not creator or team admin")
- }
-
- hook = &model.OutgoingWebhook{ChannelId: channel1.Id, CallbackURLs: []string{"http://nowhere.com"}}
- hook = Client.Must(Client.CreateOutgoingWebhook(hook)).Data.(*model.OutgoingWebhook)
-
- if _, err := Client.DeleteOutgoingWebhook(hook.Id); err != nil {
- t.Fatal(err)
- }
-
- th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableOutgoingWebhooks = false })
-
- if _, err := Client.DeleteOutgoingWebhook(hook.Id); err == nil {
- t.Fatal("should have errored - webhooks turned off")
- }
-}
-
-func TestRegenOutgoingHookToken(t *testing.T) {
- th := Setup().InitSystemAdmin()
- defer th.TearDown()
-
- Client := th.SystemAdminClient
- team := th.SystemAdminTeam
- team2 := th.CreateTeam(Client)
- channel1 := th.CreateChannel(Client, team)
- user2 := th.CreateUser(Client)
- th.LinkUserToTeam(user2, team)
- user3 := th.CreateUser(Client)
- th.LinkUserToTeam(user3, team2)
-
- th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableOutgoingWebhooks = true })
-
- defaultRolePermissions := th.SaveDefaultRolePermissions()
- defer func() {
- th.RestoreDefaultRolePermissions(defaultRolePermissions)
- }()
- th.AddPermissionToRole(model.PERMISSION_MANAGE_WEBHOOKS.Id, model.TEAM_ADMIN_ROLE_ID)
-
- // Revoke permission from regular users.
- th.RemovePermissionFromRole(model.PERMISSION_MANAGE_WEBHOOKS.Id, model.TEAM_USER_ROLE_ID)
-
- hook := &model.OutgoingWebhook{ChannelId: channel1.Id, CallbackURLs: []string{"http://nowhere.com"}}
- hook = Client.Must(Client.CreateOutgoingWebhook(hook)).Data.(*model.OutgoingWebhook)
-
- if _, err := Client.RegenOutgoingWebhookToken("junk"); err == nil {
- t.Fatal("should have failed - bad id")
- }
-
- if _, err := Client.RegenOutgoingWebhookToken(""); err == nil {
- t.Fatal("should have failed - empty id")
- }
-
- if result, err := Client.RegenOutgoingWebhookToken(hook.Id); err != nil {
- t.Fatal(err)
- } else {
- if result.Data.(*model.OutgoingWebhook).Token == hook.Token {
- t.Fatal("regen didn't work properly")
- }
- }
-
- Client.SetTeamId(model.NewId())
- if _, err := Client.RegenOutgoingWebhookToken(hook.Id); err == nil {
- t.Fatal("should have failed - wrong team id")
- }
-
- Client.Logout()
- Client.Must(Client.LoginById(user2.Id, user2.Password))
- Client.SetTeamId(team.Id)
-
- if _, err := Client.RegenOutgoingWebhookToken(hook.Id); err == nil {
- t.Fatal("should have failed - not system/team admin")
- }
-
- // Grant permission to regular users.
- th.AddPermissionToRole(model.PERMISSION_MANAGE_WEBHOOKS.Id, model.TEAM_USER_ROLE_ID)
-
- hook = &model.OutgoingWebhook{ChannelId: channel1.Id, CallbackURLs: []string{"http://nowhere.com"}}
- hook = Client.Must(Client.CreateOutgoingWebhook(hook)).Data.(*model.OutgoingWebhook)
-
- if _, err := Client.RegenOutgoingWebhookToken(hook.Id); err != nil {
- t.Fatal(err)
- }
-
- Client.Logout()
- Client.Must(Client.LoginById(user3.Id, user3.Password))
- Client.SetTeamId(team2.Id)
-
- if _, err := Client.RegenOutgoingWebhookToken(hook.Id); err == nil {
- t.Fatal("should have failed - wrong team")
- }
-
- th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableOutgoingWebhooks = false })
-
- if _, err := Client.RegenOutgoingWebhookToken(hook.Id); err == nil {
- t.Fatal("should have errored - webhooks turned off")
- }
-}
diff --git a/api/webrtc.go b/api/webrtc.go
deleted file mode 100644
index cd37c0ad8..000000000
--- a/api/webrtc.go
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-package api
-
-import (
- "net/http"
-)
-
-func (api *API) InitWebrtc() {
- api.BaseRoutes.Webrtc.Handle("/token", api.ApiUserRequired(webrtcToken)).Methods("POST")
-}
-
-func webrtcToken(c *Context, w http.ResponseWriter, r *http.Request) {
- result, err := c.App.GetWebrtcInfoForSession(c.Session.Id)
-
- if err != nil {
- c.Err = err
- return
- }
-
- w.Write([]byte(result.ToJson()))
-}
diff --git a/api/websocket.go b/api/websocket.go
deleted file mode 100644
index 7f2c9c0db..000000000
--- a/api/websocket.go
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-package api
-
-import (
- "fmt"
- "net/http"
-
- "github.com/gorilla/websocket"
- "github.com/mattermost/mattermost-server/mlog"
- "github.com/mattermost/mattermost-server/model"
-)
-
-func (api *API) InitWebSocket() {
- api.BaseRoutes.Users.Handle("/websocket", api.ApiAppHandlerTrustRequester(connect)).Methods("GET")
-}
-
-func connect(c *Context, w http.ResponseWriter, r *http.Request) {
- upgrader := websocket.Upgrader{
- ReadBufferSize: model.SOCKET_MAX_MESSAGE_SIZE_KB,
- WriteBufferSize: model.SOCKET_MAX_MESSAGE_SIZE_KB,
- CheckOrigin: c.App.OriginChecker(),
- }
-
- ws, err := upgrader.Upgrade(w, r, nil)
- if err != nil {
- mlog.Error(fmt.Sprintf("websocket connect err: %v", err))
- c.Err = model.NewAppError("connect", "api.web_socket.connect.upgrade.app_error", nil, "", http.StatusInternalServerError)
- return
- }
-
- wc := c.App.NewWebConn(ws, c.Session, c.T, c.Locale)
-
- if len(c.Session.UserId) > 0 {
- c.App.HubRegister(wc)
- }
-
- wc.Pump()
-}
diff --git a/api/websocket_test.go b/api/websocket_test.go
deleted file mode 100644
index a3c716abd..000000000
--- a/api/websocket_test.go
+++ /dev/null
@@ -1,381 +0,0 @@
-// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-package api
-
-import (
- "fmt"
- //"encoding/json"
- //"net/http"
- "net/http"
- "testing"
- "time"
-
- "github.com/gorilla/websocket"
- "github.com/mattermost/mattermost-server/model"
-)
-
-/*func TestWebSocketAuthentication(t *testing.T) {
- th := Setup().InitBasic()
- WebSocketClient, err := th.CreateWebSocketClient()
- if err != nil {
- t.Fatal(err)
- }
- WebSocketClient.Listen()
-
- time.Sleep(300 * time.Millisecond)
- if resp := <-WebSocketClient.ResponseChannel; resp.Status != model.STATUS_OK {
- t.Fatal("should have responded OK to authentication challenge")
- }
-
- WebSocketClient.SendMessage("ping", nil)
- time.Sleep(300 * time.Millisecond)
- if resp := <-WebSocketClient.ResponseChannel; resp.Data["text"].(string) != "pong" {
- t.Fatal("wrong response")
- }
-
- WebSocketClient.Close()
-
- authToken := WebSocketClient.AuthToken
- WebSocketClient.AuthToken = "junk"
- if err := WebSocketClient.Connect(); err != nil {
- t.Fatal(err)
- }
- WebSocketClient.Listen()
-
- if resp := <-WebSocketClient.ResponseChannel; resp != nil {
- t.Fatal("should have closed")
- }
-
- if conn, _, err := websocket.DefaultDialer.Dial(WebSocketClient.ApiUrl+"/users/websocket", nil); err != nil {
- t.Fatal("should have connected")
- } else {
- req := &model.WebSocketRequest{}
- req.Seq = 1
- req.Action = "ping"
- conn.WriteJSON(req)
-
- closedAutomatically := false
- hitNotAuthedError := false
-
- go func() {
- time.Sleep(10 * time.Second)
- conn.Close()
-
- if !closedAutomatically {
- t.Fatal("should have closed automatically in 5 seconds")
- }
- }()
-
- for {
- if _, rawMsg, err := conn.ReadMessage(); err != nil {
- closedAutomatically = true
- conn.Close()
- break
- } else {
- var response model.WebSocketResponse
- if err := json.Unmarshal(rawMsg, &response); err != nil && !response.IsValid() {
- t.Fatal("should not have failed")
- } else {
- if response.Error == nil || response.Error.Id != "api.web_socket_router.not_authenticated.app_error" {
- t.Log(response.Error.Id)
- t.Fatal("wrong error")
- continue
- }
-
- hitNotAuthedError = true
- }
- }
- }
-
- if !hitNotAuthedError {
- t.Fatal("should have received a not authenticated response")
- }
- }
-
- header := http.Header{}
- header.Set(model.HEADER_AUTH, "BEARER "+authToken)
- if conn, _, err := websocket.DefaultDialer.Dial(WebSocketClient.ApiUrl+"/users/websocket", header); err != nil {
- t.Fatal("should have connected")
- } else {
- if _, rawMsg, err := conn.ReadMessage(); err != nil {
- t.Fatal("should not have closed automatically")
- } else {
- var event model.WebSocketEvent
- if err := json.Unmarshal(rawMsg, &event); err != nil && !event.IsValid() {
- t.Fatal("should not have failed")
- } else if event.Event != model.WEBSOCKET_EVENT_HELLO {
- t.Log(event.ToJson())
- t.Fatal("should have helloed")
- }
- }
-
- conn.Close()
- }
-}*/
-
-func TestWebSocket(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- WebSocketClient, err := th.CreateWebSocketClient()
- if err != nil {
- t.Fatal(err)
- }
- defer WebSocketClient.Close()
-
- time.Sleep(300 * time.Millisecond)
-
- // Test closing and reconnecting
- WebSocketClient.Close()
- if err := WebSocketClient.Connect(); err != nil {
- t.Fatal(err)
- }
-
- WebSocketClient.Listen()
-
- time.Sleep(300 * time.Millisecond)
- if resp := <-WebSocketClient.ResponseChannel; resp.Status != model.STATUS_OK {
- t.Fatal("should have responded OK to authentication challenge")
- }
-
- WebSocketClient.SendMessage("ping", nil)
- time.Sleep(300 * time.Millisecond)
- if resp := <-WebSocketClient.ResponseChannel; resp.Data["text"].(string) != "pong" {
- t.Fatal("wrong response")
- }
-
- WebSocketClient.SendMessage("", nil)
- time.Sleep(300 * time.Millisecond)
- if resp := <-WebSocketClient.ResponseChannel; resp.Error.Id != "api.web_socket_router.no_action.app_error" {
- t.Fatal("should have been no action response")
- }
-
- WebSocketClient.SendMessage("junk", nil)
- time.Sleep(300 * time.Millisecond)
- if resp := <-WebSocketClient.ResponseChannel; resp.Error.Id != "api.web_socket_router.bad_action.app_error" {
- t.Fatal("should have been bad action response")
- }
-
- req := &model.WebSocketRequest{}
- req.Seq = 0
- req.Action = "ping"
- WebSocketClient.Conn.WriteJSON(req)
- time.Sleep(300 * time.Millisecond)
- if resp := <-WebSocketClient.ResponseChannel; resp.Error.Id != "api.web_socket_router.bad_seq.app_error" {
- t.Fatal("should have been bad action response")
- }
-
- WebSocketClient.UserTyping("", "")
- time.Sleep(300 * time.Millisecond)
- if resp := <-WebSocketClient.ResponseChannel; resp.Error.Id != "api.websocket_handler.invalid_param.app_error" {
- t.Fatal("should have been invalid param response")
- } else {
- if resp.Error.DetailedError != "" {
- t.Fatal("detailed error not cleared")
- }
- }
-}
-
-func TestWebSocketEvent(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- WebSocketClient, err := th.CreateWebSocketClient()
- if err != nil {
- t.Fatal(err)
- }
- defer WebSocketClient.Close()
-
- WebSocketClient.Listen()
-
- time.Sleep(300 * time.Millisecond)
- if resp := <-WebSocketClient.ResponseChannel; resp.Status != model.STATUS_OK {
- t.Fatal("should have responded OK to authentication challenge")
- }
-
- omitUser := make(map[string]bool, 1)
- omitUser["somerandomid"] = true
- evt1 := model.NewWebSocketEvent(model.WEBSOCKET_EVENT_TYPING, "", th.BasicChannel.Id, "", omitUser)
- evt1.Add("user_id", "somerandomid")
- th.App.Publish(evt1)
-
- time.Sleep(300 * time.Millisecond)
-
- stop := make(chan bool)
- eventHit := false
-
- go func() {
- for {
- select {
- case resp := <-WebSocketClient.EventChannel:
- if resp.Event == model.WEBSOCKET_EVENT_TYPING && resp.Data["user_id"].(string) == "somerandomid" {
- eventHit = true
- }
- case <-stop:
- return
- }
- }
- }()
-
- time.Sleep(400 * time.Millisecond)
-
- stop <- true
-
- if !eventHit {
- t.Fatal("did not receive typing event")
- }
-
- evt2 := model.NewWebSocketEvent(model.WEBSOCKET_EVENT_TYPING, "", "somerandomid", "", nil)
- th.App.Publish(evt2)
- time.Sleep(300 * time.Millisecond)
-
- eventHit = false
-
- go func() {
- for {
- select {
- case resp := <-WebSocketClient.EventChannel:
- if resp.Event == model.WEBSOCKET_EVENT_TYPING {
- eventHit = true
- }
- case <-stop:
- return
- }
- }
- }()
-
- time.Sleep(400 * time.Millisecond)
-
- stop <- true
-
- if eventHit {
- t.Fatal("got typing event for bad channel id")
- }
-}
-
-func TestCreateDirectChannelWithSocket(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- Client := th.BasicClient
- user2 := th.BasicUser2
-
- users := make([]*model.User, 0)
- users = append(users, user2)
-
- for i := 0; i < 10; i++ {
- users = append(users, th.CreateUser(Client))
- }
-
- WebSocketClient, err := th.CreateWebSocketClient()
- if err != nil {
- t.Fatal(err)
- }
- defer WebSocketClient.Close()
- WebSocketClient.Listen()
-
- time.Sleep(300 * time.Millisecond)
- if resp := <-WebSocketClient.ResponseChannel; resp.Status != model.STATUS_OK {
- t.Fatal("should have responded OK to authentication challenge")
- }
-
- wsr := <-WebSocketClient.EventChannel
- if wsr.Event != model.WEBSOCKET_EVENT_HELLO {
- t.Fatal("missing hello")
- }
-
- stop := make(chan bool)
- count := 0
-
- go func() {
- for {
- select {
- case wsr := <-WebSocketClient.EventChannel:
- if wsr.Event == model.WEBSOCKET_EVENT_DIRECT_ADDED {
- count = count + 1
- }
-
- case <-stop:
- return
- }
- }
- }()
-
- for _, user := range users {
- time.Sleep(100 * time.Millisecond)
- if _, err := Client.CreateDirectChannel(user.Id); err != nil {
- t.Fatal("failed to create DM channel")
- }
- }
-
- time.Sleep(5000 * time.Millisecond)
-
- stop <- true
-
- if count != len(users) {
- t.Fatal("We didn't get the proper amount of direct_added messages")
- }
-
-}
-
-func TestWebsocketOriginSecurity(t *testing.T) {
- th := Setup().InitBasic()
- defer th.TearDown()
-
- url := fmt.Sprintf("ws://localhost:%v", th.App.Srv.ListenAddr.Port)
-
- // Should fail because origin doesn't match
- _, _, err := websocket.DefaultDialer.Dial(url+model.API_URL_SUFFIX_V3+"/users/websocket", http.Header{
- "Origin": []string{"http://www.evil.com"},
- })
- if err == nil {
- t.Fatal("Should have errored because Origin does not match host! SECURITY ISSUE!")
- }
-
- // We are not a browser so we can spoof this just fine
- _, _, err = websocket.DefaultDialer.Dial(url+model.API_URL_SUFFIX_V3+"/users/websocket", http.Header{
- "Origin": []string{fmt.Sprintf("http://localhost:%v", th.App.Srv.ListenAddr.Port)},
- })
- if err != nil {
- t.Fatal(err)
- }
-
- // Should succeed now because open CORS
- th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.AllowCorsFrom = "*" })
- _, _, err = websocket.DefaultDialer.Dial(url+model.API_URL_SUFFIX_V3+"/users/websocket", http.Header{
- "Origin": []string{"http://www.evil.com"},
- })
- if err != nil {
- t.Fatal(err)
- }
-
- // Should succeed now because matching CORS
- th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.AllowCorsFrom = "http://www.evil.com" })
- _, _, err = websocket.DefaultDialer.Dial(url+model.API_URL_SUFFIX_V3+"/users/websocket", http.Header{
- "Origin": []string{"http://www.evil.com"},
- })
- if err != nil {
- t.Fatal(err)
- }
-
- // Should fail because non-matching CORS
- th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.AllowCorsFrom = "http://www.good.com" })
- _, _, err = websocket.DefaultDialer.Dial(url+model.API_URL_SUFFIX_V3+"/users/websocket", http.Header{
- "Origin": []string{"http://www.evil.com"},
- })
- if err == nil {
- t.Fatal("Should have errored because Origin contain AllowCorsFrom")
- }
-
- // Should fail because non-matching CORS
- th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.AllowCorsFrom = "http://www.good.com" })
- _, _, err = websocket.DefaultDialer.Dial(url+model.API_URL_SUFFIX_V3+"/users/websocket", http.Header{
- "Origin": []string{"http://www.good.co"},
- })
- if err == nil {
- t.Fatal("Should have errored because Origin does not match host! SECURITY ISSUE!")
- }
-
- th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.AllowCorsFrom = "" })
-}
diff --git a/api4/api.go b/api4/api.go
index 9172391dd..918154c0d 100644
--- a/api4/api.go
+++ b/api4/api.go
@@ -113,7 +113,7 @@ type API struct {
BaseRoutes *Routes
}
-func Init(a *app.App, root *mux.Router, full bool) *API {
+func Init(a *app.App, root *mux.Router) *API {
api := &API{
App: a,
BaseRoutes: &Routes{},
@@ -231,10 +231,7 @@ func Init(a *app.App, root *mux.Router, full bool) *API {
root.Handle("/api/v4/{anything:.*}", http.HandlerFunc(api.Handle404))
- // REMOVE CONDITION WHEN APIv3 REMOVED
- if full {
- a.InitEmailBatching()
- }
+ a.InitEmailBatching()
return api
}
diff --git a/api4/apitestlib.go b/api4/apitestlib.go
index 0ce334154..86150e05a 100644
--- a/api4/apitestlib.go
+++ b/api4/apitestlib.go
@@ -120,7 +120,7 @@ func setupTestHelper(enterprise bool) *TestHelper {
}
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.ListenAddress = prevListenAddress })
- Init(th.App, th.App.Srv.Router, true)
+ Init(th.App, th.App.Srv.Router)
web.NewWeb(th.App, th.App.Srv.Router)
wsapi.Init(th.App, th.App.Srv.WebSocketRouter)
th.App.Srv.Store.MarkSystemRanUnitTests()
diff --git a/api4/commands_test.go b/api4/commands_test.go
new file mode 100644
index 000000000..cb960c608
--- /dev/null
+++ b/api4/commands_test.go
@@ -0,0 +1,449 @@
+// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
+// See License.txt for license information.
+
+package api4
+
+import (
+ "strings"
+ "testing"
+ "time"
+
+ "github.com/mattermost/mattermost-server/model"
+)
+
+func TestEchoCommand(t *testing.T) {
+ th := Setup().InitBasic()
+ defer th.TearDown()
+
+ Client := th.Client
+ channel1 := th.BasicChannel
+
+ echoTestString := "/echo test"
+
+ if r1 := Client.Must(Client.ExecuteCommand(channel1.Id, echoTestString)).(*model.CommandResponse); r1 == nil {
+ t.Fatal("Echo command failed to execute")
+ }
+
+ if r1 := Client.Must(Client.ExecuteCommand(channel1.Id, "/echo ")).(*model.CommandResponse); r1 == nil {
+ t.Fatal("Echo command failed to execute")
+ }
+
+ time.Sleep(100 * time.Millisecond)
+
+ p1 := Client.Must(Client.GetPostsForChannel(channel1.Id, 0, 2, "")).(*model.PostList)
+ if len(p1.Order) != 2 {
+ t.Fatal("Echo command failed to send")
+ }
+}
+
+func TestGroupmsgCommands(t *testing.T) {
+ th := Setup().InitBasic()
+ defer th.TearDown()
+
+ Client := th.Client
+ team := th.BasicTeam
+ user1 := th.BasicUser
+ user2 := th.BasicUser2
+ user3 := th.CreateUser()
+ user4 := th.CreateUser()
+ user5 := th.CreateUser()
+ user6 := th.CreateUser()
+ user7 := th.CreateUser()
+ user8 := th.CreateUser()
+ user9 := th.CreateUser()
+ th.LinkUserToTeam(user3, team)
+ th.LinkUserToTeam(user4, team)
+
+ rs1 := Client.Must(Client.ExecuteCommand(th.BasicChannel.Id, "/groupmsg "+user2.Username+","+user3.Username)).(*model.CommandResponse)
+
+ group1 := model.GetGroupNameFromUserIds([]string{user1.Id, user2.Id, user3.Id})
+
+ if !strings.HasSuffix(rs1.GotoLocation, "/"+team.Name+"/channels/"+group1) {
+ t.Fatal("failed to create group channel")
+ }
+
+ rs2 := Client.Must(Client.ExecuteCommand(th.BasicChannel.Id, "/groupmsg "+user3.Username+","+user4.Username+" foobar")).(*model.CommandResponse)
+ group2 := model.GetGroupNameFromUserIds([]string{user1.Id, user3.Id, user4.Id})
+
+ if !strings.HasSuffix(rs2.GotoLocation, "/"+team.Name+"/channels/"+group2) {
+ t.Fatal("failed to create second direct channel")
+ }
+ if result := Client.Must(Client.SearchPosts(team.Id, "foobar", false)).(*model.PostList); len(result.Order) == 0 {
+ t.Fatal("post did not get sent to direct message")
+ }
+
+ rs3 := Client.Must(Client.ExecuteCommand(th.BasicChannel.Id, "/groupmsg "+user2.Username+","+user3.Username)).(*model.CommandResponse)
+ if !strings.HasSuffix(rs3.GotoLocation, "/"+team.Name+"/channels/"+group1) {
+ t.Fatal("failed to go back to existing group channel")
+ }
+
+ Client.Must(Client.ExecuteCommand(th.BasicChannel.Id, "/groupmsg "+user2.Username+" foobar"))
+ Client.Must(Client.ExecuteCommand(th.BasicChannel.Id, "/groupmsg "+user2.Username+","+user3.Username+","+user4.Username+","+user5.Username+","+user6.Username+","+user7.Username+","+user8.Username+","+user9.Username+" foobar"))
+ Client.Must(Client.ExecuteCommand(th.BasicChannel.Id, "/groupmsg junk foobar"))
+ Client.Must(Client.ExecuteCommand(th.BasicChannel.Id, "/groupmsg junk,junk2 foobar"))
+}
+
+func TestInvitePeopleCommand(t *testing.T) {
+ th := Setup().InitBasic()
+ defer th.TearDown()
+
+ Client := th.Client
+ channel := th.BasicChannel
+
+ r1 := Client.Must(Client.ExecuteCommand(channel.Id, "/invite_people test@example.com")).(*model.CommandResponse)
+ if r1 == nil {
+ t.Fatal("Command failed to execute")
+ }
+
+ r2 := Client.Must(Client.ExecuteCommand(channel.Id, "/invite_people test1@example.com test2@example.com")).(*model.CommandResponse)
+ if r2 == nil {
+ t.Fatal("Command failed to execute")
+ }
+
+ r3 := Client.Must(Client.ExecuteCommand(channel.Id, "/invite_people")).(*model.CommandResponse)
+ if r3 == nil {
+ t.Fatal("Command failed to execute")
+ }
+}
+
+// also used to test /open (see command_open_test.go)
+func testJoinCommands(t *testing.T, alias string) {
+ th := Setup().InitBasic()
+ defer th.TearDown()
+
+ Client := th.Client
+ team := th.BasicTeam
+ user2 := th.BasicUser2
+
+ channel0 := &model.Channel{DisplayName: "00", Name: "00" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
+ channel0 = Client.Must(Client.CreateChannel(channel0)).(*model.Channel)
+
+ channel1 := &model.Channel{DisplayName: "AA", Name: "aa" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
+ channel1 = Client.Must(Client.CreateChannel(channel1)).(*model.Channel)
+ Client.Must(Client.RemoveUserFromChannel(channel1.Id, th.BasicUser.Id))
+
+ channel2 := &model.Channel{DisplayName: "BB", Name: "bb" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
+ channel2 = Client.Must(Client.CreateChannel(channel2)).(*model.Channel)
+ Client.Must(Client.RemoveUserFromChannel(channel2.Id, th.BasicUser.Id))
+
+ channel3 := Client.Must(Client.CreateDirectChannel(th.BasicUser.Id, user2.Id)).(*model.Channel)
+
+ rs5 := Client.Must(Client.ExecuteCommand(channel0.Id, "/"+alias+" "+channel2.Name)).(*model.CommandResponse)
+ if !strings.HasSuffix(rs5.GotoLocation, "/"+team.Name+"/channels/"+channel2.Name) {
+ t.Fatal("failed to join channel")
+ }
+
+ rs6 := Client.Must(Client.ExecuteCommand(channel0.Id, "/"+alias+" "+channel3.Name)).(*model.CommandResponse)
+ if strings.HasSuffix(rs6.GotoLocation, "/"+team.Name+"/channels/"+channel3.Name) {
+ t.Fatal("should not have joined direct message channel")
+ }
+
+ c1 := Client.Must(Client.GetChannelsForTeamForUser(th.BasicTeam.Id, th.BasicUser.Id, "")).([]*model.Channel)
+
+ found := false
+ for _, c := range c1 {
+ if c.Id == channel2.Id {
+ found = true
+ }
+ }
+
+ if !found {
+ t.Fatal("did not join channel")
+ }
+}
+
+func TestJoinCommands(t *testing.T) {
+ testJoinCommands(t, "join")
+}
+
+func TestLoadTestHelpCommands(t *testing.T) {
+ th := Setup().InitBasic()
+ defer th.TearDown()
+
+ Client := th.Client
+ channel := th.BasicChannel
+
+ th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableTesting = true })
+
+ rs := Client.Must(Client.ExecuteCommand(channel.Id, "/test help")).(*model.CommandResponse)
+ if !strings.Contains(rs.Text, "Mattermost testing commands to help") {
+ t.Fatal(rs.Text)
+ }
+
+ time.Sleep(2 * time.Second)
+}
+
+func TestLoadTestSetupCommands(t *testing.T) {
+ th := Setup().InitBasic()
+ defer th.TearDown()
+
+ Client := th.Client
+ channel := th.BasicChannel
+
+ th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableTesting = true })
+
+ rs := Client.Must(Client.ExecuteCommand(channel.Id, "/test setup fuzz 1 1 1")).(*model.CommandResponse)
+ if rs.Text != "Created environment" {
+ t.Fatal(rs.Text)
+ }
+
+ time.Sleep(2 * time.Second)
+}
+
+func TestLoadTestUsersCommands(t *testing.T) {
+ th := Setup().InitBasic()
+ defer th.TearDown()
+
+ Client := th.Client
+ channel := th.BasicChannel
+
+ th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableTesting = true })
+
+ rs := Client.Must(Client.ExecuteCommand(channel.Id, "/test users fuzz 1 2")).(*model.CommandResponse)
+ if rs.Text != "Added users" {
+ t.Fatal(rs.Text)
+ }
+
+ time.Sleep(2 * time.Second)
+}
+
+func TestLoadTestChannelsCommands(t *testing.T) {
+ th := Setup().InitBasic()
+ defer th.TearDown()
+
+ Client := th.Client
+ channel := th.BasicChannel
+
+ th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableTesting = true })
+
+ rs := Client.Must(Client.ExecuteCommand(channel.Id, "/test channels fuzz 1 2")).(*model.CommandResponse)
+ if rs.Text != "Added channels" {
+ t.Fatal(rs.Text)
+ }
+
+ time.Sleep(2 * time.Second)
+}
+
+func TestLoadTestPostsCommands(t *testing.T) {
+ th := Setup().InitBasic()
+ defer th.TearDown()
+
+ Client := th.Client
+ channel := th.BasicChannel
+
+ th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableTesting = true })
+
+ rs := Client.Must(Client.ExecuteCommand(channel.Id, "/test posts fuzz 2 3 2")).(*model.CommandResponse)
+ if rs.Text != "Added posts" {
+ t.Fatal(rs.Text)
+ }
+
+ time.Sleep(2 * time.Second)
+}
+
+func TestLeaveCommands(t *testing.T) {
+ th := Setup().InitBasic()
+ defer th.TearDown()
+
+ Client := th.Client
+ team := th.BasicTeam
+ user2 := th.BasicUser2
+
+ channel1 := &model.Channel{DisplayName: "AA", Name: "aa" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
+ channel1 = Client.Must(Client.CreateChannel(channel1)).(*model.Channel)
+ Client.Must(Client.AddChannelMember(channel1.Id, th.BasicUser.Id))
+
+ channel2 := &model.Channel{DisplayName: "BB", Name: "bb" + model.NewId() + "a", Type: model.CHANNEL_PRIVATE, TeamId: team.Id}
+ channel2 = Client.Must(Client.CreateChannel(channel2)).(*model.Channel)
+ Client.Must(Client.AddChannelMember(channel2.Id, th.BasicUser.Id))
+ Client.Must(Client.AddChannelMember(channel2.Id, user2.Id))
+
+ channel3 := Client.Must(Client.CreateDirectChannel(th.BasicUser.Id, user2.Id)).(*model.Channel)
+
+ rs1 := Client.Must(Client.ExecuteCommand(channel1.Id, "/leave")).(*model.CommandResponse)
+ if !strings.HasSuffix(rs1.GotoLocation, "/"+team.Name+"/channels/"+model.DEFAULT_CHANNEL) {
+ t.Fatal("failed to leave open channel 1")
+ }
+
+ rs2 := Client.Must(Client.ExecuteCommand(channel2.Id, "/leave")).(*model.CommandResponse)
+ if !strings.HasSuffix(rs2.GotoLocation, "/"+team.Name+"/channels/"+model.DEFAULT_CHANNEL) {
+ t.Fatal("failed to leave private channel 1")
+ }
+
+ _, err := Client.ExecuteCommand(channel3.Id, "/leave")
+ if err == nil {
+ t.Fatal("should fail leaving direct channel")
+ }
+
+ cdata := Client.Must(Client.GetChannelsForTeamForUser(th.BasicTeam.Id, th.BasicUser.Id, "")).([]*model.Channel)
+
+ found := false
+ for _, c := range cdata {
+ if c.Id == channel1.Id || c.Id == channel2.Id {
+ found = true
+ }
+ }
+
+ if found {
+ t.Fatal("did not leave right channels")
+ }
+
+ for _, c := range cdata {
+ if c.Name == model.DEFAULT_CHANNEL {
+ if _, err := Client.RemoveUserFromChannel(c.Id, th.BasicUser.Id); err == nil {
+ t.Fatal("should have errored on leaving default channel")
+ }
+ break
+ }
+ }
+}
+
+func TestLogoutTestCommand(t *testing.T) {
+ th := Setup().InitBasic()
+ defer th.TearDown()
+
+ th.Client.Must(th.Client.ExecuteCommand(th.BasicChannel.Id, "/logout"))
+}
+
+func TestMeCommand(t *testing.T) {
+ th := Setup().InitBasic()
+ defer th.TearDown()
+
+ Client := th.Client
+ channel := th.BasicChannel
+
+ testString := "/me hello"
+
+ r1 := Client.Must(Client.ExecuteCommand(channel.Id, testString)).(*model.CommandResponse)
+ if r1 == nil {
+ t.Fatal("Command failed to execute")
+ }
+
+ time.Sleep(100 * time.Millisecond)
+
+ p1 := Client.Must(Client.GetPostsForChannel(channel.Id, 0, 2, "")).(*model.PostList)
+ if len(p1.Order) != 2 {
+ t.Fatal("Command failed to send")
+ } else {
+ if p1.Posts[p1.Order[0]].Message != `*hello*` {
+ t.Log(p1.Posts[p1.Order[0]].Message)
+ t.Fatal("invalid shrug response")
+ }
+ }
+}
+
+func TestMsgCommands(t *testing.T) {
+ th := Setup().InitBasic()
+ defer th.TearDown()
+
+ Client := th.Client
+ team := th.BasicTeam
+ user1 := th.BasicUser
+ user2 := th.BasicUser2
+ user3 := th.CreateUser()
+ th.LinkUserToTeam(user3, team)
+
+ Client.Must(Client.CreateDirectChannel(th.BasicUser.Id, user2.Id))
+ Client.Must(Client.CreateDirectChannel(th.BasicUser.Id, user3.Id))
+
+ rs1 := Client.Must(Client.ExecuteCommand(th.BasicChannel.Id, "/msg "+user2.Username)).(*model.CommandResponse)
+ if !strings.HasSuffix(rs1.GotoLocation, "/"+team.Name+"/channels/"+user1.Id+"__"+user2.Id) && !strings.HasSuffix(rs1.GotoLocation, "/"+team.Name+"/channels/"+user2.Id+"__"+user1.Id) {
+ t.Fatal("failed to create direct channel")
+ }
+
+ rs2 := Client.Must(Client.ExecuteCommand(th.BasicChannel.Id, "/msg "+user3.Username+" foobar")).(*model.CommandResponse)
+ if !strings.HasSuffix(rs2.GotoLocation, "/"+team.Name+"/channels/"+user1.Id+"__"+user3.Id) && !strings.HasSuffix(rs2.GotoLocation, "/"+team.Name+"/channels/"+user3.Id+"__"+user1.Id) {
+ t.Fatal("failed to create second direct channel")
+ }
+ if result := Client.Must(Client.SearchPosts(th.BasicTeam.Id, "foobar", false)).(*model.PostList); len(result.Order) == 0 {
+ t.Fatalf("post did not get sent to direct message")
+ }
+
+ rs3 := Client.Must(Client.ExecuteCommand(th.BasicChannel.Id, "/msg "+user2.Username)).(*model.CommandResponse)
+ if !strings.HasSuffix(rs3.GotoLocation, "/"+team.Name+"/channels/"+user1.Id+"__"+user2.Id) && !strings.HasSuffix(rs3.GotoLocation, "/"+team.Name+"/channels/"+user2.Id+"__"+user1.Id) {
+ t.Fatal("failed to go back to existing direct channel")
+ }
+
+ Client.Must(Client.ExecuteCommand(th.BasicChannel.Id, "/msg "+th.BasicUser.Username+" foobar"))
+ Client.Must(Client.ExecuteCommand(th.BasicChannel.Id, "/msg junk foobar"))
+}
+
+func TestOpenCommands(t *testing.T) {
+ testJoinCommands(t, "open")
+}
+
+func TestSearchCommand(t *testing.T) {
+ th := Setup().InitBasic()
+ defer th.TearDown()
+
+ th.Client.Must(th.Client.ExecuteCommand(th.BasicChannel.Id, "/search"))
+}
+
+func TestSettingsCommand(t *testing.T) {
+ th := Setup().InitBasic()
+ defer th.TearDown()
+
+ th.Client.Must(th.Client.ExecuteCommand(th.BasicChannel.Id, "/settings"))
+}
+
+func TestShortcutsCommand(t *testing.T) {
+ th := Setup().InitBasic()
+ defer th.TearDown()
+
+ th.Client.Must(th.Client.ExecuteCommand(th.BasicChannel.Id, "/shortcuts"))
+}
+
+func TestShrugCommand(t *testing.T) {
+ th := Setup().InitBasic()
+ defer th.TearDown()
+
+ Client := th.Client
+ channel := th.BasicChannel
+
+ testString := "/shrug"
+
+ r1 := Client.Must(Client.ExecuteCommand(channel.Id, testString)).(*model.CommandResponse)
+ if r1 == nil {
+ t.Fatal("Command failed to execute")
+ }
+
+ time.Sleep(100 * time.Millisecond)
+
+ p1 := Client.Must(Client.GetPostsForChannel(channel.Id, 0, 2, "")).(*model.PostList)
+ if len(p1.Order) != 2 {
+ t.Fatal("Command failed to send")
+ } else {
+ if p1.Posts[p1.Order[0]].Message != `¯\\\_(ツ)\_/¯` {
+ t.Log(p1.Posts[p1.Order[0]].Message)
+ t.Fatal("invalid shrug response")
+ }
+ }
+}
+
+func TestStatusCommands(t *testing.T) {
+ th := Setup().InitBasic()
+ defer th.TearDown()
+
+ commandAndTest(t, th, "away")
+ commandAndTest(t, th, "offline")
+ commandAndTest(t, th, "online")
+}
+
+func commandAndTest(t *testing.T, th *TestHelper, status string) {
+ Client := th.Client
+ channel := th.BasicChannel
+ user := th.BasicUser
+
+ r1 := Client.Must(Client.ExecuteCommand(channel.Id, "/"+status)).(*model.CommandResponse)
+ if r1 == nil {
+ t.Fatal("Command failed to execute")
+ }
+
+ time.Sleep(1000 * time.Millisecond)
+
+ rstatus := Client.Must(Client.GetUserStatus(user.Id, "")).(*model.Status)
+
+ if rstatus.Status != status {
+ t.Fatal("Error setting status " + status)
+ }
+}
diff --git a/api4/oauth_test.go b/api4/oauth_test.go
index 0862f13f5..8cf20ca5e 100644
--- a/api4/oauth_test.go
+++ b/api4/oauth_test.go
@@ -4,12 +4,19 @@
package api4
import (
+ "encoding/base64"
+ "io"
+ "io/ioutil"
"net/http"
"net/url"
"strconv"
"testing"
+ "github.com/stretchr/testify/assert"
+
+ "github.com/mattermost/mattermost-server/einterfaces"
"github.com/mattermost/mattermost-server/model"
+ "github.com/mattermost/mattermost-server/utils"
)
func TestCreateOAuthApp(t *testing.T) {
@@ -726,3 +733,409 @@ func TestDeauthorizeOAuthApp(t *testing.T) {
_, resp = Client.DeauthorizeOAuthApp(rapp.Id)
CheckUnauthorizedStatus(t, resp)
}
+
+func TestOAuthAccessToken(t *testing.T) {
+ if testing.Short() {
+ t.SkipNow()
+ }
+
+ th := Setup().InitBasic()
+ defer th.TearDown()
+
+ Client := th.Client
+
+ enableOAuth := th.App.Config().ServiceSettings.EnableOAuthServiceProvider
+ defer func() {
+ th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableOAuthServiceProvider = enableOAuth })
+ }()
+ th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableOAuthServiceProvider = true })
+
+ defaultRolePermissions := th.SaveDefaultRolePermissions()
+ defer func() {
+ th.RestoreDefaultRolePermissions(defaultRolePermissions)
+ }()
+ th.AddPermissionToRole(model.PERMISSION_MANAGE_OAUTH.Id, model.TEAM_USER_ROLE_ID)
+ th.AddPermissionToRole(model.PERMISSION_MANAGE_OAUTH.Id, model.SYSTEM_USER_ROLE_ID)
+
+ oauthApp := &model.OAuthApp{Name: "TestApp5" + model.NewId(), Homepage: "https://nowhere.com", Description: "test", CallbackUrls: []string{"https://nowhere.com"}}
+ oauthApp = Client.Must(Client.CreateOAuthApp(oauthApp)).(*model.OAuthApp)
+
+ th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableOAuthServiceProvider = false })
+ data := url.Values{"grant_type": []string{"junk"}, "client_id": []string{"12345678901234567890123456"}, "client_secret": []string{"12345678901234567890123456"}, "code": []string{"junk"}, "redirect_uri": []string{oauthApp.CallbackUrls[0]}}
+
+ if _, resp := Client.GetOAuthAccessToken(data); resp.Error == nil {
+ t.Log(resp.StatusCode)
+ t.Fatal("should have failed - oauth providing turned off")
+ }
+ th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableOAuthServiceProvider = true })
+
+ authRequest := &model.AuthorizeRequest{
+ ResponseType: model.AUTHCODE_RESPONSE_TYPE,
+ ClientId: oauthApp.Id,
+ RedirectUri: oauthApp.CallbackUrls[0],
+ Scope: "all",
+ State: "123",
+ }
+
+ redirect, resp := Client.AuthorizeOAuthApp(authRequest)
+ CheckNoError(t, resp)
+ rurl, _ := url.Parse(redirect)
+
+ Client.Logout()
+
+ data = url.Values{"grant_type": []string{"junk"}, "client_id": []string{oauthApp.Id}, "client_secret": []string{oauthApp.ClientSecret}, "code": []string{rurl.Query().Get("code")}, "redirect_uri": []string{oauthApp.CallbackUrls[0]}}
+
+ if _, resp := Client.GetOAuthAccessToken(data); resp.Error == nil {
+ t.Fatal("should have failed - bad grant type")
+ }
+
+ data.Set("grant_type", model.ACCESS_TOKEN_GRANT_TYPE)
+ data.Set("client_id", "")
+ if _, resp := Client.GetOAuthAccessToken(data); resp.Error == nil {
+ t.Fatal("should have failed - missing client id")
+ }
+ data.Set("client_id", "junk")
+ if _, resp := Client.GetOAuthAccessToken(data); resp.Error == nil {
+ t.Fatal("should have failed - bad client id")
+ }
+
+ data.Set("client_id", oauthApp.Id)
+ data.Set("client_secret", "")
+ if _, resp := Client.GetOAuthAccessToken(data); resp.Error == nil {
+ t.Fatal("should have failed - missing client secret")
+ }
+
+ data.Set("client_secret", "junk")
+ if _, resp := Client.GetOAuthAccessToken(data); resp.Error == nil {
+ t.Fatal("should have failed - bad client secret")
+ }
+
+ data.Set("client_secret", oauthApp.ClientSecret)
+ data.Set("code", "")
+ if _, resp := Client.GetOAuthAccessToken(data); resp.Error == nil {
+ t.Fatal("should have failed - missing code")
+ }
+
+ data.Set("code", "junk")
+ if _, resp := Client.GetOAuthAccessToken(data); resp.Error == nil {
+ t.Fatal("should have failed - bad code")
+ }
+
+ data.Set("code", rurl.Query().Get("code"))
+ data.Set("redirect_uri", "junk")
+ if _, resp := Client.GetOAuthAccessToken(data); resp.Error == nil {
+ t.Fatal("should have failed - non-matching redirect uri")
+ }
+
+ // reset data for successful request
+ data.Set("grant_type", model.ACCESS_TOKEN_GRANT_TYPE)
+ data.Set("client_id", oauthApp.Id)
+ data.Set("client_secret", oauthApp.ClientSecret)
+ data.Set("code", rurl.Query().Get("code"))
+ data.Set("redirect_uri", oauthApp.CallbackUrls[0])
+
+ token := ""
+ refreshToken := ""
+ if rsp, resp := Client.GetOAuthAccessToken(data); resp.Error != nil {
+ t.Fatal(resp.Error)
+ } else {
+ if len(rsp.AccessToken) == 0 {
+ t.Fatal("access token not returned")
+ } else if len(rsp.RefreshToken) == 0 {
+ t.Fatal("refresh token not returned")
+ } else {
+ token = rsp.AccessToken
+ refreshToken = rsp.RefreshToken
+ }
+ if rsp.TokenType != model.ACCESS_TOKEN_TYPE {
+ t.Fatal("access token type incorrect")
+ }
+ }
+
+ if _, err := Client.DoApiGet("/users?page=0&per_page=100&access_token="+token, ""); err != nil {
+ t.Fatal(err)
+ }
+
+ if _, resp := Client.GetUsers(0, 100, ""); resp.Error == nil {
+ t.Fatal("should have failed - no access token provided")
+ }
+
+ if _, resp := Client.GetUsers(0, 100, ""); resp.Error == nil {
+ t.Fatal("should have failed - bad access token provided")
+ }
+
+ Client.SetOAuthToken(token)
+ if users, resp := Client.GetUsers(0, 100, ""); resp.Error != nil {
+ t.Fatal(resp.Error)
+ } else {
+ if len(users) == 0 {
+ t.Fatal("users empty - did not get results correctly")
+ }
+ }
+
+ if _, resp := Client.GetOAuthAccessToken(data); resp.Error == nil {
+ t.Fatal("should have failed - tried to reuse auth code")
+ }
+
+ data.Set("grant_type", model.REFRESH_TOKEN_GRANT_TYPE)
+ data.Set("client_id", oauthApp.Id)
+ data.Set("client_secret", oauthApp.ClientSecret)
+ data.Set("refresh_token", "")
+ data.Set("redirect_uri", oauthApp.CallbackUrls[0])
+ data.Del("code")
+ if _, resp := Client.GetOAuthAccessToken(data); resp.Error == nil {
+ t.Fatal("Should have failed - refresh token empty")
+ }
+
+ data.Set("refresh_token", refreshToken)
+ if rsp, resp := Client.GetOAuthAccessToken(data); resp.Error != nil {
+ t.Fatal(resp.Error)
+ } else {
+ if len(rsp.AccessToken) == 0 {
+ t.Fatal("access token not returned")
+ } else if len(rsp.RefreshToken) == 0 {
+ t.Fatal("refresh token not returned")
+ } else if rsp.RefreshToken == refreshToken {
+ t.Fatal("refresh token did not update")
+ }
+
+ if rsp.TokenType != model.ACCESS_TOKEN_TYPE {
+ t.Fatal("access token type incorrect")
+ }
+ Client.SetOAuthToken(rsp.AccessToken)
+ _, resp = Client.GetMe("")
+ if resp.Error != nil {
+ t.Fatal(resp.Error)
+ }
+
+ data.Set("refresh_token", rsp.RefreshToken)
+ }
+
+ if rsp, resp := Client.GetOAuthAccessToken(data); resp.Error != nil {
+ t.Fatal(resp.Error)
+ } else {
+ if len(rsp.AccessToken) == 0 {
+ t.Fatal("access token not returned")
+ } else if len(rsp.RefreshToken) == 0 {
+ t.Fatal("refresh token not returned")
+ } else if rsp.RefreshToken == refreshToken {
+ t.Fatal("refresh token did not update")
+ }
+
+ if rsp.TokenType != model.ACCESS_TOKEN_TYPE {
+ t.Fatal("access token type incorrect")
+ }
+ Client.SetOAuthToken(rsp.AccessToken)
+ _, resp = Client.GetMe("")
+ if resp.Error != nil {
+ t.Fatal(resp.Error)
+ }
+ }
+
+ authData := &model.AuthData{ClientId: oauthApp.Id, RedirectUri: oauthApp.CallbackUrls[0], UserId: th.BasicUser.Id, Code: model.NewId(), ExpiresIn: -1}
+ <-th.App.Srv.Store.OAuth().SaveAuthData(authData)
+
+ data.Set("grant_type", model.ACCESS_TOKEN_GRANT_TYPE)
+ data.Set("client_id", oauthApp.Id)
+ data.Set("client_secret", oauthApp.ClientSecret)
+ data.Set("redirect_uri", oauthApp.CallbackUrls[0])
+ data.Set("code", authData.Code)
+ data.Del("refresh_token")
+ if _, resp := Client.GetOAuthAccessToken(data); resp.Error == nil {
+ t.Fatal("Should have failed - code is expired")
+ }
+
+ Client.ClearOAuthToken()
+}
+
+func TestOAuthComplete(t *testing.T) {
+ if testing.Short() {
+ t.SkipNow()
+ }
+
+ th := Setup().InitBasic()
+ defer th.TearDown()
+
+ Client := th.Client
+
+ r, err := HttpGet(Client.Url+"/login/gitlab/complete?code=123", Client.HttpClient, "", true)
+ assert.NotNil(t, err)
+ closeBody(r)
+
+ th.App.UpdateConfig(func(cfg *model.Config) { cfg.GitLabSettings.Enable = true })
+ r, err = HttpGet(Client.Url+"/login/gitlab/complete?code=123&state=!#$#F@#Yˆ&~ñ", Client.HttpClient, "", true)
+ assert.NotNil(t, err)
+ closeBody(r)
+
+ th.App.UpdateConfig(func(cfg *model.Config) { cfg.GitLabSettings.AuthEndpoint = Client.Url + "/oauth/authorize" })
+ th.App.UpdateConfig(func(cfg *model.Config) { cfg.GitLabSettings.Id = model.NewId() })
+
+ stateProps := map[string]string{}
+ stateProps["action"] = model.OAUTH_ACTION_LOGIN
+ stateProps["team_id"] = th.BasicTeam.Id
+ stateProps["redirect_to"] = th.App.Config().GitLabSettings.AuthEndpoint
+
+ state := base64.StdEncoding.EncodeToString([]byte(model.MapToJson(stateProps)))
+ r, err = HttpGet(Client.Url+"/login/gitlab/complete?code=123&state="+url.QueryEscape(state), Client.HttpClient, "", true)
+ assert.NotNil(t, err)
+ closeBody(r)
+
+ stateProps["hash"] = utils.HashSha256(th.App.Config().GitLabSettings.Id)
+ state = base64.StdEncoding.EncodeToString([]byte(model.MapToJson(stateProps)))
+ r, err = HttpGet(Client.Url+"/login/gitlab/complete?code=123&state="+url.QueryEscape(state), Client.HttpClient, "", true)
+ assert.NotNil(t, err)
+ closeBody(r)
+
+ // We are going to use mattermost as the provider emulating gitlab
+ th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableOAuthServiceProvider = true })
+
+ defaultRolePermissions := th.SaveDefaultRolePermissions()
+ defer func() {
+ th.RestoreDefaultRolePermissions(defaultRolePermissions)
+ }()
+ th.AddPermissionToRole(model.PERMISSION_MANAGE_OAUTH.Id, model.TEAM_USER_ROLE_ID)
+ th.AddPermissionToRole(model.PERMISSION_MANAGE_OAUTH.Id, model.SYSTEM_USER_ROLE_ID)
+
+ oauthApp := &model.OAuthApp{
+ Name: "TestApp5" + model.NewId(),
+ Homepage: "https://nowhere.com",
+ Description: "test",
+ CallbackUrls: []string{
+ Client.Url + "/signup/" + model.SERVICE_GITLAB + "/complete",
+ Client.Url + "/login/" + model.SERVICE_GITLAB + "/complete",
+ },
+ IsTrusted: true,
+ }
+ oauthApp = Client.Must(Client.CreateOAuthApp(oauthApp)).(*model.OAuthApp)
+
+ th.App.UpdateConfig(func(cfg *model.Config) { cfg.GitLabSettings.Id = oauthApp.Id })
+ th.App.UpdateConfig(func(cfg *model.Config) { cfg.GitLabSettings.Secret = oauthApp.ClientSecret })
+ th.App.UpdateConfig(func(cfg *model.Config) { cfg.GitLabSettings.AuthEndpoint = Client.Url + "/oauth/authorize" })
+ th.App.UpdateConfig(func(cfg *model.Config) { cfg.GitLabSettings.TokenEndpoint = Client.Url + "/oauth/access_token" })
+ th.App.UpdateConfig(func(cfg *model.Config) { cfg.GitLabSettings.UserApiEndpoint = Client.ApiUrl + "/users/me" })
+
+ provider := &MattermostTestProvider{}
+
+ authRequest := &model.AuthorizeRequest{
+ ResponseType: model.AUTHCODE_RESPONSE_TYPE,
+ ClientId: oauthApp.Id,
+ RedirectUri: oauthApp.CallbackUrls[0],
+ Scope: "all",
+ State: "123",
+ }
+
+ redirect, resp := Client.AuthorizeOAuthApp(authRequest)
+ CheckNoError(t, resp)
+ rurl, _ := url.Parse(redirect)
+
+ code := rurl.Query().Get("code")
+ stateProps["action"] = model.OAUTH_ACTION_EMAIL_TO_SSO
+ delete(stateProps, "team_id")
+ stateProps["redirect_to"] = th.App.Config().GitLabSettings.AuthEndpoint
+ stateProps["hash"] = utils.HashSha256(th.App.Config().GitLabSettings.Id)
+ stateProps["redirect_to"] = "/oauth/authorize"
+ state = base64.StdEncoding.EncodeToString([]byte(model.MapToJson(stateProps)))
+ if r, err := HttpGet(Client.Url+"/login/"+model.SERVICE_GITLAB+"/complete?code="+url.QueryEscape(code)+"&state="+url.QueryEscape(state), Client.HttpClient, "", false); err == nil {
+ closeBody(r)
+ }
+
+ einterfaces.RegisterOauthProvider(model.SERVICE_GITLAB, provider)
+
+ redirect, resp = Client.AuthorizeOAuthApp(authRequest)
+ CheckNoError(t, resp)
+ rurl, _ = url.Parse(redirect)
+
+ code = rurl.Query().Get("code")
+ if r, err := HttpGet(Client.Url+"/login/"+model.SERVICE_GITLAB+"/complete?code="+url.QueryEscape(code)+"&state="+url.QueryEscape(state), Client.HttpClient, "", false); err == nil {
+ closeBody(r)
+ }
+
+ if result := <-th.App.Srv.Store.User().UpdateAuthData(
+ th.BasicUser.Id, model.SERVICE_GITLAB, &th.BasicUser.Email, th.BasicUser.Email, true); result.Err != nil {
+ t.Fatal(result.Err)
+ }
+
+ redirect, resp = Client.AuthorizeOAuthApp(authRequest)
+ CheckNoError(t, resp)
+ rurl, _ = url.Parse(redirect)
+
+ code = rurl.Query().Get("code")
+ stateProps["action"] = model.OAUTH_ACTION_LOGIN
+ state = base64.StdEncoding.EncodeToString([]byte(model.MapToJson(stateProps)))
+ if r, err := HttpGet(Client.Url+"/login/"+model.SERVICE_GITLAB+"/complete?code="+url.QueryEscape(code)+"&state="+url.QueryEscape(state), Client.HttpClient, "", false); err == nil {
+ closeBody(r)
+ }
+
+ redirect, resp = Client.AuthorizeOAuthApp(authRequest)
+ CheckNoError(t, resp)
+ rurl, _ = url.Parse(redirect)
+
+ code = rurl.Query().Get("code")
+ delete(stateProps, "action")
+ state = base64.StdEncoding.EncodeToString([]byte(model.MapToJson(stateProps)))
+ if r, err := HttpGet(Client.Url+"/login/"+model.SERVICE_GITLAB+"/complete?code="+url.QueryEscape(code)+"&state="+url.QueryEscape(state), Client.HttpClient, "", false); err == nil {
+ closeBody(r)
+ }
+
+ redirect, resp = Client.AuthorizeOAuthApp(authRequest)
+ CheckNoError(t, resp)
+ rurl, _ = url.Parse(redirect)
+
+ code = rurl.Query().Get("code")
+ stateProps["action"] = model.OAUTH_ACTION_SIGNUP
+ state = base64.StdEncoding.EncodeToString([]byte(model.MapToJson(stateProps)))
+ if r, err := HttpGet(Client.Url+"/login/"+model.SERVICE_GITLAB+"/complete?code="+url.QueryEscape(code)+"&state="+url.QueryEscape(state), Client.HttpClient, "", false); err == nil {
+ closeBody(r)
+ }
+}
+
+func HttpGet(url string, httpClient *http.Client, authToken string, followRedirect bool) (*http.Response, *model.AppError) {
+ rq, _ := http.NewRequest("GET", url, nil)
+ rq.Close = true
+
+ if len(authToken) > 0 {
+ rq.Header.Set(model.HEADER_AUTH, authToken)
+ }
+
+ if !followRedirect {
+ httpClient.CheckRedirect = func(req *http.Request, via []*http.Request) error {
+ return http.ErrUseLastResponse
+ }
+ }
+
+ if rp, err := httpClient.Do(rq); err != nil {
+ return nil, model.NewAppError(url, "model.client.connecting.app_error", nil, err.Error(), 0)
+ } else if rp.StatusCode == 304 {
+ return rp, nil
+ } else if rp.StatusCode == 307 {
+ return rp, nil
+ } else if rp.StatusCode >= 300 {
+ defer closeBody(rp)
+ return rp, model.AppErrorFromJson(rp.Body)
+ } else {
+ return rp, nil
+ }
+}
+
+func closeBody(r *http.Response) {
+ if r != nil && r.Body != nil {
+ ioutil.ReadAll(r.Body)
+ r.Body.Close()
+ }
+}
+
+type MattermostTestProvider struct {
+}
+
+func (m *MattermostTestProvider) GetIdentifier() string {
+ return model.SERVICE_GITLAB
+}
+
+func (m *MattermostTestProvider) GetUserFromJson(data io.Reader) *model.User {
+ return model.UserFromJson(data)
+}
+
+func (m *MattermostTestProvider) GetAuthDataFromJson(data io.Reader) string {
+ authData := model.UserFromJson(data)
+ return authData.Email
+}
diff --git a/api4/websocket_test.go b/api4/websocket_test.go
index fa40629dc..9e4c1da73 100644
--- a/api4/websocket_test.go
+++ b/api4/websocket_test.go
@@ -4,10 +4,16 @@
package api4
import (
+ "fmt"
+ "net/http"
+ "strings"
"testing"
"time"
+ "github.com/gorilla/websocket"
+
"github.com/mattermost/mattermost-server/model"
+ "github.com/mattermost/mattermost-server/store"
)
func TestWebSocket(t *testing.T) {
@@ -71,3 +77,384 @@ func TestWebSocket(t *testing.T) {
}
}
}
+
+func TestWebSocketEvent(t *testing.T) {
+ th := Setup().InitBasic()
+ defer th.TearDown()
+
+ WebSocketClient, err := th.CreateWebSocketClient()
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer WebSocketClient.Close()
+
+ WebSocketClient.Listen()
+
+ time.Sleep(300 * time.Millisecond)
+ if resp := <-WebSocketClient.ResponseChannel; resp.Status != model.STATUS_OK {
+ t.Fatal("should have responded OK to authentication challenge")
+ }
+
+ omitUser := make(map[string]bool, 1)
+ omitUser["somerandomid"] = true
+ evt1 := model.NewWebSocketEvent(model.WEBSOCKET_EVENT_TYPING, "", th.BasicChannel.Id, "", omitUser)
+ evt1.Add("user_id", "somerandomid")
+ th.App.Publish(evt1)
+
+ time.Sleep(300 * time.Millisecond)
+
+ stop := make(chan bool)
+ eventHit := false
+
+ go func() {
+ for {
+ select {
+ case resp := <-WebSocketClient.EventChannel:
+ if resp.Event == model.WEBSOCKET_EVENT_TYPING && resp.Data["user_id"].(string) == "somerandomid" {
+ eventHit = true
+ }
+ case <-stop:
+ return
+ }
+ }
+ }()
+
+ time.Sleep(400 * time.Millisecond)
+
+ stop <- true
+
+ if !eventHit {
+ t.Fatal("did not receive typing event")
+ }
+
+ evt2 := model.NewWebSocketEvent(model.WEBSOCKET_EVENT_TYPING, "", "somerandomid", "", nil)
+ th.App.Publish(evt2)
+ time.Sleep(300 * time.Millisecond)
+
+ eventHit = false
+
+ go func() {
+ for {
+ select {
+ case resp := <-WebSocketClient.EventChannel:
+ if resp.Event == model.WEBSOCKET_EVENT_TYPING {
+ eventHit = true
+ }
+ case <-stop:
+ return
+ }
+ }
+ }()
+
+ time.Sleep(400 * time.Millisecond)
+
+ stop <- true
+
+ if eventHit {
+ t.Fatal("got typing event for bad channel id")
+ }
+}
+
+func TestCreateDirectChannelWithSocket(t *testing.T) {
+ th := Setup().InitBasic()
+ defer th.TearDown()
+
+ Client := th.Client
+ user2 := th.BasicUser2
+
+ users := make([]*model.User, 0)
+ users = append(users, user2)
+
+ for i := 0; i < 10; i++ {
+ users = append(users, th.CreateUser())
+ }
+
+ WebSocketClient, err := th.CreateWebSocketClient()
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer WebSocketClient.Close()
+ WebSocketClient.Listen()
+
+ time.Sleep(300 * time.Millisecond)
+ if resp := <-WebSocketClient.ResponseChannel; resp.Status != model.STATUS_OK {
+ t.Fatal("should have responded OK to authentication challenge")
+ }
+
+ wsr := <-WebSocketClient.EventChannel
+ if wsr.Event != model.WEBSOCKET_EVENT_HELLO {
+ t.Fatal("missing hello")
+ }
+
+ stop := make(chan bool)
+ count := 0
+
+ go func() {
+ for {
+ select {
+ case wsr := <-WebSocketClient.EventChannel:
+ if wsr != nil && wsr.Event == model.WEBSOCKET_EVENT_DIRECT_ADDED {
+ count = count + 1
+ }
+
+ case <-stop:
+ return
+ }
+ }
+ }()
+
+ for _, user := range users {
+ time.Sleep(100 * time.Millisecond)
+ if _, resp := Client.CreateDirectChannel(th.BasicUser.Id, user.Id); resp.Error != nil {
+ t.Fatal("failed to create DM channel")
+ }
+ }
+
+ time.Sleep(5000 * time.Millisecond)
+
+ stop <- true
+
+ if count != len(users) {
+ t.Fatal("We didn't get the proper amount of direct_added messages")
+ }
+
+}
+
+func TestWebsocketOriginSecurity(t *testing.T) {
+ th := Setup().InitBasic()
+ defer th.TearDown()
+
+ url := fmt.Sprintf("ws://localhost:%v", th.App.Srv.ListenAddr.Port)
+
+ // Should fail because origin doesn't match
+ _, _, err := websocket.DefaultDialer.Dial(url+model.API_URL_SUFFIX+"/websocket", http.Header{
+ "Origin": []string{"http://www.evil.com"},
+ })
+ if err == nil {
+ t.Fatal("Should have errored because Origin does not match host! SECURITY ISSUE!")
+ }
+
+ // We are not a browser so we can spoof this just fine
+ _, _, err = websocket.DefaultDialer.Dial(url+model.API_URL_SUFFIX+"/websocket", http.Header{
+ "Origin": []string{fmt.Sprintf("http://localhost:%v", th.App.Srv.ListenAddr.Port)},
+ })
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ // Should succeed now because open CORS
+ th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.AllowCorsFrom = "*" })
+ _, _, err = websocket.DefaultDialer.Dial(url+model.API_URL_SUFFIX+"/websocket", http.Header{
+ "Origin": []string{"http://www.evil.com"},
+ })
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ // Should succeed now because matching CORS
+ th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.AllowCorsFrom = "http://www.evil.com" })
+ _, _, err = websocket.DefaultDialer.Dial(url+model.API_URL_SUFFIX+"/websocket", http.Header{
+ "Origin": []string{"http://www.evil.com"},
+ })
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ // Should fail because non-matching CORS
+ th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.AllowCorsFrom = "http://www.good.com" })
+ _, _, err = websocket.DefaultDialer.Dial(url+model.API_URL_SUFFIX+"/websocket", http.Header{
+ "Origin": []string{"http://www.evil.com"},
+ })
+ if err == nil {
+ t.Fatal("Should have errored because Origin contain AllowCorsFrom")
+ }
+
+ // Should fail because non-matching CORS
+ th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.AllowCorsFrom = "http://www.good.com" })
+ _, _, err = websocket.DefaultDialer.Dial(url+model.API_URL_SUFFIX+"/websocket", http.Header{
+ "Origin": []string{"http://www.good.co"},
+ })
+ if err == nil {
+ t.Fatal("Should have errored because Origin does not match host! SECURITY ISSUE!")
+ }
+
+ th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.AllowCorsFrom = "" })
+}
+
+func TestWebSocketStatuses(t *testing.T) {
+ th := Setup().InitBasic()
+ defer th.TearDown()
+
+ Client := th.Client
+ WebSocketClient, err := th.CreateWebSocketClient()
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer WebSocketClient.Close()
+ WebSocketClient.Listen()
+
+ time.Sleep(300 * time.Millisecond)
+ if resp := <-WebSocketClient.ResponseChannel; resp.Status != model.STATUS_OK {
+ t.Fatal("should have responded OK to authentication challenge")
+ }
+
+ team := model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
+ rteam, _ := Client.CreateTeam(&team)
+
+ user := model.User{Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "passwd1"}
+ ruser := Client.Must(Client.CreateUser(&user)).(*model.User)
+ th.LinkUserToTeam(ruser, rteam)
+ store.Must(th.App.Srv.Store.User().VerifyEmail(ruser.Id))
+
+ user2 := model.User{Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "passwd1"}
+ ruser2 := Client.Must(Client.CreateUser(&user2)).(*model.User)
+ th.LinkUserToTeam(ruser2, rteam)
+ store.Must(th.App.Srv.Store.User().VerifyEmail(ruser2.Id))
+
+ Client.Login(user.Email, user.Password)
+
+ th.LoginBasic2()
+
+ WebSocketClient2, err2 := th.CreateWebSocketClient()
+ if err2 != nil {
+ t.Fatal(err2)
+ }
+
+ time.Sleep(1000 * time.Millisecond)
+
+ WebSocketClient.GetStatuses()
+ if resp := <-WebSocketClient.ResponseChannel; resp.Error != nil {
+ t.Fatal(resp.Error)
+ } else {
+ if resp.SeqReply != WebSocketClient.Sequence-1 {
+ t.Fatal("bad sequence number")
+ }
+
+ for _, status := range resp.Data {
+ if status != model.STATUS_OFFLINE && status != model.STATUS_AWAY && status != model.STATUS_ONLINE && status != model.STATUS_DND {
+ t.Fatalf("one of the statuses had an invalid value status=%v", status)
+ }
+ }
+
+ if status, ok := resp.Data[th.BasicUser2.Id]; !ok {
+ t.Log(resp.Data)
+ t.Fatal("should have had user status")
+ } else if status != model.STATUS_ONLINE {
+ t.Log(status)
+ t.Fatal("status should have been online")
+ }
+ }
+
+ WebSocketClient.GetStatusesByIds([]string{th.BasicUser2.Id})
+ if resp := <-WebSocketClient.ResponseChannel; resp.Error != nil {
+ t.Fatal(resp.Error)
+ } else {
+ if resp.SeqReply != WebSocketClient.Sequence-1 {
+ t.Fatal("bad sequence number")
+ }
+
+ for _, status := range resp.Data {
+ if status != model.STATUS_OFFLINE && status != model.STATUS_AWAY && status != model.STATUS_ONLINE {
+ t.Fatal("one of the statuses had an invalid value")
+ }
+ }
+
+ if status, ok := resp.Data[th.BasicUser2.Id]; !ok {
+ t.Log(len(resp.Data))
+ t.Fatal("should have had user status")
+ } else if status != model.STATUS_ONLINE {
+ t.Log(status)
+ t.Fatal("status should have been online")
+ } else if len(resp.Data) != 1 {
+ t.Fatal("only 1 status should be returned")
+ }
+ }
+
+ WebSocketClient.GetStatusesByIds([]string{ruser2.Id, "junk"})
+ if resp := <-WebSocketClient.ResponseChannel; resp.Error != nil {
+ t.Fatal(resp.Error)
+ } else {
+ if resp.SeqReply != WebSocketClient.Sequence-1 {
+ t.Fatal("bad sequence number")
+ }
+
+ if len(resp.Data) != 2 {
+ t.Fatal("2 statuses should be returned")
+ }
+ }
+
+ WebSocketClient.GetStatusesByIds([]string{})
+ if resp := <-WebSocketClient.ResponseChannel; resp.Error == nil {
+ if resp.SeqReply != WebSocketClient.Sequence-1 {
+ t.Fatal("bad sequence number")
+ }
+ t.Fatal("should have errored - empty user ids")
+ }
+
+ WebSocketClient2.Close()
+
+ th.App.SetStatusAwayIfNeeded(th.BasicUser.Id, false)
+
+ awayTimeout := *th.App.Config().TeamSettings.UserStatusAwayTimeout
+ defer func() {
+ th.App.UpdateConfig(func(cfg *model.Config) { *cfg.TeamSettings.UserStatusAwayTimeout = awayTimeout })
+ }()
+ th.App.UpdateConfig(func(cfg *model.Config) { *cfg.TeamSettings.UserStatusAwayTimeout = 1 })
+
+ time.Sleep(1500 * time.Millisecond)
+
+ th.App.SetStatusAwayIfNeeded(th.BasicUser.Id, false)
+ th.App.SetStatusOnline(th.BasicUser.Id, "junk", false)
+
+ time.Sleep(1500 * time.Millisecond)
+
+ WebSocketClient.GetStatuses()
+ if resp := <-WebSocketClient.ResponseChannel; resp.Error != nil {
+ t.Fatal(resp.Error)
+ } else {
+ if resp.SeqReply != WebSocketClient.Sequence-1 {
+ t.Fatal("bad sequence number")
+ }
+
+ if _, ok := resp.Data[th.BasicUser2.Id]; ok {
+ t.Fatal("should not have had user status")
+ }
+ }
+
+ stop := make(chan bool)
+ onlineHit := false
+ awayHit := false
+
+ go func() {
+ for {
+ select {
+ case resp := <-WebSocketClient.EventChannel:
+ if resp.Event == model.WEBSOCKET_EVENT_STATUS_CHANGE && resp.Data["user_id"].(string) == th.BasicUser.Id {
+ status := resp.Data["status"].(string)
+ if status == model.STATUS_ONLINE {
+ onlineHit = true
+ } else if status == model.STATUS_AWAY {
+ awayHit = true
+ }
+ }
+ case <-stop:
+ return
+ }
+ }
+ }()
+
+ time.Sleep(500 * time.Millisecond)
+
+ stop <- true
+
+ if !onlineHit {
+ t.Fatal("didn't get online event")
+ }
+ if !awayHit {
+ t.Fatal("didn't get away event")
+ }
+
+ time.Sleep(500 * time.Millisecond)
+
+ WebSocketClient.Close()
+}
diff --git a/app/auto_channels.go b/app/auto_channels.go
index 78b500961..72561d2b9 100644
--- a/app/auto_channels.go
+++ b/app/auto_channels.go
@@ -9,7 +9,7 @@ import (
)
type AutoChannelCreator struct {
- client *model.Client
+ client *model.Client4
team *model.Team
Fuzzy bool
DisplayNameLen utils.Range
@@ -19,7 +19,7 @@ type AutoChannelCreator struct {
ChannelType string
}
-func NewAutoChannelCreator(client *model.Client, team *model.Team) *AutoChannelCreator {
+func NewAutoChannelCreator(client *model.Client4, team *model.Team) *AutoChannelCreator {
return &AutoChannelCreator{
client: client,
team: team,
@@ -47,14 +47,14 @@ func (cfg *AutoChannelCreator) createRandomChannel() (*model.Channel, bool) {
Name: name,
Type: cfg.ChannelType}
- println(cfg.client.GetTeamRoute())
- result, err := cfg.client.CreateChannel(channel)
- if err != nil {
- println(err.Error())
- println(err.DetailedError)
+ println(cfg.client.GetTeamRoute(cfg.team.Id))
+ channel, resp := cfg.client.CreateChannel(channel)
+ if resp.Error != nil {
+ println(resp.Error.Error())
+ println(resp.Error.DetailedError)
return nil, false
}
- return result.Data.(*model.Channel), true
+ return channel, true
}
func (cfg *AutoChannelCreator) CreateTestChannels(num utils.Range) ([]*model.Channel, bool) {
diff --git a/app/auto_environment.go b/app/auto_environment.go
index 476a1c211..688940337 100644
--- a/app/auto_environment.go
+++ b/app/auto_environment.go
@@ -16,7 +16,7 @@ type TestEnvironment struct {
Environments []TeamEnvironment
}
-func CreateTestEnvironmentWithTeams(a *App, client *model.Client, rangeTeams utils.Range, rangeChannels utils.Range, rangeUsers utils.Range, rangePosts utils.Range, fuzzy bool) (TestEnvironment, bool) {
+func CreateTestEnvironmentWithTeams(a *App, client *model.Client4, rangeTeams utils.Range, rangeChannels utils.Range, rangeUsers utils.Range, rangePosts utils.Range, fuzzy bool) (TestEnvironment, bool) {
rand.Seed(time.Now().UTC().UnixNano())
teamCreator := NewAutoTeamCreator(client)
@@ -36,7 +36,6 @@ func CreateTestEnvironmentWithTeams(a *App, client *model.Client, rangeTeams uti
return TestEnvironment{}, false
}
client.LoginById(randomUser.Id, USER_PASSWORD)
- client.SetTeamId(team.Id)
teamEnvironment, err := CreateTestEnvironmentInTeam(a, client, team, rangeChannels, rangeUsers, rangePosts, fuzzy)
if !err {
return TestEnvironment{}, false
@@ -47,7 +46,7 @@ func CreateTestEnvironmentWithTeams(a *App, client *model.Client, rangeTeams uti
return environment, true
}
-func CreateTestEnvironmentInTeam(a *App, client *model.Client, team *model.Team, rangeChannels utils.Range, rangeUsers utils.Range, rangePosts utils.Range, fuzzy bool) (TeamEnvironment, bool) {
+func CreateTestEnvironmentInTeam(a *App, client *model.Client4, team *model.Team, rangeChannels utils.Range, rangeUsers utils.Range, rangePosts utils.Range, fuzzy bool) (TeamEnvironment, bool) {
rand.Seed(time.Now().UTC().UnixNano())
// We need to create at least one user
@@ -74,7 +73,7 @@ func CreateTestEnvironmentInTeam(a *App, client *model.Client, team *model.Team,
for _, user := range users {
for _, channel := range channels {
client.LoginById(user.Id, USER_PASSWORD)
- client.JoinChannel(channel.Id)
+ client.AddChannelMember(channel.Id, user.Id)
}
}
diff --git a/app/auto_posts.go b/app/auto_posts.go
index a2adb9d6c..23746a9ba 100644
--- a/app/auto_posts.go
+++ b/app/auto_posts.go
@@ -14,7 +14,7 @@ import (
)
type AutoPostCreator struct {
- client *model.Client
+ client *model.Client4
channelid string
Fuzzy bool
TextLength utils.Range
@@ -26,7 +26,7 @@ type AutoPostCreator struct {
}
// Automatic poster used for testing
-func NewAutoPostCreator(client *model.Client, channelid string) *AutoPostCreator {
+func NewAutoPostCreator(client *model.Client4, channelid string) *AutoPostCreator {
return &AutoPostCreator{
client: client,
channelid: channelid,
@@ -56,7 +56,7 @@ func (cfg *AutoPostCreator) UploadTestFile() ([]string, bool) {
return nil, false
}
- resp, appErr := cfg.client.UploadPostAttachment(data.Bytes(), cfg.channelid, filename)
+ resp, appErr := cfg.client.UploadFile(data.Bytes(), cfg.channelid, filename)
if appErr != nil {
return nil, false
}
@@ -85,9 +85,9 @@ func (cfg *AutoPostCreator) CreateRandomPost() (*model.Post, bool) {
ChannelId: cfg.channelid,
Message: postText,
FileIds: fileIds}
- result, err2 := cfg.client.CreatePost(post)
+ rpost, err2 := cfg.client.CreatePost(post)
if err2 != nil {
return nil, false
}
- return result.Data.(*model.Post), true
+ return rpost, true
}
diff --git a/app/auto_teams.go b/app/auto_teams.go
index 9dce5bd15..e322e8c66 100644
--- a/app/auto_teams.go
+++ b/app/auto_teams.go
@@ -14,7 +14,7 @@ type TeamEnvironment struct {
}
type AutoTeamCreator struct {
- client *model.Client
+ client *model.Client4
Fuzzy bool
NameLength utils.Range
NameCharset string
@@ -24,7 +24,7 @@ type AutoTeamCreator struct {
EmailCharset string
}
-func NewAutoTeamCreator(client *model.Client) *AutoTeamCreator {
+func NewAutoTeamCreator(client *model.Client4) *AutoTeamCreator {
return &AutoTeamCreator{
client: client,
Fuzzy: false,
@@ -57,11 +57,10 @@ func (cfg *AutoTeamCreator) createRandomTeam() (*model.Team, bool) {
Type: model.TEAM_OPEN,
}
- result, err := cfg.client.CreateTeam(team)
+ createdTeam, err := cfg.client.CreateTeam(team)
if err != nil {
return nil, false
}
- createdTeam := result.Data.(*model.Team)
return createdTeam, true
}
diff --git a/app/auto_users.go b/app/auto_users.go
index b11f9c572..b61ab053f 100644
--- a/app/auto_users.go
+++ b/app/auto_users.go
@@ -12,7 +12,7 @@ import (
type AutoUserCreator struct {
app *App
- client *model.Client
+ client *model.Client4
team *model.Team
EmailLength utils.Range
EmailCharset string
@@ -21,7 +21,7 @@ type AutoUserCreator struct {
Fuzzy bool
}
-func NewAutoUserCreator(a *App, client *model.Client, team *model.Team) *AutoUserCreator {
+func NewAutoUserCreator(a *App, client *model.Client4, team *model.Team) *AutoUserCreator {
return &AutoUserCreator{
app: a,
client: client,
@@ -35,21 +35,19 @@ func NewAutoUserCreator(a *App, client *model.Client, team *model.Team) *AutoUse
}
// Basic test team and user so you always know one
-func (a *App) CreateBasicUser(client *model.Client) *model.AppError {
- result, _ := client.FindTeamByName(BTEST_TEAM_NAME)
- if !result.Data.(bool) {
+func (a *App) CreateBasicUser(client *model.Client4) *model.AppError {
+ found, _ := client.TeamExists(BTEST_TEAM_NAME, "")
+ if !found {
newteam := &model.Team{DisplayName: BTEST_TEAM_DISPLAY_NAME, Name: BTEST_TEAM_NAME, Email: BTEST_TEAM_EMAIL, Type: BTEST_TEAM_TYPE}
- result, err := client.CreateTeam(newteam)
- if err != nil {
- return err
+ basicteam, resp := client.CreateTeam(newteam)
+ if resp.Error != nil {
+ return resp.Error
}
- basicteam := result.Data.(*model.Team)
newuser := &model.User{Email: BTEST_USER_EMAIL, Nickname: BTEST_USER_NAME, Password: BTEST_USER_PASSWORD}
- result, err = client.CreateUser(newuser, "")
- if err != nil {
- return err
+ ruser, resp := client.CreateUser(newuser)
+ if resp.Error != nil {
+ return resp.Error
}
- ruser := result.Data.(*model.User)
store.Must(a.Srv.Store.User().VerifyEmail(ruser.Id))
store.Must(a.Srv.Store.Team().SaveMember(&model.TeamMember{TeamId: basicteam.Id, UserId: ruser.Id}, *a.Config().TeamSettings.MaxUsersPerTeam))
}
@@ -72,14 +70,12 @@ func (cfg *AutoUserCreator) createRandomUser() (*model.User, bool) {
Nickname: userName,
Password: USER_PASSWORD}
- result, err := cfg.client.CreateUserWithInvite(user, "", "", cfg.team.InviteId)
- if err != nil {
- mlog.Error(err.Error())
+ ruser, resp := cfg.client.CreateUserWithInviteId(user, cfg.team.InviteId)
+ if resp.Error != nil {
+ mlog.Error(resp.Error.Error())
return nil, false
}
- ruser := result.Data.(*model.User)
-
status := &model.Status{UserId: ruser.Id, Status: model.STATUS_ONLINE, Manual: false, LastActivityAt: model.GetMillis(), ActiveChannel: ""}
if result := <-cfg.app.Srv.Store.Status().SaveOrUpdate(status); result.Err != nil {
mlog.Error(result.Err.Error())
@@ -89,7 +85,7 @@ func (cfg *AutoUserCreator) createRandomUser() (*model.User, bool) {
// We need to cheat to verify the user's email
store.Must(cfg.app.Srv.Store.User().VerifyEmail(ruser.Id))
- return result.Data.(*model.User), true
+ return ruser, true
}
func (cfg *AutoUserCreator) CreateTestUsers(num utils.Range) ([]*model.User, bool) {
diff --git a/app/command_loadtest.go b/app/command_loadtest.go
index a4a8f003a..8b3cd2e3b 100644
--- a/app/command_loadtest.go
+++ b/app/command_loadtest.go
@@ -159,7 +159,7 @@ func (me *LoadTestProvider) SetupCommand(a *App, args *model.CommandArgs, messag
numPosts, _ = strconv.Atoi(tokens[numArgs+2])
}
}
- client := model.NewClient(args.SiteURL)
+ client := model.NewAPIv4Client(args.SiteURL)
if doTeams {
if err := a.CreateBasicUser(client); err != nil {
@@ -193,7 +193,6 @@ func (me *LoadTestProvider) SetupCommand(a *App, args *model.CommandArgs, messag
}
client.MockSession(args.Session.Token)
- client.SetTeamId(args.TeamId)
CreateTestEnvironmentInTeam(
a,
client,
@@ -228,8 +227,7 @@ func (me *LoadTestProvider) UsersCommand(a *App, args *model.CommandArgs, messag
team = tr.Data.(*model.Team)
}
- client := model.NewClient(args.SiteURL)
- client.SetTeamId(team.Id)
+ client := model.NewAPIv4Client(args.SiteURL)
userCreator := NewAutoUserCreator(a, client, team)
userCreator.Fuzzy = doFuzz
userCreator.CreateTestUsers(usersr)
@@ -258,8 +256,7 @@ func (me *LoadTestProvider) ChannelsCommand(a *App, args *model.CommandArgs, mes
team = tr.Data.(*model.Team)
}
- client := model.NewClient(args.SiteURL)
- client.SetTeamId(team.Id)
+ client := model.NewAPIv4Client(args.SiteURL)
client.MockSession(args.Session.Token)
channelCreator := NewAutoChannelCreator(client, team)
channelCreator.Fuzzy = doFuzz
@@ -301,8 +298,7 @@ func (me *LoadTestProvider) PostsCommand(a *App, args *model.CommandArgs, messag
}
}
- client := model.NewClient(args.SiteURL)
- client.SetTeamId(args.TeamId)
+ client := model.NewAPIv4Client(args.SiteURL)
client.MockSession(args.Session.Token)
testPoster := NewAutoPostCreator(client, args.ChannelId)
testPoster.Fuzzy = doFuzz
diff --git a/app/diagnostics.go b/app/diagnostics.go
index 7dcea839e..fc8a2e886 100644
--- a/app/diagnostics.go
+++ b/app/diagnostics.go
@@ -6,7 +6,6 @@ package app
import (
"encoding/json"
"runtime"
- "sync/atomic"
"github.com/mattermost/mattermost-server/mlog"
"github.com/mattermost/mattermost-server/model"
@@ -181,10 +180,7 @@ func (a *App) trackActivity() {
"public_channels_deleted": deletedPublicChannelCount,
"private_channels_deleted": deletedPrivateChannelCount,
"posts": postsCount,
- "used_apiv3": atomic.LoadInt32(model.UsedApiV3) == 1,
})
-
- atomic.StoreInt32(model.UsedApiV3, 0)
}
func (a *App) trackConfig() {
@@ -199,7 +195,6 @@ func (a *App) trackConfig() {
"enable_only_admin_integrations": *cfg.ServiceSettings.EnableOnlyAdminIntegrations,
"enable_post_username_override": cfg.ServiceSettings.EnablePostUsernameOverride,
"enable_post_icon_override": cfg.ServiceSettings.EnablePostIconOverride,
- "enable_apiv3": *cfg.ServiceSettings.EnableAPIv3,
"enable_user_access_tokens": *cfg.ServiceSettings.EnableUserAccessTokens,
"enable_custom_emoji": *cfg.ServiceSettings.EnableCustomEmoji,
"enable_emoji_picker": *cfg.ServiceSettings.EnableEmojiPicker,
diff --git a/app/file.go b/app/file.go
index cb8d54cb1..aba09479a 100644
--- a/app/file.go
+++ b/app/file.go
@@ -295,11 +295,6 @@ func (a *App) GeneratePublicLink(siteURL string, info *model.FileInfo) string {
return fmt.Sprintf("%s/files/%v/public?h=%s", siteURL, info.Id, hash)
}
-func (a *App) GeneratePublicLinkV3(siteURL string, info *model.FileInfo) string {
- hash := GeneratePublicLinkHash(info.Id, *a.Config().FileSettings.PublicLinkSalt)
- return fmt.Sprintf("%s%s/public/files/%v/get?h=%s", siteURL, model.API_URL_SUFFIX_V3, info.Id, hash)
-}
-
func GeneratePublicLinkHash(fileId, salt string) string {
hash := sha256.New()
hash.Write([]byte(salt))
diff --git a/app/file_test.go b/app/file_test.go
index 204113782..23750ad6e 100644
--- a/app/file_test.go
+++ b/app/file_test.go
@@ -5,10 +5,16 @@ package app
import (
"fmt"
+ "os"
+ "path/filepath"
"testing"
"time"
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+
"github.com/mattermost/mattermost-server/model"
+ "github.com/mattermost/mattermost-server/utils"
)
func TestGeneratePublicLinkHash(t *testing.T) {
@@ -100,3 +106,58 @@ func TestDoUploadFile(t *testing.T) {
t.Fatal("stored file at incorrect path", info4.Path)
}
}
+
+func TestGetInfoForFilename(t *testing.T) {
+ th := Setup().InitBasic()
+ defer th.TearDown()
+
+ post := th.BasicPost
+ teamId := th.BasicTeam.Id
+
+ info := th.App.GetInfoForFilename(post, teamId, "sometestfile")
+ assert.Nil(t, info, "Test bad filename")
+
+ info = th.App.GetInfoForFilename(post, teamId, "/somechannel/someuser/someid/somefile.png")
+ assert.Nil(t, info, "Test non-existent file")
+}
+
+func TestFindTeamIdForFilename(t *testing.T) {
+ th := Setup().InitBasic()
+ defer th.TearDown()
+
+ teamId := th.App.FindTeamIdForFilename(th.BasicPost, fmt.Sprintf("/%v/%v/%v/blargh.png", th.BasicChannel.Id, th.BasicUser.Id, "someid"))
+ assert.Equal(t, th.BasicTeam.Id, teamId)
+
+ _, err := th.App.CreateTeamWithUser(&model.Team{Email: th.BasicUser.Email, Name: "zz" + model.NewId(), DisplayName: "Joram's Test Team", Type: model.TEAM_OPEN}, th.BasicUser.Id)
+ require.Nil(t, err)
+
+ teamId = th.App.FindTeamIdForFilename(th.BasicPost, fmt.Sprintf("/%v/%v/%v/blargh.png", th.BasicChannel.Id, th.BasicUser.Id, "someid"))
+ assert.Equal(t, "", teamId)
+}
+
+func TestMigrateFilenamesToFileInfos(t *testing.T) {
+ th := Setup().InitBasic()
+ defer th.TearDown()
+
+ post := th.BasicPost
+ infos := th.App.MigrateFilenamesToFileInfos(post)
+ assert.Equal(t, 0, len(infos))
+
+ post.Filenames = []string{fmt.Sprintf("/%v/%v/%v/blargh.png", th.BasicChannel.Id, th.BasicUser.Id, "someid")}
+ infos = th.App.MigrateFilenamesToFileInfos(post)
+ assert.Equal(t, 0, len(infos))
+
+ path, _ := utils.FindDir("tests")
+ file, fileErr := os.Open(filepath.Join(path, "test.png"))
+ require.Nil(t, fileErr)
+ defer file.Close()
+
+ fpath := fmt.Sprintf("/teams/%v/channels/%v/users/%v/%v/test.png", th.BasicTeam.Id, th.BasicChannel.Id, th.BasicUser.Id, "someid")
+ _, err := th.App.WriteFile(file, fpath)
+ require.Nil(t, err)
+ rpost, err := th.App.CreatePost(&model.Post{UserId: th.BasicUser.Id, ChannelId: th.BasicChannel.Id, Filenames: []string{fmt.Sprintf("/%v/%v/%v/test.png", th.BasicChannel.Id, th.BasicUser.Id, "someid")}}, th.BasicChannel, false)
+ require.Nil(t, err)
+
+ infos = th.App.MigrateFilenamesToFileInfos(rpost)
+ assert.Equal(t, 1, len(infos))
+}
diff --git a/cmd/commands/channel_test.go b/cmd/commands/channel_test.go
index bd19b020a..09747b10b 100644
--- a/cmd/commands/channel_test.go
+++ b/cmd/commands/channel_test.go
@@ -7,17 +7,17 @@ import (
"strings"
"testing"
- "github.com/mattermost/mattermost-server/api"
+ "github.com/mattermost/mattermost-server/api4"
"github.com/mattermost/mattermost-server/cmd"
"github.com/mattermost/mattermost-server/model"
"github.com/stretchr/testify/require"
)
func TestJoinChannel(t *testing.T) {
- th := api.Setup().InitBasic()
+ th := api4.Setup().InitBasic()
defer th.TearDown()
- channel := th.CreateChannel(th.BasicClient, th.BasicTeam)
+ channel := th.CreatePublicChannel()
cmd.CheckCommand(t, "channel", "add", th.BasicTeam.Name+":"+channel.Name, th.BasicUser2.Email)
@@ -29,10 +29,10 @@ func TestJoinChannel(t *testing.T) {
}
func TestRemoveChannel(t *testing.T) {
- th := api.Setup().InitBasic()
+ th := api4.Setup().InitBasic()
defer th.TearDown()
- channel := th.CreateChannel(th.BasicClient, th.BasicTeam)
+ channel := th.CreatePublicChannel()
cmd.CheckCommand(t, "channel", "add", th.BasicTeam.Name+":"+channel.Name, th.BasicUser2.Email)
@@ -46,12 +46,11 @@ func TestRemoveChannel(t *testing.T) {
}
func TestMoveChannel(t *testing.T) {
- th := api.Setup().InitBasic()
+ th := api4.Setup().InitBasic()
defer th.TearDown()
- client := th.BasicClient
team1 := th.BasicTeam
- team2 := th.CreateTeam(client)
+ team2 := th.CreateTeam()
user1 := th.BasicUser
th.LinkUserToTeam(user1, team2)
channel := th.BasicChannel
@@ -73,11 +72,11 @@ func TestMoveChannel(t *testing.T) {
}
func TestListChannels(t *testing.T) {
- th := api.Setup().InitBasic()
+ th := api4.Setup().InitBasic()
defer th.TearDown()
- channel := th.CreateChannel(th.BasicClient, th.BasicTeam)
- th.BasicClient.Must(th.BasicClient.DeleteChannel(channel.Id))
+ channel := th.CreatePublicChannel()
+ th.Client.Must(th.Client.DeleteChannel(channel.Id))
output := cmd.CheckCommand(t, "channel", "list", th.BasicTeam.Name)
@@ -91,11 +90,11 @@ func TestListChannels(t *testing.T) {
}
func TestRestoreChannel(t *testing.T) {
- th := api.Setup().InitBasic()
+ th := api4.Setup().InitBasic()
defer th.TearDown()
- channel := th.CreateChannel(th.BasicClient, th.BasicTeam)
- th.BasicClient.Must(th.BasicClient.DeleteChannel(channel.Id))
+ channel := th.CreatePublicChannel()
+ th.Client.Must(th.Client.DeleteChannel(channel.Id))
cmd.CheckCommand(t, "channel", "restore", th.BasicTeam.Name+":"+channel.Name)
@@ -104,7 +103,7 @@ func TestRestoreChannel(t *testing.T) {
}
func TestCreateChannel(t *testing.T) {
- th := api.Setup().InitBasic()
+ th := api4.Setup().InitBasic()
defer th.TearDown()
id := model.NewId()
diff --git a/cmd/commands/roles_test.go b/cmd/commands/roles_test.go
index 1e0a46a4e..b6b3ae10f 100644
--- a/cmd/commands/roles_test.go
+++ b/cmd/commands/roles_test.go
@@ -6,13 +6,13 @@ package commands
import (
"testing"
- "github.com/mattermost/mattermost-server/api"
+ "github.com/mattermost/mattermost-server/api4"
"github.com/mattermost/mattermost-server/cmd"
"github.com/mattermost/mattermost-server/model"
)
func TestAssignRole(t *testing.T) {
- th := api.Setup().InitBasic()
+ th := api4.Setup().InitBasic()
defer th.TearDown()
cmd.CheckCommand(t, "roles", "system_admin", th.BasicUser.Email)
diff --git a/cmd/commands/sampledata_test.go b/cmd/commands/sampledata_test.go
index d71ac0575..183392f11 100644
--- a/cmd/commands/sampledata_test.go
+++ b/cmd/commands/sampledata_test.go
@@ -6,13 +6,13 @@ package commands
import (
"testing"
- "github.com/mattermost/mattermost-server/api"
+ "github.com/mattermost/mattermost-server/api4"
"github.com/mattermost/mattermost-server/cmd"
"github.com/stretchr/testify/require"
)
func TestSampledataBadParameters(t *testing.T) {
- th := api.Setup().InitBasic()
+ th := api4.Setup().InitBasic()
defer th.TearDown()
// should fail because you need at least 1 worker
diff --git a/cmd/commands/server.go b/cmd/commands/server.go
index 441eb82bc..0d354f08e 100644
--- a/cmd/commands/server.go
+++ b/cmd/commands/server.go
@@ -11,7 +11,6 @@ import (
"syscall"
"time"
- "github.com/mattermost/mattermost-server/api"
"github.com/mattermost/mattermost-server/api4"
"github.com/mattermost/mattermost-server/app"
"github.com/mattermost/mattermost-server/cmd"
@@ -104,8 +103,7 @@ func runServer(configFileLocation string, disableConfigWatch bool, interruptChan
return serverErr
}
- api4.Init(a, a.Srv.Router, false)
- api3 := api.Init(a, a.Srv.Router)
+ api := api4.Init(a, a.Srv.Router)
wsapi.Init(a, a.Srv.WebSocketRouter)
web.NewWeb(a, a.Srv.Router)
@@ -135,7 +133,7 @@ func runServer(configFileLocation string, disableConfigWatch bool, interruptChan
// If we allow testing then listen for manual testing URL hits
if a.Config().ServiceSettings.EnableTesting {
- manualtesting.Init(api3)
+ manualtesting.Init(api)
}
a.EnsureDiagnosticId()
diff --git a/cmd/commands/team_test.go b/cmd/commands/team_test.go
index ac006dbe1..e6bc47a09 100644
--- a/cmd/commands/team_test.go
+++ b/cmd/commands/team_test.go
@@ -7,13 +7,13 @@ import (
"strings"
"testing"
- "github.com/mattermost/mattermost-server/api"
+ "github.com/mattermost/mattermost-server/api4"
"github.com/mattermost/mattermost-server/cmd"
"github.com/mattermost/mattermost-server/model"
)
func TestCreateTeam(t *testing.T) {
- th := api.Setup().InitSystemAdmin()
+ th := api4.Setup().InitSystemAdmin()
defer th.TearDown()
id := model.NewId()
@@ -22,7 +22,7 @@ func TestCreateTeam(t *testing.T) {
cmd.CheckCommand(t, "team", "create", "--name", name, "--display_name", displayName)
- found := th.SystemAdminClient.Must(th.SystemAdminClient.FindTeamByName(name)).Data.(bool)
+ found := th.SystemAdminClient.Must(th.SystemAdminClient.TeamExists(name, "")).(bool)
if !found {
t.Fatal("Failed to create Team")
@@ -30,12 +30,12 @@ func TestCreateTeam(t *testing.T) {
}
func TestJoinTeam(t *testing.T) {
- th := api.Setup().InitSystemAdmin().InitBasic()
+ th := api4.Setup().InitSystemAdmin().InitBasic()
defer th.TearDown()
- cmd.CheckCommand(t, "team", "add", th.SystemAdminTeam.Name, th.BasicUser.Email)
+ cmd.CheckCommand(t, "team", "add", th.BasicTeam.Name, th.BasicUser.Email)
- profiles := th.SystemAdminClient.Must(th.SystemAdminClient.GetProfilesInTeam(th.SystemAdminTeam.Id, 0, 1000, "")).Data.(map[string]*model.User)
+ profiles := th.SystemAdminClient.Must(th.SystemAdminClient.GetUsersInTeam(th.BasicTeam.Id, 0, 1000, "")).([]*model.User)
found := false
@@ -52,12 +52,12 @@ func TestJoinTeam(t *testing.T) {
}
func TestLeaveTeam(t *testing.T) {
- th := api.Setup().InitBasic()
+ th := api4.Setup().InitBasic()
defer th.TearDown()
cmd.CheckCommand(t, "team", "remove", th.BasicTeam.Name, th.BasicUser.Email)
- profiles := th.BasicClient.Must(th.BasicClient.GetProfilesInTeam(th.BasicTeam.Id, 0, 1000, "")).Data.(map[string]*model.User)
+ profiles := th.Client.Must(th.Client.GetUsersInTeam(th.BasicTeam.Id, 0, 1000, "")).([]*model.User)
found := false
@@ -81,7 +81,7 @@ func TestLeaveTeam(t *testing.T) {
}
func TestListTeams(t *testing.T) {
- th := api.Setup().InitBasic()
+ th := api4.Setup().InitBasic()
defer th.TearDown()
id := model.NewId()
diff --git a/cmd/commands/test.go b/cmd/commands/test.go
index 62df16438..837b988cc 100644
--- a/cmd/commands/test.go
+++ b/cmd/commands/test.go
@@ -12,7 +12,6 @@ import (
"os/signal"
"syscall"
- "github.com/mattermost/mattermost-server/api"
"github.com/mattermost/mattermost-server/api4"
"github.com/mattermost/mattermost-server/cmd"
"github.com/mattermost/mattermost-server/model"
@@ -60,8 +59,7 @@ func webClientTestsCmdF(command *cobra.Command, args []string) error {
return serverErr
}
- api4.Init(a, a.Srv.Router, false)
- api.Init(a, a.Srv.Router)
+ api4.Init(a, a.Srv.Router)
wsapi.Init(a, a.Srv.WebSocketRouter)
a.UpdateConfig(setupClientTests)
runWebClientTests()
@@ -82,8 +80,7 @@ func serverForWebClientTestsCmdF(command *cobra.Command, args []string) error {
return serverErr
}
- api4.Init(a, a.Srv.Router, false)
- api.Init(a, a.Srv.Router)
+ api4.Init(a, a.Srv.Router)
wsapi.Init(a, a.Srv.WebSocketRouter)
a.UpdateConfig(setupClientTests)
diff --git a/cmd/commands/user_test.go b/cmd/commands/user_test.go
index 8691ac803..e51a6150b 100644
--- a/cmd/commands/user_test.go
+++ b/cmd/commands/user_test.go
@@ -6,14 +6,14 @@ package commands
import (
"testing"
- "github.com/mattermost/mattermost-server/api"
+ "github.com/mattermost/mattermost-server/api4"
"github.com/mattermost/mattermost-server/cmd"
"github.com/mattermost/mattermost-server/model"
"github.com/stretchr/testify/require"
)
func TestCreateUserWithTeam(t *testing.T) {
- th := api.Setup().InitSystemAdmin()
+ th := api4.Setup().InitBasic().InitSystemAdmin()
defer th.TearDown()
id := model.NewId()
@@ -22,9 +22,9 @@ func TestCreateUserWithTeam(t *testing.T) {
cmd.CheckCommand(t, "user", "create", "--email", email, "--password", "mypassword1", "--username", username)
- cmd.CheckCommand(t, "team", "add", th.SystemAdminTeam.Id, email)
+ cmd.CheckCommand(t, "team", "add", th.BasicTeam.Id, email)
- profiles := th.SystemAdminClient.Must(th.SystemAdminClient.GetProfilesInTeam(th.SystemAdminTeam.Id, 0, 1000, "")).Data.(map[string]*model.User)
+ profiles := th.SystemAdminClient.Must(th.SystemAdminClient.GetUsersInTeam(th.BasicTeam.Id, 0, 1000, "")).([]*model.User)
found := false
@@ -41,7 +41,7 @@ func TestCreateUserWithTeam(t *testing.T) {
}
func TestCreateUserWithoutTeam(t *testing.T) {
- th := api.Setup()
+ th := api4.Setup()
defer th.TearDown()
id := model.NewId()
@@ -61,18 +61,18 @@ func TestCreateUserWithoutTeam(t *testing.T) {
}
func TestResetPassword(t *testing.T) {
- th := api.Setup().InitBasic()
+ th := api4.Setup().InitBasic()
defer th.TearDown()
cmd.CheckCommand(t, "user", "password", th.BasicUser.Email, "password2")
- th.BasicClient.Logout()
+ th.Client.Logout()
th.BasicUser.Password = "password2"
th.LoginBasic()
}
func TestMakeUserActiveAndInactive(t *testing.T) {
- th := api.Setup().InitBasic()
+ th := api4.Setup().InitBasic()
defer th.TearDown()
// first inactivate the user
@@ -83,7 +83,7 @@ func TestMakeUserActiveAndInactive(t *testing.T) {
}
func TestChangeUserEmail(t *testing.T) {
- th := api.Setup().InitBasic()
+ th := api4.Setup().InitBasic()
defer th.TearDown()
newEmail := model.NewId() + "@mattermost-test.com"
diff --git a/manualtesting/manual_testing.go b/manualtesting/manual_testing.go
index 7b78fd312..2dbe61343 100644
--- a/manualtesting/manual_testing.go
+++ b/manualtesting/manual_testing.go
@@ -12,28 +12,29 @@ import (
"strconv"
"time"
- "github.com/mattermost/mattermost-server/api"
+ "github.com/mattermost/mattermost-server/api4"
"github.com/mattermost/mattermost-server/app"
"github.com/mattermost/mattermost-server/mlog"
"github.com/mattermost/mattermost-server/model"
"github.com/mattermost/mattermost-server/utils"
+ "github.com/mattermost/mattermost-server/web"
)
type TestEnvironment struct {
Params map[string][]string
- Client *model.Client
+ Client *model.Client4
CreatedTeamId string
CreatedUserId string
- Context *api.Context
+ Context *web.Context
Writer http.ResponseWriter
Request *http.Request
}
-func Init(api3 *api.API) {
- api3.BaseRoutes.Root.Handle("/manualtest", api3.AppHandler(manualTest)).Methods("GET")
+func Init(api4 *api4.API) {
+ api4.BaseRoutes.Root.Handle("/manualtest", api4.ApiHandler(manualTest)).Methods("GET")
}
-func manualTest(c *api.Context, w http.ResponseWriter, r *http.Request) {
+func manualTest(c *web.Context, w http.ResponseWriter, r *http.Request) {
// Let the world know
mlog.Info("Setting up for manual test...")
@@ -56,7 +57,7 @@ func manualTest(c *api.Context, w http.ResponseWriter, r *http.Request) {
}
// Create a client for tests to use
- client := model.NewClient("http://localhost" + *c.App.Config().ServiceSettings.ListenAddress)
+ client := model.NewAPIv4Client("http://localhost" + *c.App.Config().ServiceSettings.ListenAddress)
// Check for username parameter and create a user if present
username, ok1 := params["username"]
@@ -95,22 +96,21 @@ func manualTest(c *api.Context, w http.ResponseWriter, r *http.Request) {
Nickname: username[0],
Password: app.USER_PASSWORD}
- result, err := client.CreateUser(user, "")
- if err != nil {
- c.Err = err
+ user, resp := client.CreateUser(user)
+ if resp.Error != nil {
+ c.Err = resp.Error
return
}
- <-c.App.Srv.Store.User().VerifyEmail(result.Data.(*model.User).Id)
- <-c.App.Srv.Store.Team().SaveMember(&model.TeamMember{TeamId: teamID, UserId: result.Data.(*model.User).Id}, *c.App.Config().TeamSettings.MaxUsersPerTeam)
+ <-c.App.Srv.Store.User().VerifyEmail(user.Id)
+ <-c.App.Srv.Store.Team().SaveMember(&model.TeamMember{TeamId: teamID, UserId: user.Id}, *c.App.Config().TeamSettings.MaxUsersPerTeam)
- newuser := result.Data.(*model.User)
- userID = newuser.Id
+ userID = user.Id
// Login as user to generate auth token
- _, err = client.LoginById(newuser.Id, app.USER_PASSWORD)
- if err != nil {
- c.Err = err
+ _, resp = client.LoginById(user.Id, app.USER_PASSWORD)
+ if resp.Error != nil {
+ c.Err = resp.Error
return
}
diff --git a/manualtesting/test_autolink.go b/manualtesting/test_autolink.go
index 3fe589241..05fd45551 100644
--- a/manualtesting/test_autolink.go
+++ b/manualtesting/test_autolink.go
@@ -31,6 +31,6 @@ func testAutoLink(env TestEnvironment) *model.AppError {
post := &model.Post{
ChannelId: channelID,
Message: LINK_POST_TEXT}
- _, err2 := env.Client.CreatePost(post)
- return err2
+ _, resp := env.Client.CreatePost(post)
+ return resp.Error
}
diff --git a/model/client.go b/model/client.go
deleted file mode 100644
index e648ca279..000000000
--- a/model/client.go
+++ /dev/null
@@ -1,2379 +0,0 @@
-// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-package model
-
-import (
- "bytes"
- "fmt"
- "io"
- "io/ioutil"
- "mime/multipart"
- "net/http"
- "net/url"
- "strconv"
- "strings"
- "time"
-)
-
-var UsedApiV3 *int32 = new(int32)
-
-const (
- HEADER_REQUEST_ID = "X-Request-ID"
- HEADER_VERSION_ID = "X-Version-ID"
- HEADER_CLUSTER_ID = "X-Cluster-ID"
- HEADER_ETAG_SERVER = "ETag"
- HEADER_ETAG_CLIENT = "If-None-Match"
- HEADER_FORWARDED = "X-Forwarded-For"
- HEADER_REAL_IP = "X-Real-IP"
- HEADER_FORWARDED_PROTO = "X-Forwarded-Proto"
- HEADER_TOKEN = "token"
- HEADER_BEARER = "BEARER"
- HEADER_AUTH = "Authorization"
- HEADER_REQUESTED_WITH = "X-Requested-With"
- HEADER_REQUESTED_WITH_XML = "XMLHttpRequest"
- STATUS = "status"
- STATUS_OK = "OK"
- STATUS_FAIL = "FAIL"
- STATUS_REMOVE = "REMOVE"
-
- CLIENT_DIR = "client"
-
- API_URL_SUFFIX_V1 = "/api/v1"
- API_URL_SUFFIX_V3 = "/api/v3"
- API_URL_SUFFIX_V4 = "/api/v4"
- API_URL_SUFFIX = API_URL_SUFFIX_V4
-)
-
-type Result struct {
- RequestId string
- Etag string
- Data interface{}
-}
-
-type ResponseMetadata struct {
- StatusCode int
- Error *AppError
- RequestId string
- Etag string
-}
-
-type Client struct {
- Url string // The location of the server like "http://localhost:8065"
- ApiUrl string // The api location of the server like "http://localhost:8065/api/v3"
- HttpClient *http.Client // The http client
- AuthToken string
- AuthType string
- TeamId string
- RequestId string
- Etag string
- ServerVersion string
-}
-
-// NewClient constructs a new client with convenience methods for talking to
-// the server.
-func NewClient(url string) *Client {
- return &Client{url, url + API_URL_SUFFIX_V3, &http.Client{}, "", "", "", "", "", ""}
-}
-
-func closeBody(r *http.Response) {
- if r.Body != nil {
- ioutil.ReadAll(r.Body)
- r.Body.Close()
- }
-}
-
-func (c *Client) SetOAuthToken(token string) {
- c.AuthToken = token
- c.AuthType = HEADER_TOKEN
-}
-
-func (c *Client) ClearOAuthToken() {
- c.AuthToken = ""
- c.AuthType = HEADER_BEARER
-}
-
-func (c *Client) SetTeamId(teamId string) {
- c.TeamId = teamId
-}
-
-func (c *Client) GetTeamId() string {
- if len(c.TeamId) == 0 {
- println(`You are trying to use a route that requires a team_id,
- but you have not called SetTeamId() in client.go`)
- }
-
- return c.TeamId
-}
-
-func (c *Client) ClearTeamId() {
- c.TeamId = ""
-}
-
-func (c *Client) GetTeamRoute() string {
- return fmt.Sprintf("/teams/%v", c.GetTeamId())
-}
-
-func (c *Client) GetChannelRoute(channelId string) string {
- return fmt.Sprintf("/teams/%v/channels/%v", c.GetTeamId(), channelId)
-}
-
-func (c *Client) GetUserRequiredRoute(userId string) string {
- return fmt.Sprintf("/users/%v", userId)
-}
-
-func (c *Client) GetChannelNameRoute(channelName string) string {
- return fmt.Sprintf("/teams/%v/channels/name/%v", c.GetTeamId(), channelName)
-}
-
-func (c *Client) GetEmojiRoute() string {
- return "/emoji"
-}
-
-func (c *Client) GetGeneralRoute() string {
- return "/general"
-}
-
-func (c *Client) GetFileRoute(fileId string) string {
- return fmt.Sprintf("/files/%v", fileId)
-}
-
-func (c *Client) DoPost(url, data, contentType string) (*http.Response, *AppError) {
- rq, _ := http.NewRequest("POST", c.Url+url, strings.NewReader(data))
- rq.Header.Set("Content-Type", contentType)
- rq.Close = true
-
- if rp, err := c.HttpClient.Do(rq); err != nil {
- return nil, NewAppError(url, "model.client.connecting.app_error", nil, err.Error(), 0)
- } else if rp.StatusCode >= 300 {
- defer closeBody(rp)
- return nil, AppErrorFromJson(rp.Body)
- } else {
- return rp, nil
- }
-}
-
-func (c *Client) DoApiPost(url string, data string) (*http.Response, *AppError) {
- rq, _ := http.NewRequest("POST", c.ApiUrl+url, strings.NewReader(data))
- rq.Close = true
-
- if len(c.AuthToken) > 0 {
- rq.Header.Set(HEADER_AUTH, c.AuthType+" "+c.AuthToken)
- }
-
- if rp, err := c.HttpClient.Do(rq); err != nil {
- return nil, NewAppError(url, "model.client.connecting.app_error", nil, err.Error(), 0)
- } else if rp.StatusCode >= 300 {
- defer closeBody(rp)
- return nil, AppErrorFromJson(rp.Body)
- } else {
- return rp, nil
- }
-}
-
-func (c *Client) DoApiGet(url string, data string, etag string) (*http.Response, *AppError) {
- rq, _ := http.NewRequest("GET", c.ApiUrl+url, strings.NewReader(data))
- rq.Close = true
-
- if len(etag) > 0 {
- rq.Header.Set(HEADER_ETAG_CLIENT, etag)
- }
-
- if len(c.AuthToken) > 0 {
- rq.Header.Set(HEADER_AUTH, c.AuthType+" "+c.AuthToken)
- }
-
- if rp, err := c.HttpClient.Do(rq); err != nil {
- return nil, NewAppError(url, "model.client.connecting.app_error", nil, err.Error(), 0)
- } else if rp.StatusCode == 304 {
- return rp, nil
- } else if rp.StatusCode >= 300 {
- defer closeBody(rp)
- return rp, AppErrorFromJson(rp.Body)
- } else {
- return rp, nil
- }
-}
-
-func getCookie(name string, resp *http.Response) *http.Cookie {
- for _, cookie := range resp.Cookies() {
- if cookie.Name == name {
- return cookie
- }
- }
-
- return nil
-}
-
-// Must is a convenience function used for testing.
-func (c *Client) Must(result *Result, err *AppError) *Result {
- if err != nil {
-
- time.Sleep(time.Second)
- panic(err)
- }
-
- return result
-}
-
-// MustGeneric is a convenience function used for testing.
-func (c *Client) MustGeneric(result interface{}, err *AppError) interface{} {
- if err != nil {
-
- time.Sleep(time.Second)
- panic(err)
- }
-
- return result
-}
-
-// CheckStatusOK is a convenience function for checking the return of Web Service
-// call that return the a map of status=OK.
-func (c *Client) CheckStatusOK(r *http.Response) bool {
- m := MapFromJson(r.Body)
- defer closeBody(r)
-
- if m != nil && m[STATUS] == STATUS_OK {
- return true
- }
-
- return false
-}
-
-func (c *Client) fillInExtraProperties(r *http.Response) {
- c.RequestId = r.Header.Get(HEADER_REQUEST_ID)
- c.Etag = r.Header.Get(HEADER_ETAG_SERVER)
- c.ServerVersion = r.Header.Get(HEADER_VERSION_ID)
-}
-
-func (c *Client) clearExtraProperties() {
- c.RequestId = ""
- c.Etag = ""
- c.ServerVersion = ""
-}
-
-// General Routes Section
-
-// GetClientProperties returns properties needed by the client to show/hide
-// certain features. It returns a map of strings.
-func (c *Client) GetClientProperties() (map[string]string, *AppError) {
- c.clearExtraProperties()
- if r, err := c.DoApiGet(c.GetGeneralRoute()+"/client_props", "", ""); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- c.fillInExtraProperties(r)
- return MapFromJson(r.Body), nil
- }
-}
-
-// LogClient is a convenience Web Service call so clients can log messages into
-// the server-side logs. For example we typically log javascript error messages
-// into the server-side. It returns true if the logging was successful.
-func (c *Client) LogClient(message string) (bool, *AppError) {
- c.clearExtraProperties()
- m := make(map[string]string)
- m["level"] = "ERROR"
- m["message"] = message
-
- if r, err := c.DoApiPost(c.GetGeneralRoute()+"/log_client", MapToJson(m)); err != nil {
- return false, err
- } else {
- defer closeBody(r)
- c.fillInExtraProperties(r)
- return c.CheckStatusOK(r), nil
- }
-}
-
-// GetPing returns a map of strings with server time, server version, and node Id.
-// Systems that want to check on health status of the server should check the
-// url /api/v3/ping for a 200 status response.
-func (c *Client) GetPing() (map[string]string, *AppError) {
- c.clearExtraProperties()
- if r, err := c.DoApiGet(c.GetGeneralRoute()+"/ping", "", ""); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- c.fillInExtraProperties(r)
- return MapFromJson(r.Body), nil
- }
-}
-
-// Team Routes Section
-
-// CreateTeam creates a team based on the provided Team struct. On success it returns
-// the Team struct with the Id, CreateAt and other server-decided fields populated.
-func (c *Client) CreateTeam(team *Team) (*Result, *AppError) {
- if r, err := c.DoApiPost("/teams/create", team.ToJson()); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), TeamFromJson(r.Body)}, nil
- }
-}
-
-// GetAllTeams returns a map of all teams using team ids as the key.
-func (c *Client) GetAllTeams() (*Result, *AppError) {
- if r, err := c.DoApiGet("/teams/all", "", ""); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), TeamMapFromJson(r.Body)}, nil
- }
-}
-
-// GetAllTeamListings returns a map of all teams that are available to join
-// using team ids as the key. Must be authenticated.
-func (c *Client) GetAllTeamListings() (*Result, *AppError) {
- if r, err := c.DoApiGet("/teams/all_team_listings", "", ""); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), TeamMapFromJson(r.Body)}, nil
- }
-}
-
-// FindTeamByName returns the strings "true" or "false" depending on if a team
-// with the provided name was found.
-func (c *Client) FindTeamByName(name string) (*Result, *AppError) {
- m := make(map[string]string)
- m["name"] = name
- if r, err := c.DoApiPost("/teams/find_team_by_name", MapToJson(m)); err != nil {
- return nil, err
- } else {
- val := false
- if body, _ := ioutil.ReadAll(r.Body); string(body) == "true" {
- val = true
- }
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), val}, nil
- }
-}
-
-// Adds a user directly to the team without sending an invite.
-// The teamId and userId are required. You must be a valid member of the team and/or
-// have the correct role to add new users to the team. Returns a map of user_id=userId
-// if successful, otherwise returns an AppError.
-func (c *Client) AddUserToTeam(teamId string, userId string) (*Result, *AppError) {
- if len(teamId) == 0 {
- teamId = c.GetTeamId()
- }
-
- data := make(map[string]string)
- data["user_id"] = userId
- if r, err := c.DoApiPost(fmt.Sprintf("/teams/%v", teamId)+"/add_user_to_team", MapToJson(data)); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
- }
-}
-
-// AddUserToTeamFromInvite adds a user to a team based off data provided in an invite link.
-// Either token and data are required or inviteId is required.
-func (c *Client) AddUserToTeamFromInvite(token, inviteData, inviteId string) (*Result, *AppError) {
- data := make(map[string]string)
- data["token"] = token
- data["data"] = inviteData
- data["invite_id"] = inviteId
- if r, err := c.DoApiPost("/teams/add_user_to_team_from_invite", MapToJson(data)); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), TeamFromJson(r.Body)}, nil
- }
-}
-
-// Removes a user directly from the team.
-// The teamId and userId are required. You must be a valid member of the team and/or
-// have the correct role to remove a user from the team. Returns a map of user_id=userId
-// if successful, otherwise returns an AppError.
-func (c *Client) RemoveUserFromTeam(teamId string, userId string) (*Result, *AppError) {
- if len(teamId) == 0 {
- teamId = c.GetTeamId()
- }
-
- data := make(map[string]string)
- data["user_id"] = userId
- if r, err := c.DoApiPost(fmt.Sprintf("/teams/%v", teamId)+"/remove_user_from_team", MapToJson(data)); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
- }
-}
-
-func (c *Client) InviteMembers(invites *Invites) (*Result, *AppError) {
- if r, err := c.DoApiPost(c.GetTeamRoute()+"/invite_members", invites.ToJson()); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), InvitesFromJson(r.Body)}, nil
- }
-}
-
-// UpdateTeam updates a team based on the changes in the provided team struct. On success
-// it returns a sanitized version of the updated team. Must be authenticated as a team admin
-// for that team or a system admin.
-func (c *Client) UpdateTeam(team *Team) (*Result, *AppError) {
- if r, err := c.DoApiPost(c.GetTeamRoute()+"/update", team.ToJson()); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), TeamFromJson(r.Body)}, nil
- }
-}
-
-// User Routes Section
-
-// CreateUser creates a user in the system based on the provided user struct.
-func (c *Client) CreateUser(user *User, token string) (*Result, *AppError) {
- if r, err := c.DoApiPost("/users/create", user.ToJson()); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), UserFromJson(r.Body)}, nil
- }
-}
-
-// CreateUserWithInvite creates a user based on the provided user struct. Either the token and
-// data strings or the inviteId is required from the invite.
-func (c *Client) CreateUserWithInvite(user *User, token string, data string, inviteId string) (*Result, *AppError) {
-
- url := "/users/create?d=" + url.QueryEscape(data) + "&t=" + url.QueryEscape(token) + "&iid=" + url.QueryEscape(inviteId)
-
- if r, err := c.DoApiPost(url, user.ToJson()); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), UserFromJson(r.Body)}, nil
- }
-}
-
-func (c *Client) CreateUserFromSignup(user *User, data string, token string) (*Result, *AppError) {
- if r, err := c.DoApiPost("/users/create?d="+url.QueryEscape(data)+"&t="+token, user.ToJson()); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), UserFromJson(r.Body)}, nil
- }
-}
-
-// GetUser returns a user based on a provided user id string. Must be authenticated.
-func (c *Client) GetUser(id string, etag string) (*Result, *AppError) {
- if r, err := c.DoApiGet("/users/"+id+"/get", "", etag); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), UserFromJson(r.Body)}, nil
- }
-}
-
-// getByUsername returns a user based on a provided username string. Must be authenticated.
-func (c *Client) GetByUsername(username string, etag string) (*Result, *AppError) {
- if r, err := c.DoApiGet(fmt.Sprintf("/users/name/%v", username), "", etag); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), UserFromJson(r.Body)}, nil
- }
-}
-
-// getByEmail returns a user based on a provided username string. Must be authenticated.
-func (c *Client) GetByEmail(email string, etag string) (*User, *ResponseMetadata) {
- if r, err := c.DoApiGet(fmt.Sprintf("/users/email/%v", email), "", etag); err != nil {
- return nil, &ResponseMetadata{StatusCode: r.StatusCode, Error: err}
- } else {
- defer closeBody(r)
- return UserFromJson(r.Body),
- &ResponseMetadata{
- StatusCode: r.StatusCode,
- RequestId: r.Header.Get(HEADER_REQUEST_ID),
- Etag: r.Header.Get(HEADER_ETAG_SERVER),
- }
- }
-}
-
-// GetMe returns the current user.
-func (c *Client) GetMe(etag string) (*Result, *AppError) {
- if r, err := c.DoApiGet("/users/me", "", etag); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), UserFromJson(r.Body)}, nil
- }
-}
-
-// GetProfiles returns a map of users using user id as the key. Must be authenticated.
-func (c *Client) GetProfiles(offset int, limit int, etag string) (*Result, *AppError) {
- if r, err := c.DoApiGet(fmt.Sprintf("/users/%v/%v", offset, limit), "", etag); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), UserMapFromJson(r.Body)}, nil
- }
-}
-
-// GetProfilesInTeam returns a map of users for a team using user id as the key. Must
-// be authenticated.
-func (c *Client) GetProfilesInTeam(teamId string, offset int, limit int, etag string) (*Result, *AppError) {
- if r, err := c.DoApiGet(fmt.Sprintf("/teams/%v/users/%v/%v", teamId, offset, limit), "", etag); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), UserMapFromJson(r.Body)}, nil
- }
-}
-
-// GetProfilesInChannel returns a map of users for a channel using user id as the key. Must
-// be authenticated.
-func (c *Client) GetProfilesInChannel(channelId string, offset int, limit int, etag string) (*Result, *AppError) {
- if r, err := c.DoApiGet(fmt.Sprintf(c.GetChannelRoute(channelId)+"/users/%v/%v", offset, limit), "", etag); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), UserMapFromJson(r.Body)}, nil
- }
-}
-
-// GetProfilesNotInChannel returns a map of users not in a channel but on the team using user id as the key. Must
-// be authenticated.
-func (c *Client) GetProfilesNotInChannel(channelId string, offset int, limit int, etag string) (*Result, *AppError) {
- if r, err := c.DoApiGet(fmt.Sprintf(c.GetChannelRoute(channelId)+"/users/not_in_channel/%v/%v", offset, limit), "", etag); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), UserMapFromJson(r.Body)}, nil
- }
-}
-
-// GetProfilesByIds returns a map of users based on the user ids provided. Must
-// be authenticated.
-func (c *Client) GetProfilesByIds(userIds []string) (*Result, *AppError) {
- if r, err := c.DoApiPost("/users/ids", ArrayToJson(userIds)); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), UserMapFromJson(r.Body)}, nil
- }
-}
-
-// SearchUsers returns a list of users that have a username matching or similar to the search term. Must
-// be authenticated.
-func (c *Client) SearchUsers(params UserSearch) (*Result, *AppError) {
- if r, err := c.DoApiPost("/users/search", params.ToJson()); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), UserListFromJson(r.Body)}, nil
- }
-}
-
-// AutocompleteUsersInChannel returns two lists for autocompletion of users in a channel. The first list "in_channel",
-// specifies users in the channel. The second list "out_of_channel" specifies users outside of the
-// channel. Term, the string to search against, is required, channel id is also required. Must be authenticated.
-func (c *Client) AutocompleteUsersInChannel(term string, channelId string) (*Result, *AppError) {
- url := fmt.Sprintf("%s/users/autocomplete?term=%s", c.GetChannelRoute(channelId), url.QueryEscape(term))
- if r, err := c.DoApiGet(url, "", ""); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), UserAutocompleteInChannelFromJson(r.Body)}, nil
- }
-}
-
-// AutocompleteUsersInTeam returns a list for autocompletion of users in a team. The list "in_team" specifies
-// the users in the team that match the provided term, matching against username, full name and
-// nickname. Must be authenticated.
-func (c *Client) AutocompleteUsersInTeam(term string) (*Result, *AppError) {
- url := fmt.Sprintf("%s/users/autocomplete?term=%s", c.GetTeamRoute(), url.QueryEscape(term))
- if r, err := c.DoApiGet(url, "", ""); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), UserAutocompleteInTeamFromJson(r.Body)}, nil
- }
-}
-
-// AutocompleteUsers returns a list for autocompletion of users on the system that match the provided term,
-// matching against username, full name and nickname. Must be authenticated.
-func (c *Client) AutocompleteUsers(term string) (*Result, *AppError) {
- url := fmt.Sprintf("/users/autocomplete?term=%s", url.QueryEscape(term))
- if r, err := c.DoApiGet(url, "", ""); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), UserListFromJson(r.Body)}, nil
- }
-}
-
-// LoginById authenticates a user by user id and password.
-func (c *Client) LoginById(id string, password string) (*Result, *AppError) {
- m := make(map[string]string)
- m["id"] = id
- m["password"] = password
- return c.login(m)
-}
-
-// Login authenticates a user by login id, which can be username, email or some sort
-// of SSO identifier based on configuration, and a password.
-func (c *Client) Login(loginId string, password string) (*Result, *AppError) {
- m := make(map[string]string)
- m["login_id"] = loginId
- m["password"] = password
- return c.login(m)
-}
-
-// LoginByLdap authenticates a user by LDAP id and password.
-func (c *Client) LoginByLdap(loginId string, password string) (*Result, *AppError) {
- m := make(map[string]string)
- m["login_id"] = loginId
- m["password"] = password
- m["ldap_only"] = "true"
- return c.login(m)
-}
-
-// LoginWithDevice authenticates a user by login id (username, email or some sort
-// of SSO identifier based on configuration), password and attaches a device id to
-// the session.
-func (c *Client) LoginWithDevice(loginId string, password string, deviceId string) (*Result, *AppError) {
- m := make(map[string]string)
- m["login_id"] = loginId
- m["password"] = password
- m["device_id"] = deviceId
- return c.login(m)
-}
-
-func (c *Client) login(m map[string]string) (*Result, *AppError) {
- if r, err := c.DoApiPost("/users/login", MapToJson(m)); err != nil {
- return nil, err
- } else {
- c.AuthToken = r.Header.Get(HEADER_TOKEN)
- c.AuthType = HEADER_BEARER
- sessionToken := getCookie(SESSION_COOKIE_TOKEN, r)
-
- if c.AuthToken != sessionToken.Value {
- NewAppError("/users/login", "model.client.login.app_error", nil, "", 0)
- }
-
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), UserFromJson(r.Body)}, nil
- }
-}
-
-// Logout terminates the current user's session.
-func (c *Client) Logout() (*Result, *AppError) {
- if r, err := c.DoApiPost("/users/logout", ""); err != nil {
- return nil, err
- } else {
- c.AuthToken = ""
- c.AuthType = HEADER_BEARER
- c.TeamId = ""
-
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
- }
-}
-
-// CheckMfa returns a map with key "mfa_required" with the string value "true" or "false",
-// indicating whether MFA is required to log the user in, based on a provided login id
-// (username, email or some sort of SSO identifier based on configuration).
-func (c *Client) CheckMfa(loginId string) (*Result, *AppError) {
- m := make(map[string]string)
- m["login_id"] = loginId
-
- if r, err := c.DoApiPost("/users/mfa", MapToJson(m)); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
- }
-}
-
-// GenerateMfaSecret returns a QR code image containing the secret, to be scanned
-// by a multi-factor authentication mobile application. It also returns the secret
-// for manual entry. Must be authenticated.
-func (c *Client) GenerateMfaSecret() (*Result, *AppError) {
- if r, err := c.DoApiGet("/users/generate_mfa_secret", "", ""); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
- }
-}
-
-// UpdateMfa activates multi-factor authenticates for the current user if activate
-// is true and a valid token is provided. If activate is false, then token is not
-// required and multi-factor authentication is disabled for the current user.
-func (c *Client) UpdateMfa(activate bool, token string) (*Result, *AppError) {
- m := make(map[string]interface{})
- m["activate"] = activate
- m["token"] = token
-
- if r, err := c.DoApiPost("/users/update_mfa", StringInterfaceToJson(m)); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
- }
-}
-
-func (c *Client) AdminResetMfa(userId string) (*Result, *AppError) {
- m := make(map[string]string)
- m["user_id"] = userId
-
- if r, err := c.DoApiPost("/admin/reset_mfa", MapToJson(m)); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
- }
-}
-
-func (c *Client) RevokeSession(sessionAltId string) (*Result, *AppError) {
- m := make(map[string]string)
- m["id"] = sessionAltId
-
- if r, err := c.DoApiPost("/users/revoke_session", MapToJson(m)); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
- }
-}
-
-func (c *Client) GetSessions(id string) (*Result, *AppError) {
- if r, err := c.DoApiGet("/users/"+id+"/sessions", "", ""); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), SessionsFromJson(r.Body)}, nil
- }
-}
-
-func (c *Client) EmailToOAuth(m map[string]string) (*Result, *AppError) {
- if r, err := c.DoApiPost("/users/claim/email_to_oauth", MapToJson(m)); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
- }
-}
-
-func (c *Client) OAuthToEmail(m map[string]string) (*Result, *AppError) {
- if r, err := c.DoApiPost("/users/claim/oauth_to_email", MapToJson(m)); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
- }
-}
-
-func (c *Client) LDAPToEmail(m map[string]string) (*Result, *AppError) {
- if r, err := c.DoApiPost("/users/claim/ldap_to_email", MapToJson(m)); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
- }
-}
-
-func (c *Client) EmailToLDAP(m map[string]string) (*Result, *AppError) {
- if r, err := c.DoApiPost("/users/claim/ldap_to_email", MapToJson(m)); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
- }
-}
-
-func (c *Client) Command(channelId string, command string) (*Result, *AppError) {
- args := &CommandArgs{ChannelId: channelId, Command: command}
- if r, err := c.DoApiPost(c.GetTeamRoute()+"/commands/execute", args.ToJson()); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
-
- response, _ := CommandResponseFromJson(r.Body)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), response}, nil
- }
-}
-
-func (c *Client) ListCommands() (*Result, *AppError) {
- if r, err := c.DoApiGet(c.GetTeamRoute()+"/commands/list", "", ""); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), CommandListFromJson(r.Body)}, nil
- }
-}
-
-func (c *Client) ListTeamCommands() (*Result, *AppError) {
- if r, err := c.DoApiGet(c.GetTeamRoute()+"/commands/list_team_commands", "", ""); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), CommandListFromJson(r.Body)}, nil
- }
-}
-
-func (c *Client) CreateCommand(cmd *Command) (*Result, *AppError) {
- if r, err := c.DoApiPost(c.GetTeamRoute()+"/commands/create", cmd.ToJson()); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), CommandFromJson(r.Body)}, nil
- }
-}
-
-func (c *Client) UpdateCommand(cmd *Command) (*Result, *AppError) {
- if r, err := c.DoApiPost(c.GetTeamRoute()+"/commands/update", cmd.ToJson()); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), CommandFromJson(r.Body)}, nil
- }
-}
-
-func (c *Client) RegenCommandToken(data map[string]string) (*Result, *AppError) {
- if r, err := c.DoApiPost(c.GetTeamRoute()+"/commands/regen_token", MapToJson(data)); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), CommandFromJson(r.Body)}, nil
- }
-}
-
-func (c *Client) DeleteCommand(data map[string]string) (*Result, *AppError) {
- if r, err := c.DoApiPost(c.GetTeamRoute()+"/commands/delete", MapToJson(data)); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
- }
-}
-
-func (c *Client) GetAudits(id string, etag string) (*Result, *AppError) {
- if r, err := c.DoApiGet("/users/"+id+"/audits", "", etag); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), AuditsFromJson(r.Body)}, nil
- }
-}
-
-func (c *Client) GetLogs() (*Result, *AppError) {
- if r, err := c.DoApiGet("/admin/logs", "", ""); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), ArrayFromJson(r.Body)}, nil
- }
-}
-
-func (c *Client) GetClusterStatus() ([]*ClusterInfo, *AppError) {
- if r, err := c.DoApiGet("/admin/cluster_status", "", ""); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return ClusterInfosFromJson(r.Body), nil
- }
-}
-
-// GetRecentlyActiveUsers returns a map of users including lastActivityAt using user id as the key
-func (c *Client) GetRecentlyActiveUsers(teamId string) (*Result, *AppError) {
- if r, err := c.DoApiGet("/admin/recently_active_users/"+teamId, "", ""); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), UserMapFromJson(r.Body)}, nil
- }
-}
-
-func (c *Client) GetAllAudits() (*Result, *AppError) {
- if r, err := c.DoApiGet("/admin/audits", "", ""); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), AuditsFromJson(r.Body)}, nil
- }
-}
-
-func (c *Client) GetConfig() (*Result, *AppError) {
- if r, err := c.DoApiGet("/admin/config", "", ""); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), ConfigFromJson(r.Body)}, nil
- }
-}
-
-// ReloadConfig will reload the config.json file from disk. Properties
-// requiring a server restart will still need a server restart. You must
-// have the system admin role to call this method. It will return status=OK
-// if it's successfully reloaded the config file, otherwise check the returned error.
-func (c *Client) ReloadConfig() (bool, *AppError) {
- c.clearExtraProperties()
- if r, err := c.DoApiGet("/admin/reload_config", "", ""); err != nil {
- return false, err
- } else {
- c.fillInExtraProperties(r)
- return c.CheckStatusOK(r), nil
- }
-}
-
-func (c *Client) InvalidateAllCaches() (bool, *AppError) {
- c.clearExtraProperties()
- if r, err := c.DoApiGet("/admin/invalidate_all_caches", "", ""); err != nil {
- return false, err
- } else {
- c.fillInExtraProperties(r)
- return c.CheckStatusOK(r), nil
- }
-}
-
-func (c *Client) SaveConfig(config *Config) (*Result, *AppError) {
- if r, err := c.DoApiPost("/admin/save_config", config.ToJson()); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
- }
-}
-
-// RecycleDatabaseConnection will attempt to recycle the database connections.
-// You must have the system admin role to call this method. It will return status=OK
-// if it's successfully recycled the connections, otherwise check the returned error.
-func (c *Client) RecycleDatabaseConnection() (bool, *AppError) {
- c.clearExtraProperties()
- if r, err := c.DoApiGet("/admin/recycle_db_conn", "", ""); err != nil {
- return false, err
- } else {
- c.fillInExtraProperties(r)
- return c.CheckStatusOK(r), nil
- }
-}
-
-func (c *Client) TestEmail(config *Config) (*Result, *AppError) {
- if r, err := c.DoApiPost("/admin/test_email", config.ToJson()); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
- }
-}
-
-// TestLdap will run a connection test on the current LDAP settings.
-// It will return the standard OK response if settings work. Otherwise
-// it will return an appropriate error.
-func (c *Client) TestLdap(config *Config) (*Result, *AppError) {
- if r, err := c.DoApiPost("/admin/ldap_test", config.ToJson()); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
- }
-}
-
-func (c *Client) GetComplianceReports() (*Result, *AppError) {
- if r, err := c.DoApiGet("/admin/compliance_reports", "", ""); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), CompliancesFromJson(r.Body)}, nil
- }
-}
-
-func (c *Client) SaveComplianceReport(job *Compliance) (*Result, *AppError) {
- if r, err := c.DoApiPost("/admin/save_compliance_report", job.ToJson()); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), ComplianceFromJson(r.Body)}, nil
- }
-}
-
-func (c *Client) DownloadComplianceReport(id string) (*Result, *AppError) {
- var rq *http.Request
- rq, _ = http.NewRequest("GET", c.ApiUrl+"/admin/download_compliance_report/"+id, nil)
- rq.Close = true
-
- if len(c.AuthToken) > 0 {
- rq.Header.Set(HEADER_AUTH, "BEARER "+c.AuthToken)
- }
-
- if rp, err := c.HttpClient.Do(rq); err != nil {
- return nil, NewAppError("/admin/download_compliance_report", "model.client.connecting.app_error", nil, err.Error(), 0)
- } else if rp.StatusCode >= 300 {
- defer rp.Body.Close()
- return nil, AppErrorFromJson(rp.Body)
- } else {
- defer closeBody(rp)
- return &Result{rp.Header.Get(HEADER_REQUEST_ID),
- rp.Header.Get(HEADER_ETAG_SERVER), rp.Body}, nil
- }
-}
-
-func (c *Client) GetTeamAnalytics(teamId, name string) (*Result, *AppError) {
- if r, err := c.DoApiGet("/admin/analytics/"+teamId+"/"+name, "", ""); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), AnalyticsRowsFromJson(r.Body)}, nil
- }
-}
-
-func (c *Client) GetSystemAnalytics(name string) (*Result, *AppError) {
- if r, err := c.DoApiGet("/admin/analytics/"+name, "", ""); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), AnalyticsRowsFromJson(r.Body)}, nil
- }
-}
-
-// Initiate immediate synchronization of LDAP users.
-// The synchronization will be performed asynchronously and this function will
-// always return OK unless you don't have permissions.
-// You must be the system administrator to use this function.
-func (c *Client) LdapSyncNow() (*Result, *AppError) {
- if r, err := c.DoApiPost("/admin/ldap_sync_now", ""); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
- }
-}
-
-func (c *Client) CreateChannel(channel *Channel) (*Result, *AppError) {
- if r, err := c.DoApiPost(c.GetTeamRoute()+"/channels/create", channel.ToJson()); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), ChannelFromJson(r.Body)}, nil
- }
-}
-
-func (c *Client) CreateDirectChannel(userId string) (*Result, *AppError) {
- data := make(map[string]string)
- data["user_id"] = userId
- if r, err := c.DoApiPost(c.GetTeamRoute()+"/channels/create_direct", MapToJson(data)); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), ChannelFromJson(r.Body)}, nil
- }
-}
-
-func (c *Client) CreateGroupChannel(userIds []string) (*Result, *AppError) {
- if r, err := c.DoApiPost(c.GetTeamRoute()+"/channels/create_group", ArrayToJson(userIds)); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), ChannelFromJson(r.Body)}, nil
- }
-}
-
-func (c *Client) UpdateChannel(channel *Channel) (*Result, *AppError) {
- if r, err := c.DoApiPost(c.GetTeamRoute()+"/channels/update", channel.ToJson()); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), ChannelFromJson(r.Body)}, nil
- }
-}
-
-func (c *Client) UpdateChannelHeader(data map[string]string) (*Result, *AppError) {
- if r, err := c.DoApiPost(c.GetTeamRoute()+"/channels/update_header", MapToJson(data)); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), ChannelFromJson(r.Body)}, nil
- }
-}
-
-func (c *Client) UpdateChannelPurpose(data map[string]string) (*Result, *AppError) {
- if r, err := c.DoApiPost(c.GetTeamRoute()+"/channels/update_purpose", MapToJson(data)); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), ChannelFromJson(r.Body)}, nil
- }
-}
-
-func (c *Client) UpdateNotifyProps(data map[string]string) (*Result, *AppError) {
- if r, err := c.DoApiPost(c.GetTeamRoute()+"/channels/update_notify_props", MapToJson(data)); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
- }
-}
-
-func (c *Client) GetMyChannelMembers() (*Result, *AppError) {
- if r, err := c.DoApiGet(c.GetTeamRoute()+"/channels/members", "", ""); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), ChannelMembersFromJson(r.Body)}, nil
- }
-}
-
-func (c *Client) GetChannel(id, etag string) (*Result, *AppError) {
- if r, err := c.DoApiGet(c.GetChannelRoute(id)+"/", "", etag); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), ChannelDataFromJson(r.Body)}, nil
- }
-}
-
-// GetMoreChannelsPage will return a page of open channels the user is not in based on
-// the provided offset and limit. Must be authenticated.
-func (c *Client) GetMoreChannelsPage(offset int, limit int) (*Result, *AppError) {
- if r, err := c.DoApiGet(fmt.Sprintf(c.GetTeamRoute()+"/channels/more/%v/%v", offset, limit), "", ""); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), ChannelListFromJson(r.Body)}, nil
- }
-}
-
-// SearchMoreChannels will return a list of open channels the user is not in, that matches
-// the search criteria provided. Must be authenticated.
-func (c *Client) SearchMoreChannels(channelSearch ChannelSearch) (*Result, *AppError) {
- if r, err := c.DoApiPost(c.GetTeamRoute()+"/channels/more/search", channelSearch.ToJson()); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), ChannelListFromJson(r.Body)}, nil
- }
-}
-
-// AutocompleteChannels will return a list of open channels that match the provided
-// string. Must be authenticated.
-func (c *Client) AutocompleteChannels(term string) (*Result, *AppError) {
- url := fmt.Sprintf("%s/channels/autocomplete?term=%s", c.GetTeamRoute(), url.QueryEscape(term))
- if r, err := c.DoApiGet(url, "", ""); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), ChannelListFromJson(r.Body)}, nil
- }
-}
-
-func (c *Client) GetChannelCounts(etag string) (*Result, *AppError) {
- if r, err := c.DoApiGet(c.GetTeamRoute()+"/channels/counts", "", etag); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), ChannelCountsFromJson(r.Body)}, nil
- }
-}
-
-func (c *Client) GetChannels(etag string) (*Result, *AppError) {
- if r, err := c.DoApiGet(c.GetTeamRoute()+"/channels/", "", etag); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), ChannelListFromJson(r.Body)}, nil
- }
-}
-
-func (c *Client) GetChannelByName(channelName string) (*Result, *AppError) {
- if r, err := c.DoApiGet(c.GetChannelNameRoute(channelName), "", ""); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), ChannelFromJson(r.Body)}, nil
- }
-}
-
-func (c *Client) JoinChannel(id string) (*Result, *AppError) {
- if r, err := c.DoApiPost(c.GetChannelRoute(id)+"/join", ""); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), nil}, nil
- }
-}
-
-func (c *Client) JoinChannelByName(name string) (*Result, *AppError) {
- if r, err := c.DoApiPost(c.GetChannelNameRoute(name)+"/join", ""); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), nil}, nil
- }
-}
-
-func (c *Client) LeaveChannel(id string) (*Result, *AppError) {
- if r, err := c.DoApiPost(c.GetChannelRoute(id)+"/leave", ""); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), nil}, nil
- }
-}
-
-func (c *Client) DeleteChannel(id string) (*Result, *AppError) {
- if r, err := c.DoApiPost(c.GetChannelRoute(id)+"/delete", ""); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), nil}, nil
- }
-}
-
-func (c *Client) AddChannelMember(id, user_id string) (*Result, *AppError) {
- data := make(map[string]string)
- data["user_id"] = user_id
- if r, err := c.DoApiPost(c.GetChannelRoute(id)+"/add", MapToJson(data)); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), nil}, nil
- }
-}
-
-func (c *Client) RemoveChannelMember(id, user_id string) (*Result, *AppError) {
- data := make(map[string]string)
- data["user_id"] = user_id
- if r, err := c.DoApiPost(c.GetChannelRoute(id)+"/remove", MapToJson(data)); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), nil}, nil
- }
-}
-
-// ViewChannel performs all the actions related to viewing a channel. This includes marking
-// the channel and the previous one as read, and marking the channel as being actively viewed.
-// ChannelId is required but may be blank to indicate no channel is being viewed.
-// PrevChannelId is optional, populate to indicate a channel switch occurred.
-func (c *Client) ViewChannel(params ChannelView) (bool, *ResponseMetadata) {
- if r, err := c.DoApiPost(c.GetTeamRoute()+"/channels/view", params.ToJson()); err != nil {
- return false, &ResponseMetadata{StatusCode: r.StatusCode, Error: err}
- } else {
- return c.CheckStatusOK(r),
- &ResponseMetadata{
- StatusCode: r.StatusCode,
- RequestId: r.Header.Get(HEADER_REQUEST_ID),
- Etag: r.Header.Get(HEADER_ETAG_SERVER),
- }
- }
-}
-
-func (c *Client) GetChannelStats(id string, etag string) (*Result, *AppError) {
- if r, err := c.DoApiGet(c.GetChannelRoute(id)+"/stats", "", etag); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), ChannelStatsFromJson(r.Body)}, nil
- }
-}
-
-func (c *Client) GetChannelMember(channelId string, userId string) (*Result, *AppError) {
- if r, err := c.DoApiGet(c.GetChannelRoute(channelId)+"/members/"+userId, "", ""); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), ChannelMemberFromJson(r.Body)}, nil
- }
-}
-
-// GetChannelMembersByIds will return channel member objects as an array based on the
-// channel id and a list of user ids provided. Must be authenticated.
-func (c *Client) GetChannelMembersByIds(channelId string, userIds []string) (*Result, *AppError) {
- if r, err := c.DoApiPost(c.GetChannelRoute(channelId)+"/members/ids", ArrayToJson(userIds)); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), ChannelMembersFromJson(r.Body)}, nil
- }
-}
-
-func (c *Client) CreatePost(post *Post) (*Result, *AppError) {
- if r, err := c.DoApiPost(c.GetChannelRoute(post.ChannelId)+"/posts/create", post.ToJson()); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), PostFromJson(r.Body)}, nil
- }
-}
-
-func (c *Client) UpdatePost(post *Post) (*Result, *AppError) {
- if r, err := c.DoApiPost(c.GetChannelRoute(post.ChannelId)+"/posts/update", post.ToJson()); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), PostFromJson(r.Body)}, nil
- }
-}
-
-func (c *Client) GetPosts(channelId string, offset int, limit int, etag string) (*Result, *AppError) {
- if r, err := c.DoApiGet(c.GetChannelRoute(channelId)+fmt.Sprintf("/posts/page/%v/%v", offset, limit), "", etag); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), PostListFromJson(r.Body)}, nil
- }
-}
-
-func (c *Client) GetPostsSince(channelId string, time int64) (*Result, *AppError) {
- if r, err := c.DoApiGet(c.GetChannelRoute(channelId)+fmt.Sprintf("/posts/since/%v", time), "", ""); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), PostListFromJson(r.Body)}, nil
- }
-}
-
-func (c *Client) GetPostsBefore(channelId string, postid string, offset int, limit int, etag string) (*Result, *AppError) {
- if r, err := c.DoApiGet(c.GetChannelRoute(channelId)+fmt.Sprintf("/posts/%v/before/%v/%v", postid, offset, limit), "", etag); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), PostListFromJson(r.Body)}, nil
- }
-}
-
-func (c *Client) GetPostsAfter(channelId string, postid string, offset int, limit int, etag string) (*Result, *AppError) {
- if r, err := c.DoApiGet(fmt.Sprintf(c.GetChannelRoute(channelId)+"/posts/%v/after/%v/%v", postid, offset, limit), "", etag); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), PostListFromJson(r.Body)}, nil
- }
-}
-
-func (c *Client) GetPost(channelId string, postId string, etag string) (*Result, *AppError) {
- if r, err := c.DoApiGet(c.GetChannelRoute(channelId)+fmt.Sprintf("/posts/%v/get", postId), "", etag); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), PostListFromJson(r.Body)}, nil
- }
-}
-
-// GetPostById returns a post and any posts in the same thread by post id
-func (c *Client) GetPostById(postId string, etag string) (*PostList, *ResponseMetadata) {
- if r, err := c.DoApiGet(c.GetTeamRoute()+fmt.Sprintf("/posts/%v", postId), "", etag); err != nil {
- return nil, &ResponseMetadata{StatusCode: r.StatusCode, Error: err}
- } else {
- defer closeBody(r)
- return PostListFromJson(r.Body),
- &ResponseMetadata{
- StatusCode: r.StatusCode,
- RequestId: r.Header.Get(HEADER_REQUEST_ID),
- Etag: r.Header.Get(HEADER_ETAG_SERVER),
- }
- }
-}
-
-// GetPermalink returns a post list, based on the provided channel and post ID.
-func (c *Client) GetPermalink(channelId string, postId string, etag string) (*PostList, *ResponseMetadata) {
- if r, err := c.DoApiGet(c.GetTeamRoute()+fmt.Sprintf("/pltmp/%v", postId), "", etag); err != nil {
- return nil, &ResponseMetadata{StatusCode: r.StatusCode, Error: err}
- } else {
- defer closeBody(r)
- return PostListFromJson(r.Body),
- &ResponseMetadata{
- StatusCode: r.StatusCode,
- RequestId: r.Header.Get(HEADER_REQUEST_ID),
- Etag: r.Header.Get(HEADER_ETAG_SERVER),
- }
- }
-}
-
-func (c *Client) DeletePost(channelId string, postId string) (*Result, *AppError) {
- if r, err := c.DoApiPost(c.GetChannelRoute(channelId)+fmt.Sprintf("/posts/%v/delete", postId), ""); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
- }
-}
-
-func (c *Client) SearchPosts(terms string, isOrSearch bool) (*Result, *AppError) {
- data := map[string]interface{}{}
- data["terms"] = terms
- data["is_or_search"] = isOrSearch
- if r, err := c.DoApiPost(c.GetTeamRoute()+"/posts/search", StringInterfaceToJson(data)); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), PostListFromJson(r.Body)}, nil
- }
-}
-
-// GetFlaggedPosts will return a post list of posts that have been flagged by the user.
-// The page is set by the integer parameters offset and limit.
-func (c *Client) GetFlaggedPosts(offset int, limit int) (*Result, *AppError) {
- if r, err := c.DoApiGet(c.GetTeamRoute()+fmt.Sprintf("/posts/flagged/%v/%v", offset, limit), "", ""); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), PostListFromJson(r.Body)}, nil
- }
-}
-
-func (c *Client) GetPinnedPosts(channelId string) (*Result, *AppError) {
- if r, err := c.DoApiGet(c.GetChannelRoute(channelId)+"/pinned", "", ""); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), PostListFromJson(r.Body)}, nil
- }
-}
-
-func (c *Client) UploadProfileFile(data []byte, contentType string) (*Result, *AppError) {
- return c.uploadFile(c.ApiUrl+"/users/newimage", data, contentType)
-}
-
-func (c *Client) UploadPostAttachment(data []byte, channelId string, filename string) (*FileUploadResponse, *AppError) {
- c.clearExtraProperties()
-
- body := &bytes.Buffer{}
- writer := multipart.NewWriter(body)
-
- if part, err := writer.CreateFormFile("files", filename); err != nil {
- return nil, NewAppError("UploadPostAttachment", "model.client.upload_post_attachment.file.app_error", nil, err.Error(), 0)
- } else if _, err = io.Copy(part, bytes.NewBuffer(data)); err != nil {
- return nil, NewAppError("UploadPostAttachment", "model.client.upload_post_attachment.file.app_error", nil, err.Error(), 0)
- }
-
- if part, err := writer.CreateFormField("channel_id"); err != nil {
- return nil, NewAppError("UploadPostAttachment", "model.client.upload_post_attachment.channel_id.app_error", nil, err.Error(), 0)
- } else if _, err = io.Copy(part, strings.NewReader(channelId)); err != nil {
- return nil, NewAppError("UploadPostAttachment", "model.client.upload_post_attachment.channel_id.app_error", nil, err.Error(), 0)
- }
-
- if err := writer.Close(); err != nil {
- return nil, NewAppError("UploadPostAttachment", "model.client.upload_post_attachment.writer.app_error", nil, err.Error(), 0)
- }
-
- if result, err := c.uploadFile(c.ApiUrl+c.GetTeamRoute()+"/files/upload", body.Bytes(), writer.FormDataContentType()); err != nil {
- return nil, err
- } else {
- return result.Data.(*FileUploadResponse), nil
- }
-}
-
-func (c *Client) uploadFile(url string, data []byte, contentType string) (*Result, *AppError) {
- rq, _ := http.NewRequest("POST", url, bytes.NewReader(data))
- rq.Header.Set("Content-Type", contentType)
- rq.Close = true
-
- if len(c.AuthToken) > 0 {
- rq.Header.Set(HEADER_AUTH, "BEARER "+c.AuthToken)
- }
-
- if rp, err := c.HttpClient.Do(rq); err != nil {
- return nil, NewAppError(url, "model.client.connecting.app_error", nil, err.Error(), 0)
- } else if rp.StatusCode >= 300 {
- return nil, AppErrorFromJson(rp.Body)
- } else {
- defer closeBody(rp)
- return &Result{rp.Header.Get(HEADER_REQUEST_ID),
- rp.Header.Get(HEADER_ETAG_SERVER), FileUploadResponseFromJson(rp.Body)}, nil
- }
-}
-
-func (c *Client) GetFile(fileId string) (io.ReadCloser, *AppError) {
- if r, err := c.DoApiGet(c.GetFileRoute(fileId)+"/get", "", ""); err != nil {
- return nil, err
- } else {
- c.fillInExtraProperties(r)
- return r.Body, nil
- }
-}
-
-func (c *Client) GetFileThumbnail(fileId string) (io.ReadCloser, *AppError) {
- if r, err := c.DoApiGet(c.GetFileRoute(fileId)+"/get_thumbnail", "", ""); err != nil {
- return nil, err
- } else {
- c.fillInExtraProperties(r)
- return r.Body, nil
- }
-}
-
-func (c *Client) GetFilePreview(fileId string) (io.ReadCloser, *AppError) {
- if r, err := c.DoApiGet(c.GetFileRoute(fileId)+"/get_preview", "", ""); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- c.fillInExtraProperties(r)
- return r.Body, nil
- }
-}
-
-func (c *Client) GetFileInfo(fileId string) (*FileInfo, *AppError) {
- if r, err := c.DoApiGet(c.GetFileRoute(fileId)+"/get_info", "", ""); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- c.fillInExtraProperties(r)
- return FileInfoFromJson(r.Body), nil
- }
-}
-
-func (c *Client) GetPublicLink(fileId string) (string, *AppError) {
- if r, err := c.DoApiGet(c.GetFileRoute(fileId)+"/get_public_link", "", ""); err != nil {
- return "", err
- } else {
- defer closeBody(r)
- c.fillInExtraProperties(r)
- return StringFromJson(r.Body), nil
- }
-}
-
-func (c *Client) UpdateUser(user *User) (*Result, *AppError) {
- if r, err := c.DoApiPost("/users/update", user.ToJson()); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), UserFromJson(r.Body)}, nil
- }
-}
-
-func (c *Client) UpdateUserRoles(userId string, roles string) (*Result, *AppError) {
- data := make(map[string]string)
- data["new_roles"] = roles
-
- if r, err := c.DoApiPost(c.GetUserRequiredRoute(userId)+"/update_roles", MapToJson(data)); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
- }
-}
-
-func (c *Client) UpdateTeamRoles(userId string, roles string) (*Result, *AppError) {
- data := make(map[string]string)
- data["new_roles"] = roles
- data["user_id"] = userId
-
- if r, err := c.DoApiPost(c.GetTeamRoute()+"/update_member_roles", MapToJson(data)); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
- }
-}
-
-func (c *Client) AttachDeviceId(deviceId string) (*Result, *AppError) {
- data := make(map[string]string)
- data["device_id"] = deviceId
- if r, err := c.DoApiPost("/users/attach_device", MapToJson(data)); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), UserFromJson(r.Body)}, nil
- }
-}
-
-func (c *Client) UpdateActive(userId string, active bool) (*Result, *AppError) {
- data := make(map[string]string)
- data["user_id"] = userId
- data["active"] = strconv.FormatBool(active)
- if r, err := c.DoApiPost("/users/update_active", MapToJson(data)); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), UserFromJson(r.Body)}, nil
- }
-}
-
-func (c *Client) UpdateUserNotify(data map[string]string) (*Result, *AppError) {
- if r, err := c.DoApiPost("/users/update_notify", MapToJson(data)); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), UserFromJson(r.Body)}, nil
- }
-}
-
-func (c *Client) UpdateUserPassword(userId, currentPassword, newPassword string) (*Result, *AppError) {
- data := make(map[string]string)
- data["current_password"] = currentPassword
- data["new_password"] = newPassword
- data["user_id"] = userId
-
- if r, err := c.DoApiPost("/users/newpassword", MapToJson(data)); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
- }
-}
-
-func (c *Client) SendPasswordReset(email string) (*Result, *AppError) {
- data := map[string]string{}
- data["email"] = email
- if r, err := c.DoApiPost("/users/send_password_reset", MapToJson(data)); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
- }
-}
-
-func (c *Client) ResetPassword(code, newPassword string) (*Result, *AppError) {
- data := map[string]string{}
- data["code"] = code
- data["new_password"] = newPassword
- if r, err := c.DoApiPost("/users/reset_password", MapToJson(data)); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
- }
-}
-
-func (c *Client) AdminResetPassword(userId, newPassword string) (*Result, *AppError) {
- data := map[string]string{}
- data["user_id"] = userId
- data["new_password"] = newPassword
- if r, err := c.DoApiPost("/admin/reset_password", MapToJson(data)); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
- }
-}
-
-// GetStatuses returns a map of string statuses using user id as the key
-func (c *Client) GetStatuses() (*Result, *AppError) {
- if r, err := c.DoApiGet("/users/status", "", ""); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
- }
-}
-
-// GetStatusesByIds returns a map of string statuses using user id as the key,
-// based on the provided user ids
-func (c *Client) GetStatusesByIds(userIds []string) (*Result, *AppError) {
- if r, err := c.DoApiPost("/users/status/ids", ArrayToJson(userIds)); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
- }
-}
-
-func (c *Client) GetMyTeam(etag string) (*Result, *AppError) {
- if r, err := c.DoApiGet(c.GetTeamRoute()+"/me", "", etag); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), TeamFromJson(r.Body)}, nil
- }
-}
-
-// GetTeamMembers will return a page of team member objects as an array paged based on the
-// team id, offset and limit provided. Must be authenticated.
-func (c *Client) GetTeamMembers(teamId string, offset int, limit int) (*Result, *AppError) {
- if r, err := c.DoApiGet(fmt.Sprintf("/teams/%v/members/%v/%v", teamId, offset, limit), "", ""); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), TeamMembersFromJson(r.Body)}, nil
- }
-}
-
-// GetMyTeamMembers will return an array with team member objects that the current user
-// is a member of. Must be authenticated.
-func (c *Client) GetMyTeamMembers() (*Result, *AppError) {
- if r, err := c.DoApiGet("/teams/members", "", ""); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), TeamMembersFromJson(r.Body)}, nil
- }
-}
-
-// GetMyTeamsUnread will return an array with TeamUnread objects that contain the amount of
-// unread messages and mentions the current user has for the teams it belongs to.
-// An optional team ID can be set to exclude that team from the results. Must be authenticated.
-func (c *Client) GetMyTeamsUnread(teamId string) (*Result, *AppError) {
- endpoint := "/teams/unread"
-
- if teamId != "" {
- endpoint += fmt.Sprintf("?id=%s", url.QueryEscape(teamId))
- }
- if r, err := c.DoApiGet(endpoint, "", ""); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), TeamsUnreadFromJson(r.Body)}, nil
- }
-}
-
-// GetTeamMember will return a team member object based on the team id and user id provided.
-// Must be authenticated.
-func (c *Client) GetTeamMember(teamId string, userId string) (*Result, *AppError) {
- if r, err := c.DoApiGet(fmt.Sprintf("/teams/%v/members/%v", teamId, userId), "", ""); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), TeamMemberFromJson(r.Body)}, nil
- }
-}
-
-// GetTeamStats will return a team stats object containing the number of users on the team
-// based on the team id provided. Must be authenticated.
-func (c *Client) GetTeamStats(teamId string) (*Result, *AppError) {
- if r, err := c.DoApiGet(fmt.Sprintf("/teams/%v/stats", teamId), "", ""); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), TeamStatsFromJson(r.Body)}, nil
- }
-}
-
-// GetTeamByName will return a team object based on the team name provided. Must be authenticated.
-func (c *Client) GetTeamByName(teamName string) (*Result, *AppError) {
- if r, err := c.DoApiGet(fmt.Sprintf("/teams/name/%v", teamName), "", ""); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), TeamFromJson(r.Body)}, nil
- }
-}
-
-// GetTeamMembersByIds will return team member objects as an array based on the
-// team id and a list of user ids provided. Must be authenticated.
-func (c *Client) GetTeamMembersByIds(teamId string, userIds []string) (*Result, *AppError) {
- if r, err := c.DoApiPost(fmt.Sprintf("/teams/%v/members/ids", teamId), ArrayToJson(userIds)); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), TeamMembersFromJson(r.Body)}, nil
- }
-}
-
-// RegisterApp creates a new OAuth2 app to be used with the OAuth2 Provider. On success
-// it returns the created app. Must be authenticated as a user.
-func (c *Client) RegisterApp(app *OAuthApp) (*Result, *AppError) {
- if r, err := c.DoApiPost("/oauth/register", app.ToJson()); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), OAuthAppFromJson(r.Body)}, nil
- }
-}
-
-// AllowOAuth allows a new session by an OAuth2 App. On success
-// it returns the url to be redirected back to the app which initiated the oauth2 flow.
-// Must be authenticated as a user.
-func (c *Client) AllowOAuth(rspType, clientId, redirect, scope, state string) (*Result, *AppError) {
- if r, err := c.DoApiGet("/oauth/allow?response_type="+rspType+"&client_id="+clientId+"&redirect_uri="+url.QueryEscape(redirect)+"&scope="+scope+"&state="+url.QueryEscape(state), "", ""); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
- }
-}
-
-// GetOAuthAppsByUser returns the OAuth2 Apps registered by the user. On success
-// it returns a list of OAuth2 Apps from the same user or all the registered apps if the user
-// is a System Administrator. Must be authenticated as a user.
-func (c *Client) GetOAuthAppsByUser() (*Result, *AppError) {
- if r, err := c.DoApiGet("/oauth/list", "", ""); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), OAuthAppListFromJson(r.Body)}, nil
- }
-}
-
-// GetOAuthAppInfo lookup an OAuth2 App using the client_id. On success
-// it returns a Sanitized OAuth2 App. Must be authenticated as a user.
-func (c *Client) GetOAuthAppInfo(clientId string) (*Result, *AppError) {
- if r, err := c.DoApiGet("/oauth/app/"+clientId, "", ""); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), OAuthAppFromJson(r.Body)}, nil
- }
-}
-
-// DeleteOAuthApp deletes an OAuth2 app, the app must be deleted by the same user who created it or
-// a System Administrator. On success returs Status OK. Must be authenticated as a user.
-func (c *Client) DeleteOAuthApp(id string) (*Result, *AppError) {
- data := make(map[string]string)
- data["id"] = id
- if r, err := c.DoApiPost("/oauth/delete", MapToJson(data)); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
- }
-}
-
-// GetOAuthAuthorizedApps returns the OAuth2 Apps authorized by the user. On success
-// it returns a list of sanitized OAuth2 Authorized Apps by the user.
-func (c *Client) GetOAuthAuthorizedApps() (*Result, *AppError) {
- if r, err := c.DoApiGet("/oauth/authorized", "", ""); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), OAuthAppListFromJson(r.Body)}, nil
- }
-}
-
-// OAuthDeauthorizeApp deauthorize a user an OAuth 2.0 app. On success
-// it returns status OK or an AppError on fail.
-func (c *Client) OAuthDeauthorizeApp(clientId string) *AppError {
- if r, err := c.DoApiPost("/oauth/"+clientId+"/deauthorize", ""); err != nil {
- return err
- } else {
- defer closeBody(r)
- return nil
- }
-}
-
-// RegenerateOAuthAppSecret generates a new OAuth App Client Secret. On success
-// it returns an OAuth2 App. Must be authenticated as a user and the same user who
-// registered the app or a System Admin.
-func (c *Client) RegenerateOAuthAppSecret(clientId string) (*Result, *AppError) {
- if r, err := c.DoApiPost("/oauth/"+clientId+"/regen_secret", ""); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), OAuthAppFromJson(r.Body)}, nil
- }
-}
-
-func (c *Client) GetAccessToken(data url.Values) (*Result, *AppError) {
- if r, err := c.DoPost("/oauth/access_token", data.Encode(), "application/x-www-form-urlencoded"); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), AccessResponseFromJson(r.Body)}, nil
- }
-}
-
-func (c *Client) CreateIncomingWebhook(hook *IncomingWebhook) (*Result, *AppError) {
- if r, err := c.DoApiPost(c.GetTeamRoute()+"/hooks/incoming/create", hook.ToJson()); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), IncomingWebhookFromJson(r.Body)}, nil
- }
-}
-
-func (c *Client) UpdateIncomingWebhook(hook *IncomingWebhook) (*Result, *AppError) {
- if r, err := c.DoApiPost(c.GetTeamRoute()+"/hooks/incoming/update", hook.ToJson()); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), IncomingWebhookFromJson(r.Body)}, nil
- }
-}
-
-func (c *Client) PostToWebhook(id, payload string) (*Result, *AppError) {
- if r, err := c.DoPost("/hooks/"+id, payload, "application/x-www-form-urlencoded"); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), nil}, nil
- }
-}
-
-func (c *Client) DeleteIncomingWebhook(id string) (*Result, *AppError) {
- data := make(map[string]string)
- data["id"] = id
- if r, err := c.DoApiPost(c.GetTeamRoute()+"/hooks/incoming/delete", MapToJson(data)); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
- }
-}
-
-func (c *Client) ListIncomingWebhooks() (*Result, *AppError) {
- if r, err := c.DoApiGet(c.GetTeamRoute()+"/hooks/incoming/list", "", ""); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), IncomingWebhookListFromJson(r.Body)}, nil
- }
-}
-
-func (c *Client) GetAllPreferences() (*Result, *AppError) {
- if r, err := c.DoApiGet("/preferences/", "", ""); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- preferences, _ := PreferencesFromJson(r.Body)
- return &Result{r.Header.Get(HEADER_REQUEST_ID), r.Header.Get(HEADER_ETAG_SERVER), preferences}, nil
- }
-}
-
-func (c *Client) SetPreferences(preferences *Preferences) (*Result, *AppError) {
- if r, err := c.DoApiPost("/preferences/save", preferences.ToJson()); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), preferences}, nil
- }
-}
-
-func (c *Client) GetPreference(category string, name string) (*Result, *AppError) {
- if r, err := c.DoApiGet("/preferences/"+category+"/"+name, "", ""); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID), r.Header.Get(HEADER_ETAG_SERVER), PreferenceFromJson(r.Body)}, nil
- }
-}
-
-func (c *Client) GetPreferenceCategory(category string) (*Result, *AppError) {
- if r, err := c.DoApiGet("/preferences/"+category, "", ""); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- preferences, _ := PreferencesFromJson(r.Body)
- return &Result{r.Header.Get(HEADER_REQUEST_ID), r.Header.Get(HEADER_ETAG_SERVER), preferences}, nil
- }
-}
-
-// DeletePreferences deletes a list of preferences owned by the current user. If successful,
-// it will return status=ok. Otherwise, an error will be returned.
-func (c *Client) DeletePreferences(preferences *Preferences) (bool, *AppError) {
- if r, err := c.DoApiPost("/preferences/delete", preferences.ToJson()); err != nil {
- return false, err
- } else {
- return c.CheckStatusOK(r), nil
- }
-}
-
-func (c *Client) CreateOutgoingWebhook(hook *OutgoingWebhook) (*Result, *AppError) {
- if r, err := c.DoApiPost(c.GetTeamRoute()+"/hooks/outgoing/create", hook.ToJson()); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), OutgoingWebhookFromJson(r.Body)}, nil
- }
-}
-
-func (c *Client) UpdateOutgoingWebhook(hook *OutgoingWebhook) (*Result, *AppError) {
- if r, err := c.DoApiPost(c.GetTeamRoute()+"/hooks/outgoing/update", hook.ToJson()); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), OutgoingWebhookFromJson(r.Body)}, nil
- }
-}
-
-func (c *Client) DeleteOutgoingWebhook(id string) (*Result, *AppError) {
- data := make(map[string]string)
- data["id"] = id
- if r, err := c.DoApiPost(c.GetTeamRoute()+"/hooks/outgoing/delete", MapToJson(data)); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
- }
-}
-
-func (c *Client) ListOutgoingWebhooks() (*Result, *AppError) {
- if r, err := c.DoApiGet(c.GetTeamRoute()+"/hooks/outgoing/list", "", ""); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), OutgoingWebhookListFromJson(r.Body)}, nil
- }
-}
-
-func (c *Client) RegenOutgoingWebhookToken(id string) (*Result, *AppError) {
- data := make(map[string]string)
- data["id"] = id
- if r, err := c.DoApiPost(c.GetTeamRoute()+"/hooks/outgoing/regen_token", MapToJson(data)); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), OutgoingWebhookFromJson(r.Body)}, nil
- }
-}
-
-func (c *Client) MockSession(sessionToken string) {
- c.AuthToken = sessionToken
- c.AuthType = HEADER_BEARER
-}
-
-func (c *Client) GetClientLicenceConfig(etag string) (*Result, *AppError) {
- if r, err := c.DoApiGet("/license/client_config", "", etag); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
- }
-}
-
-func (c *Client) GetInitialLoad() (*Result, *AppError) {
- if r, err := c.DoApiGet("/users/initial_load", "", ""); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), InitialLoadFromJson(r.Body)}, nil
- }
-}
-
-// ListEmoji returns a list of all user-created emoji for the server.
-func (c *Client) ListEmoji() ([]*Emoji, *AppError) {
- if r, err := c.DoApiGet(c.GetEmojiRoute()+"/list", "", ""); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- c.fillInExtraProperties(r)
- return EmojiListFromJson(r.Body), nil
- }
-}
-
-// CreateEmoji will save an emoji to the server if the current user has permission
-// to do so. If successful, the provided emoji will be returned with its Id field
-// filled in. Otherwise, an error will be returned.
-func (c *Client) CreateEmoji(emoji *Emoji, image []byte, filename string) (*Emoji, *AppError) {
- c.clearExtraProperties()
-
- body := &bytes.Buffer{}
- writer := multipart.NewWriter(body)
-
- if part, err := writer.CreateFormFile("image", filename); err != nil {
- return nil, NewAppError("CreateEmoji", "model.client.create_emoji.image.app_error", nil, err.Error(), 0)
- } else if _, err = io.Copy(part, bytes.NewBuffer(image)); err != nil {
- return nil, NewAppError("CreateEmoji", "model.client.create_emoji.image.app_error", nil, err.Error(), 0)
- }
-
- if err := writer.WriteField("emoji", emoji.ToJson()); err != nil {
- return nil, NewAppError("CreateEmoji", "model.client.create_emoji.emoji.app_error", nil, err.Error(), 0)
- }
-
- if err := writer.Close(); err != nil {
- return nil, NewAppError("CreateEmoji", "model.client.create_emoji.writer.app_error", nil, err.Error(), 0)
- }
-
- rq, _ := http.NewRequest("POST", c.ApiUrl+c.GetEmojiRoute()+"/create", body)
- rq.Header.Set("Content-Type", writer.FormDataContentType())
- rq.Close = true
-
- if len(c.AuthToken) > 0 {
- rq.Header.Set(HEADER_AUTH, "BEARER "+c.AuthToken)
- }
-
- if r, err := c.HttpClient.Do(rq); err != nil {
- return nil, NewAppError("CreateEmoji", "model.client.connecting.app_error", nil, err.Error(), 0)
- } else if r.StatusCode >= 300 {
- return nil, AppErrorFromJson(r.Body)
- } else {
- defer closeBody(r)
- c.fillInExtraProperties(r)
- return EmojiFromJson(r.Body), nil
- }
-}
-
-// DeleteEmoji will delete an emoji from the server if the current user has permission
-// to do so. If successful, it will return status=ok. Otherwise, an error will be returned.
-func (c *Client) DeleteEmoji(id string) (bool, *AppError) {
- data := map[string]string{"id": id}
-
- if r, err := c.DoApiPost(c.GetEmojiRoute()+"/delete", MapToJson(data)); err != nil {
- return false, err
- } else {
- defer closeBody(r)
- c.fillInExtraProperties(r)
- return c.CheckStatusOK(r), nil
- }
-}
-
-// GetCustomEmojiImageUrl returns the API route that can be used to get the image used by
-// the given emoji.
-func (c *Client) GetCustomEmojiImageUrl(id string) string {
- return c.GetEmojiRoute() + "/" + id
-}
-
-// Uploads a x509 base64 Certificate or Private Key file to be used with SAML.
-// data byte array is required and needs to be a Multi-Part with 'certificate' as the field name
-// contentType is also required. Returns nil if successful, otherwise returns an AppError
-func (c *Client) UploadCertificateFile(data []byte, contentType string) *AppError {
- url := c.ApiUrl + "/admin/add_certificate"
- rq, _ := http.NewRequest("POST", url, bytes.NewReader(data))
- rq.Header.Set("Content-Type", contentType)
- rq.Close = true
-
- if len(c.AuthToken) > 0 {
- rq.Header.Set(HEADER_AUTH, "BEARER "+c.AuthToken)
- }
-
- if rp, err := c.HttpClient.Do(rq); err != nil {
- return NewAppError(url, "model.client.connecting.app_error", nil, err.Error(), 0)
- } else if rp.StatusCode >= 300 {
- return AppErrorFromJson(rp.Body)
- } else {
- defer closeBody(rp)
- c.fillInExtraProperties(rp)
- return nil
- }
-}
-
-// Removes a x509 base64 Certificate or Private Key file used with SAML.
-// filename is required. Returns nil if successful, otherwise returns an AppError
-func (c *Client) RemoveCertificateFile(filename string) *AppError {
- if r, err := c.DoApiPost("/admin/remove_certificate", MapToJson(map[string]string{"filename": filename})); err != nil {
- return err
- } else {
- defer closeBody(r)
- c.fillInExtraProperties(r)
- return nil
- }
-}
-
-// Checks if the x509 base64 Certificates and Private Key files used with SAML exists on the file system.
-// Returns a map[string]interface{} if successful, otherwise returns an AppError. Must be System Admin authenticated.
-func (c *Client) SamlCertificateStatus(filename string) (map[string]interface{}, *AppError) {
- if r, err := c.DoApiGet("/admin/remove_certificate", "", ""); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- c.fillInExtraProperties(r)
- return StringInterfaceFromJson(r.Body), nil
- }
-}
-
-// GetWebrtcToken if Successful returns a map with a valid token, stun server and turn server with credentials to use with
-// the Mattermost WebRTC service, otherwise returns an AppError. Must be authenticated user.
-func (c *Client) GetWebrtcToken() (map[string]string, *AppError) {
- if r, err := c.DoApiPost("/webrtc/token", ""); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return MapFromJson(r.Body), nil
- }
-}
-
-// GetFileInfosForPost returns a list of FileInfo objects for a given post id, if successful.
-// Otherwise, it returns an error.
-func (c *Client) GetFileInfosForPost(channelId string, postId string, etag string) ([]*FileInfo, *AppError) {
- c.clearExtraProperties()
-
- if r, err := c.DoApiGet(c.GetChannelRoute(channelId)+fmt.Sprintf("/posts/%v/get_file_infos", postId), "", etag); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- c.fillInExtraProperties(r)
- return FileInfosFromJson(r.Body), nil
- }
-}
-
-// Saves an emoji reaction for a post in the given channel. Returns the saved reaction if successful, otherwise returns an AppError.
-func (c *Client) SaveReaction(channelId string, reaction *Reaction) (*Reaction, *AppError) {
- if r, err := c.DoApiPost(c.GetChannelRoute(channelId)+fmt.Sprintf("/posts/%v/reactions/save", reaction.PostId), reaction.ToJson()); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- c.fillInExtraProperties(r)
- return ReactionFromJson(r.Body), nil
- }
-}
-
-// Removes an emoji reaction for a post in the given channel. Returns nil if successful, otherwise returns an AppError.
-func (c *Client) DeleteReaction(channelId string, reaction *Reaction) *AppError {
- if r, err := c.DoApiPost(c.GetChannelRoute(channelId)+fmt.Sprintf("/posts/%v/reactions/delete", reaction.PostId), reaction.ToJson()); err != nil {
- return err
- } else {
- defer closeBody(r)
- c.fillInExtraProperties(r)
- return nil
- }
-}
-
-// Lists all emoji reactions made for the given post in the given channel. Returns a list of Reactions if successful, otherwise returns an AppError.
-func (c *Client) ListReactions(channelId string, postId string) ([]*Reaction, *AppError) {
- if r, err := c.DoApiGet(c.GetChannelRoute(channelId)+fmt.Sprintf("/posts/%v/reactions", postId), "", ""); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- c.fillInExtraProperties(r)
- return ReactionsFromJson(r.Body), nil
- }
-}
-
-// Updates the user's roles in the channel by replacing them with the roles provided.
-func (c *Client) UpdateChannelRoles(channelId string, userId string, roles string) (map[string]string, *ResponseMetadata) {
- data := make(map[string]string)
- data["new_roles"] = roles
- data["user_id"] = userId
-
- if r, err := c.DoApiPost(c.GetChannelRoute(channelId)+"/update_member_roles", MapToJson(data)); err != nil {
- metadata := ResponseMetadata{Error: err}
- if r != nil {
- metadata.StatusCode = r.StatusCode
- }
- return nil, &metadata
- } else {
- defer closeBody(r)
- return MapFromJson(r.Body),
- &ResponseMetadata{
- StatusCode: r.StatusCode,
- RequestId: r.Header.Get(HEADER_REQUEST_ID),
- Etag: r.Header.Get(HEADER_ETAG_SERVER),
- }
- }
-}
-
-func (c *Client) PinPost(channelId string, postId string) (*Result, *AppError) {
- if r, err := c.DoApiPost(c.GetChannelRoute(channelId)+"/posts/"+postId+"/pin", ""); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), PostFromJson(r.Body)}, nil
- }
-}
-
-func (c *Client) UnpinPost(channelId string, postId string) (*Result, *AppError) {
- if r, err := c.DoApiPost(c.GetChannelRoute(channelId)+"/posts/"+postId+"/unpin", ""); err != nil {
- return nil, err
- } else {
- defer closeBody(r)
- return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), PostFromJson(r.Body)}, nil
- }
-}
diff --git a/model/client4.go b/model/client4.go
index 7ca2bdf4e..d245fe6c0 100644
--- a/model/client4.go
+++ b/model/client4.go
@@ -13,6 +13,33 @@ import (
"net/url"
"strconv"
"strings"
+ "time"
+)
+
+const (
+ HEADER_REQUEST_ID = "X-Request-ID"
+ HEADER_VERSION_ID = "X-Version-ID"
+ HEADER_CLUSTER_ID = "X-Cluster-ID"
+ HEADER_ETAG_SERVER = "ETag"
+ HEADER_ETAG_CLIENT = "If-None-Match"
+ HEADER_FORWARDED = "X-Forwarded-For"
+ HEADER_REAL_IP = "X-Real-IP"
+ HEADER_FORWARDED_PROTO = "X-Forwarded-Proto"
+ HEADER_TOKEN = "token"
+ HEADER_BEARER = "BEARER"
+ HEADER_AUTH = "Authorization"
+ HEADER_REQUESTED_WITH = "X-Requested-With"
+ HEADER_REQUESTED_WITH_XML = "XMLHttpRequest"
+ STATUS = "status"
+ STATUS_OK = "OK"
+ STATUS_FAIL = "FAIL"
+ STATUS_REMOVE = "REMOVE"
+
+ CLIENT_DIR = "client"
+
+ API_URL_SUFFIX_V1 = "/api/v1"
+ API_URL_SUFFIX_V4 = "/api/v4"
+ API_URL_SUFFIX = API_URL_SUFFIX_V4
)
type Response struct {
@@ -32,6 +59,24 @@ type Client4 struct {
AuthType string
}
+func closeBody(r *http.Response) {
+ if r.Body != nil {
+ ioutil.ReadAll(r.Body)
+ r.Body.Close()
+ }
+}
+
+// Must is a convenience function used for testing.
+func (c *Client4) Must(result interface{}, resp *Response) interface{} {
+ if resp.Error != nil {
+
+ time.Sleep(time.Second)
+ panic(resp.Error)
+ }
+
+ return result
+}
+
func NewAPIv4Client(url string) *Client4 {
return &Client4{url, url + API_URL_SUFFIX, &http.Client{}, "", ""}
}
@@ -64,6 +109,11 @@ func BuildResponse(r *http.Response) *Response {
}
}
+func (c *Client4) MockSession(sessionToken string) {
+ c.AuthToken = sessionToken
+ c.AuthType = HEADER_BEARER
+}
+
func (c *Client4) SetOAuthToken(token string) {
c.AuthToken = token
c.AuthType = HEADER_TOKEN
@@ -2966,6 +3016,28 @@ func (c *Client4) DeauthorizeOAuthApp(appId string) (bool, *Response) {
}
}
+// GetOAuthAccessToken is a test helper function for the OAuth access token endpoint.
+func (c *Client4) GetOAuthAccessToken(data url.Values) (*AccessResponse, *Response) {
+ rq, _ := http.NewRequest(http.MethodPost, c.Url+"/oauth/access_token", strings.NewReader(data.Encode()))
+ rq.Header.Set("Content-Type", "application/x-www-form-urlencoded")
+ rq.Close = true
+
+ if len(c.AuthToken) > 0 {
+ rq.Header.Set(HEADER_AUTH, c.AuthType+" "+c.AuthToken)
+ }
+
+ if rp, err := c.HttpClient.Do(rq); err != nil || rp == nil {
+ return nil, &Response{StatusCode: http.StatusForbidden, Error: NewAppError(c.Url+"/oauth/access_token", "model.client.connecting.app_error", nil, err.Error(), 403)}
+ } else {
+ defer closeBody(rp)
+ if rp.StatusCode >= 300 {
+ return nil, BuildErrorResponse(rp, AppErrorFromJson(rp.Body))
+ } else {
+ return AccessResponseFromJson(rp.Body), BuildResponse(rp)
+ }
+ }
+}
+
// Elasticsearch Section
// TestElasticsearch will attempt to connect to the configured Elasticsearch server and return OK if configured
diff --git a/model/config.go b/model/config.go
index 07cd9d977..a5a588a82 100644
--- a/model/config.go
+++ b/model/config.go
@@ -184,7 +184,6 @@ type ServiceSettings struct {
EnableOnlyAdminIntegrations *bool
EnablePostUsernameOverride bool
EnablePostIconOverride bool
- EnableAPIv3 *bool
EnableLinkPreviews *bool
EnableTesting bool
EnableDeveloper *bool
@@ -244,10 +243,6 @@ func (s *ServiceSettings) SetDefaults() {
s.ListenAddress = NewString(SERVICE_SETTINGS_DEFAULT_LISTEN_AND_ADDRESS)
}
- if s.EnableAPIv3 == nil {
- s.EnableAPIv3 = NewBool(true)
- }
-
if s.EnableLinkPreviews == nil {
s.EnableLinkPreviews = NewBool(false)
}
diff --git a/model/websocket_client.go b/model/websocket_client.go
index 788dbee20..4e6c1d8cc 100644
--- a/model/websocket_client.go
+++ b/model/websocket_client.go
@@ -39,15 +39,15 @@ func NewWebSocketClient(url, authToken string) (*WebSocketClient, *AppError) {
// NewWebSocketClientWithDialer constructs a new WebSocket client with convenience
// methods for talking to the server using a custom dialer.
func NewWebSocketClientWithDialer(dialer *websocket.Dialer, url, authToken string) (*WebSocketClient, *AppError) {
- conn, _, err := dialer.Dial(url+API_URL_SUFFIX_V3+"/users/websocket", nil)
+ conn, _, err := dialer.Dial(url+API_URL_SUFFIX+"/websocket", nil)
if err != nil {
return nil, NewAppError("NewWebSocketClient", "model.websocket_client.connect_fail.app_error", nil, err.Error(), http.StatusInternalServerError)
}
client := &WebSocketClient{
url,
- url + API_URL_SUFFIX_V3,
- url + API_URL_SUFFIX_V3 + "/users/websocket",
+ url + API_URL_SUFFIX,
+ url + API_URL_SUFFIX + "/websocket",
conn,
authToken,
1,
@@ -74,30 +74,7 @@ func NewWebSocketClient4(url, authToken string) (*WebSocketClient, *AppError) {
// NewWebSocketClient4WithDialer constructs a new WebSocket client with convenience
// methods for talking to the server using a custom dialer. Uses the v4 endpoint.
func NewWebSocketClient4WithDialer(dialer *websocket.Dialer, url, authToken string) (*WebSocketClient, *AppError) {
- conn, _, err := dialer.Dial(url+API_URL_SUFFIX+"/websocket", nil)
- if err != nil {
- return nil, NewAppError("NewWebSocketClient4", "model.websocket_client.connect_fail.app_error", nil, err.Error(), http.StatusInternalServerError)
- }
-
- client := &WebSocketClient{
- url,
- url + API_URL_SUFFIX,
- url + API_URL_SUFFIX + "/websocket",
- conn,
- authToken,
- 1,
- make(chan bool, 1),
- make(chan *WebSocketEvent, 100),
- make(chan *WebSocketResponse, 100),
- nil,
- nil,
- }
-
- client.configurePingHandling()
-
- client.SendMessage(WEBSOCKET_AUTHENTICATION_CHALLENGE, map[string]interface{}{"token": authToken})
-
- return client, nil
+ return NewWebSocketClientWithDialer(dialer, url, authToken)
}
func (wsc *WebSocketClient) Connect() *AppError {
diff --git a/utils/config.go b/utils/config.go
index 3827cf4ee..1b5fc7674 100644
--- a/utils/config.go
+++ b/utils/config.go
@@ -448,7 +448,6 @@ func GenerateClientConfig(c *model.Config, diagnosticId string, license *model.L
props["WebsocketURL"] = strings.TrimRight(*c.ServiceSettings.WebsocketURL, "/")
props["SiteName"] = c.TeamSettings.SiteName
props["EnableTeamCreation"] = strconv.FormatBool(*c.TeamSettings.EnableTeamCreation)
- props["EnableAPIv3"] = strconv.FormatBool(*c.ServiceSettings.EnableAPIv3)
props["EnableUserCreation"] = strconv.FormatBool(c.TeamSettings.EnableUserCreation)
props["EnableOpenServer"] = strconv.FormatBool(*c.TeamSettings.EnableOpenServer)
props["RestrictDirectMessage"] = *c.TeamSettings.RestrictDirectMessage
diff --git a/web/web_test.go b/web/web_test.go
index 4497f00cc..9b6230013 100644
--- a/web/web_test.go
+++ b/web/web_test.go
@@ -17,7 +17,7 @@ import (
"github.com/mattermost/mattermost-server/utils"
)
-var ApiClient *model.Client
+var ApiClient *model.Client4
var URL string
type persistentTestStore struct {
@@ -58,7 +58,7 @@ func Setup() *TestHelper {
NewWeb(a, a.Srv.Router)
URL = fmt.Sprintf("http://localhost:%v", a.Srv.ListenAddr.Port)
- ApiClient = model.NewClient(URL)
+ ApiClient = model.NewAPIv4Client(URL)
a.DoAdvancedPermissionsMigration()
@@ -66,7 +66,6 @@ func Setup() *TestHelper {
a.UpdateConfig(func(cfg *model.Config) {
*cfg.TeamSettings.EnableOpenServer = true
- *cfg.ServiceSettings.EnableAPIv3 = true
})
th := &TestHelper{
diff --git a/web/webhook_test.go b/web/webhook_test.go
index e625e55bb..48e0a2744 100644
--- a/web/webhook_test.go
+++ b/web/webhook_test.go
@@ -7,6 +7,7 @@ import (
"bytes"
"fmt"
"net/http"
+ "strings"
"testing"
"github.com/stretchr/testify/assert"
@@ -20,7 +21,7 @@ func TestIncomingWebhook(t *testing.T) {
defer th.TearDown()
if !th.App.Config().ServiceSettings.EnableIncomingWebhooks {
- _, err := ApiClient.PostToWebhook("123", "123")
+ _, err := http.Post(ApiClient.Url+"/hooks/123", "", strings.NewReader("123"))
assert.NotNil(t, err, "should have errored - webhooks turned off")
return
}
@@ -28,7 +29,7 @@ func TestIncomingWebhook(t *testing.T) {
hook, err := th.App.CreateIncomingWebhookForChannel(th.BasicUser.Id, th.BasicChannel, &model.IncomingWebhook{ChannelId: th.BasicChannel.Id})
require.Nil(t, err)
- url := "/hooks/" + hook.Id
+ url := ApiClient.Url + "/hooks/" + hook.Id
tooLongText := ""
for i := 0; i < 8200; i++ {
@@ -37,55 +38,68 @@ func TestIncomingWebhook(t *testing.T) {
t.Run("WebhookBasics", func(t *testing.T) {
payload := "payload={\"text\": \"test text\"}"
- _, err := ApiClient.DoPost(url, payload, "application/x-www-form-urlencoded")
- assert.Nil(t, err)
+ resp, err := http.Post(url, "application/x-www-form-urlencoded", strings.NewReader(payload))
+ require.Nil(t, err)
+ assert.True(t, resp.StatusCode == http.StatusOK)
payload = "payload={\"text\": \"\"}"
- _, err = ApiClient.DoPost(url, payload, "application/x-www-form-urlencoded")
- assert.NotNil(t, err, "should have errored - no text to post")
+ resp, err = http.Post(url, "application/x-www-form-urlencoded", strings.NewReader(payload))
+ require.Nil(t, err)
+ assert.True(t, resp.StatusCode != http.StatusOK, "should have errored - no text to post")
payload = "payload={\"text\": \"test text\", \"channel\": \"junk\"}"
- _, err = ApiClient.DoPost(url, payload, "application/x-www-form-urlencoded")
- assert.NotNil(t, err, "should have errored - bad channel")
+ resp, err = http.Post(url, "application/x-www-form-urlencoded", strings.NewReader(payload))
+ require.Nil(t, err)
+ assert.True(t, resp.StatusCode != http.StatusOK, "should have errored - bad channel")
payload = "payload={\"text\": \"test text\"}"
- _, err = ApiClient.DoPost("/hooks/abc123", payload, "application/x-www-form-urlencoded")
- assert.NotNil(t, err, "should have errored - bad hook")
+ resp, err = http.Post(ApiClient.Url+"/hooks/abc123", "application/x-www-form-urlencoded", strings.NewReader(payload))
+ require.Nil(t, err)
+ assert.True(t, resp.StatusCode != http.StatusOK, "should have errored - bad hook")
- _, err = ApiClient.DoPost(url, "{\"text\":\"this is a test\"}", "application/json")
- assert.Nil(t, err)
+ resp, err = http.Post(url, "application/json", strings.NewReader("{\"text\":\"this is a test\"}"))
+ require.Nil(t, err)
+ assert.True(t, resp.StatusCode == http.StatusOK)
text := `this is a \"test\"
that contains a newline and a tab`
- _, err = ApiClient.DoPost(url, "{\"text\":\""+text+"\"}", "application/json")
- assert.Nil(t, err)
+ resp, err = http.Post(url, "application/json", strings.NewReader("{\"text\":\""+text+"\"}"))
+ require.Nil(t, err)
+ assert.True(t, resp.StatusCode == http.StatusOK)
- _, err = ApiClient.DoPost(url, fmt.Sprintf("{\"text\":\"this is a test\", \"channel\":\"%s\"}", th.BasicChannel.Name), "application/json")
- assert.Nil(t, err)
+ resp, err = http.Post(url, "application/json", strings.NewReader(fmt.Sprintf("{\"text\":\"this is a test\", \"channel\":\"%s\"}", th.BasicChannel.Name)))
+ require.Nil(t, err)
+ assert.True(t, resp.StatusCode == http.StatusOK)
- _, err = ApiClient.DoPost(url, fmt.Sprintf("{\"text\":\"this is a test\", \"channel\":\"#%s\"}", th.BasicChannel.Name), "application/json")
- assert.Nil(t, err)
+ resp, err = http.Post(url, "application/json", strings.NewReader(fmt.Sprintf("{\"text\":\"this is a test\", \"channel\":\"#%s\"}", th.BasicChannel.Name)))
+ require.Nil(t, err)
+ assert.True(t, resp.StatusCode == http.StatusOK)
- _, err = ApiClient.DoPost(url, fmt.Sprintf("{\"text\":\"this is a test\", \"channel\":\"@%s\"}", th.BasicUser.Username), "application/json")
- assert.Nil(t, err)
+ resp, err = http.Post(url, "application/json", strings.NewReader(fmt.Sprintf("{\"text\":\"this is a test\", \"channel\":\"@%s\"}", th.BasicUser.Username)))
+ require.Nil(t, err)
+ assert.True(t, resp.StatusCode == http.StatusOK)
- _, err = ApiClient.DoPost(url, "payload={\"text\":\"this is a test\"}", "application/x-www-form-urlencoded")
- assert.Nil(t, err)
+ resp, err = http.Post(url, "application/x-www-form-urlencoded", strings.NewReader("payload={\"text\":\"this is a test\"}"))
+ require.Nil(t, err)
+ assert.True(t, resp.StatusCode == http.StatusOK)
- _, err = ApiClient.DoPost(url, "payload={\"text\":\""+text+"\"}", "application/x-www-form-urlencoded")
+ resp, err = http.Post(url, "application/x-www-form-urlencoded", strings.NewReader("payload={\"text\":\""+text+"\"}"))
assert.Nil(t, err)
+ assert.True(t, resp.StatusCode == http.StatusOK)
- _, err = ApiClient.DoPost(url, "{\"text\":\""+tooLongText+"\"}", "application/json")
- assert.Nil(t, err)
+ resp, err = http.Post(url, "application/json", strings.NewReader("{\"text\":\""+tooLongText+"\"}"))
+ require.Nil(t, err)
+ assert.True(t, resp.StatusCode == http.StatusOK)
payloadMultiPart := "------WebKitFormBoundary7MA4YWxkTrZu0gW\r\nContent-Disposition: form-data; name=\"username\"\r\n\r\nwebhook-bot\r\n------WebKitFormBoundary7MA4YWxkTrZu0gW\r\nContent-Disposition: form-data; name=\"text\"\r\n\r\nthis is a test :tada:\r\n------WebKitFormBoundary7MA4YWxkTrZu0gW--"
- _, err = ApiClient.DoPost("/hooks/"+hook.Id, payloadMultiPart, "multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW")
- assert.Nil(t, err)
+ resp, err = http.Post(ApiClient.Url+"/hooks/"+hook.Id, "multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW", strings.NewReader(payloadMultiPart))
+ require.Nil(t, err)
+ assert.True(t, resp.StatusCode == http.StatusOK)
})
t.Run("WebhookExperimentReadOnly", func(t *testing.T) {
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.TeamSettings.ExperimentalTownSquareIsReadOnly = false })
- _, err := ApiClient.DoPost(url, fmt.Sprintf("{\"text\":\"this is a test\", \"channel\":\"%s\"}", model.DEFAULT_CHANNEL), "application/json")
+ _, err := http.Post(url, "application/json", strings.NewReader(fmt.Sprintf("{\"text\":\"this is a test\", \"channel\":\"%s\"}", model.DEFAULT_CHANNEL)))
assert.Nil(t, err, "Not read only")
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.TeamSettings.ExperimentalTownSquareIsReadOnly = true })
@@ -126,8 +140,9 @@ func TestIncomingWebhook(t *testing.T) {
]
}`
- _, err := ApiClient.DoPost(url, attachmentPayload, "application/json")
- assert.Nil(t, err)
+ resp, err := http.Post(url, "application/json", strings.NewReader(attachmentPayload))
+ require.Nil(t, err)
+ assert.True(t, resp.StatusCode == http.StatusOK)
attachmentPayload = `{
"text": "this is a test",
@@ -162,14 +177,16 @@ func TestIncomingWebhook(t *testing.T) {
]
}`
- _, err = ApiClient.DoPost(url, attachmentPayload, "application/json")
- assert.Nil(t, err)
+ resp, err = http.Post(url, "application/json", strings.NewReader(attachmentPayload))
+ require.Nil(t, err)
+ assert.True(t, resp.StatusCode == http.StatusOK)
})
t.Run("DisableWebhooks", func(t *testing.T) {
th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableIncomingWebhooks = false })
- _, err := ApiClient.DoPost(url, "{\"text\":\"this is a test\"}", "application/json")
- assert.NotNil(t, err)
+ resp, err := http.Post(url, "application/json", strings.NewReader("{\"text\":\"this is a test\"}"))
+ require.Nil(t, err)
+ assert.True(t, resp.StatusCode == http.StatusNotImplemented)
})
}