Merge branch 'master' into mark-as-unread
Этот коммит содержится в:
7
Makefile
7
Makefile
@@ -230,7 +230,10 @@ check-prereqs: ## Checks prerequisite software status.
|
||||
./scripts/prereq-check.sh
|
||||
|
||||
# TODO: remove govet and gofmt checks once golangci-lint is being enforced.
|
||||
check-style: govet gofmt check-licenses ## Runs govet and gofmt against all packages.
|
||||
check-style: govet gofmt check-licenses check-plugin-golint ## Runs govet and gofmt against all packages and also ensures plugin package golint compliant
|
||||
|
||||
check-plugin-golint: # Checks if golint returns any uncompliant code for any file that starts with plugin/helpers
|
||||
@! golint ./plugin/ | grep plugin/helpers
|
||||
|
||||
test-te-race: ## Checks for race conditions in the team edition.
|
||||
@echo Testing TE race conditions
|
||||
@@ -398,7 +401,7 @@ stop-client: ## Stops the webapp.
|
||||
|
||||
cd $(BUILD_WEBAPP_DIR) && $(MAKE) stop
|
||||
|
||||
stop: stop-server stop-client ## Stops server and client.
|
||||
stop: stop-server stop-client stop-docker ## Stops server, client and the docker compose.
|
||||
|
||||
restart: restart-server restart-client ## Restarts the server and webapp.
|
||||
|
||||
|
||||
@@ -574,7 +574,9 @@ func CheckEtag(t *testing.T, data interface{}, resp *model.Response) {
|
||||
func CheckNoError(t *testing.T, resp *model.Response) {
|
||||
t.Helper()
|
||||
|
||||
require.Nil(t, resp.Error)
|
||||
if resp.Error != nil {
|
||||
require.FailNow(t, "Expected no error, got %q", resp.Error.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func checkHTTPStatus(t *testing.T, resp *model.Response, expectedStatus int, expectError bool) {
|
||||
@@ -637,8 +639,8 @@ func CheckInternalErrorStatus(t *testing.T, resp *model.Response) {
|
||||
func CheckErrorMessage(t *testing.T, resp *model.Response, errorId string) {
|
||||
t.Helper()
|
||||
|
||||
require.NotNil(t, resp.Error)
|
||||
require.Equal(t, resp.Error.Id, errorId, "incorrect error message")
|
||||
require.NotNilf(t, resp.Error, "should have errored with message: %s", errorId)
|
||||
require.Equalf(t, resp.Error.Id, errorId, "incorrect error message, actual: %s, expected: %s", resp.Error.Id, errorId)
|
||||
}
|
||||
|
||||
func CheckStartsWith(t *testing.T, value, prefix, message string) {
|
||||
|
||||
@@ -27,6 +27,7 @@ func (api *API) InitChannel() {
|
||||
api.BaseRoutes.ChannelsForTeam.Handle("/deleted", api.ApiSessionRequired(getDeletedChannelsForTeam)).Methods("GET")
|
||||
api.BaseRoutes.ChannelsForTeam.Handle("/ids", api.ApiSessionRequired(getPublicChannelsByIdsForTeam)).Methods("POST")
|
||||
api.BaseRoutes.ChannelsForTeam.Handle("/search", api.ApiSessionRequired(searchChannelsForTeam)).Methods("POST")
|
||||
api.BaseRoutes.ChannelsForTeam.Handle("/search_archived", api.ApiSessionRequired(searchArchivedChannelsForTeam)).Methods("POST")
|
||||
api.BaseRoutes.ChannelsForTeam.Handle("/autocomplete", api.ApiSessionRequired(autocompleteChannelsForTeam)).Methods("GET")
|
||||
api.BaseRoutes.ChannelsForTeam.Handle("/search_autocomplete", api.ApiSessionRequired(autocompleteChannelsForTeamForSearch)).Methods("GET")
|
||||
api.BaseRoutes.User.Handle("/teams/{team_id:[A-Za-z0-9]+}/channels", api.ApiSessionRequired(getChannelsForTeamForUser)).Methods("GET")
|
||||
@@ -681,12 +682,7 @@ func getDeletedChannelsForTeam(c *Context, w http.ResponseWriter, r *http.Reques
|
||||
return
|
||||
}
|
||||
|
||||
if !c.App.SessionHasPermissionToTeam(c.App.Session, c.Params.TeamId, model.PERMISSION_MANAGE_TEAM) {
|
||||
c.SetPermissionError(model.PERMISSION_MANAGE_TEAM)
|
||||
return
|
||||
}
|
||||
|
||||
channels, err := c.App.GetDeletedChannels(c.Params.TeamId, c.Params.Page*c.Params.PerPage, c.Params.PerPage)
|
||||
channels, err := c.App.GetDeletedChannels(c.Params.TeamId, c.Params.Page*c.Params.PerPage, c.Params.PerPage, c.App.Session.UserId)
|
||||
if err != nil {
|
||||
c.Err = err
|
||||
return
|
||||
@@ -860,6 +856,42 @@ func searchChannelsForTeam(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
w.Write([]byte(channels.ToJson()))
|
||||
}
|
||||
|
||||
func searchArchivedChannelsForTeam(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
c.RequireTeamId()
|
||||
if c.Err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
props := model.ChannelSearchFromJson(r.Body)
|
||||
if props == nil {
|
||||
c.SetInvalidParam("channel_search")
|
||||
return
|
||||
}
|
||||
|
||||
var channels *model.ChannelList
|
||||
var err *model.AppError
|
||||
if c.App.SessionHasPermissionToTeam(c.App.Session, c.Params.TeamId, model.PERMISSION_LIST_TEAM_CHANNELS) {
|
||||
channels, err = c.App.SearchArchivedChannels(c.Params.TeamId, props.Term, c.App.Session.UserId)
|
||||
} else {
|
||||
// If the user is not a team member, return a 404
|
||||
if _, err = c.App.GetTeamMember(c.Params.TeamId, c.App.Session.UserId); err != nil {
|
||||
c.Err = err
|
||||
return
|
||||
}
|
||||
|
||||
channels, err = c.App.SearchArchivedChannels(c.Params.TeamId, props.Term, c.App.Session.UserId)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
c.Err = err
|
||||
return
|
||||
}
|
||||
|
||||
// Don't fill in channels props, since unused by client and potentially expensive.
|
||||
|
||||
w.Write([]byte(channels.ToJson()))
|
||||
}
|
||||
|
||||
func searchAllChannels(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
props := model.ChannelSearchFromJson(r.Body)
|
||||
if props == nil {
|
||||
|
||||
@@ -678,9 +678,6 @@ func TestGetDeletedChannelsForTeam(t *testing.T) {
|
||||
Client := th.Client
|
||||
team := th.BasicTeam
|
||||
|
||||
_, resp := Client.GetDeletedChannelsForTeam(team.Id, 0, 100, "")
|
||||
CheckForbiddenStatus(t, resp)
|
||||
|
||||
th.LoginTeamAdmin()
|
||||
|
||||
channels, resp := Client.GetDeletedChannelsForTeam(team.Id, 0, 100, "")
|
||||
@@ -706,6 +703,31 @@ func TestGetDeletedChannelsForTeam(t *testing.T) {
|
||||
t.Fatal("should be 2 deleted channels")
|
||||
}
|
||||
|
||||
th.LoginBasic()
|
||||
|
||||
privateChannel1 := th.CreatePrivateChannel()
|
||||
Client.DeleteChannel(privateChannel1.Id)
|
||||
|
||||
channels, resp = Client.GetDeletedChannelsForTeam(team.Id, 0, 100, "")
|
||||
CheckNoError(t, resp)
|
||||
if len(channels) != numInitialChannelsForTeam+3 {
|
||||
t.Fatal("should be 3 deleted channels")
|
||||
}
|
||||
|
||||
// Login as different user and create private channel
|
||||
th.LoginBasic2()
|
||||
privateChannel2 := th.CreatePrivateChannel()
|
||||
Client.DeleteChannel(privateChannel2.Id)
|
||||
|
||||
// Log back in as first user
|
||||
th.LoginBasic()
|
||||
|
||||
channels, resp = Client.GetDeletedChannelsForTeam(team.Id, 0, 100, "")
|
||||
CheckNoError(t, resp)
|
||||
if len(channels) != numInitialChannelsForTeam+3 {
|
||||
t.Fatal("should still be 3 deleted channels", len(channels), numInitialChannelsForTeam+3)
|
||||
}
|
||||
|
||||
channels, resp = Client.GetDeletedChannelsForTeam(team.Id, 0, 1, "")
|
||||
CheckNoError(t, resp)
|
||||
if len(channels) != 1 {
|
||||
@@ -1060,6 +1082,100 @@ func TestSearchChannels(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestSearchArchivedChannels(t *testing.T) {
|
||||
th := Setup().InitBasic()
|
||||
defer th.TearDown()
|
||||
Client := th.Client
|
||||
|
||||
search := &model.ChannelSearch{Term: th.BasicChannel.Name}
|
||||
|
||||
Client.DeleteChannel(th.BasicChannel.Id)
|
||||
|
||||
channels, resp := Client.SearchArchivedChannels(th.BasicTeam.Id, search)
|
||||
CheckNoError(t, resp)
|
||||
|
||||
found := false
|
||||
for _, c := range channels {
|
||||
if c.Type != model.CHANNEL_OPEN {
|
||||
t.Fatal("should only return public channels")
|
||||
}
|
||||
|
||||
if c.Id == th.BasicChannel.Id {
|
||||
found = true
|
||||
}
|
||||
}
|
||||
|
||||
if !found {
|
||||
t.Fatal("didn't find channel")
|
||||
}
|
||||
|
||||
search.Term = th.BasicPrivateChannel.Name
|
||||
Client.DeleteChannel(th.BasicPrivateChannel.Id)
|
||||
|
||||
channels, resp = Client.SearchArchivedChannels(th.BasicTeam.Id, search)
|
||||
CheckNoError(t, resp)
|
||||
|
||||
found = false
|
||||
for _, c := range channels {
|
||||
if c.Id == th.BasicPrivateChannel.Id {
|
||||
found = true
|
||||
}
|
||||
}
|
||||
|
||||
if !found {
|
||||
t.Fatal("couldn't find private channel")
|
||||
}
|
||||
|
||||
search.Term = ""
|
||||
_, resp = Client.SearchArchivedChannels(th.BasicTeam.Id, search)
|
||||
CheckNoError(t, resp)
|
||||
|
||||
search.Term = th.BasicDeletedChannel.Name
|
||||
_, resp = Client.SearchArchivedChannels(model.NewId(), search)
|
||||
CheckNotFoundStatus(t, resp)
|
||||
|
||||
_, resp = Client.SearchArchivedChannels("junk", search)
|
||||
CheckBadRequestStatus(t, resp)
|
||||
|
||||
_, resp = th.SystemAdminClient.SearchArchivedChannels(th.BasicTeam.Id, search)
|
||||
CheckNoError(t, resp)
|
||||
|
||||
// Check the appropriate permissions are enforced.
|
||||
defaultRolePermissions := th.SaveDefaultRolePermissions()
|
||||
defer func() {
|
||||
th.RestoreDefaultRolePermissions(defaultRolePermissions)
|
||||
}()
|
||||
|
||||
// Remove list channels permission from the user
|
||||
th.RemovePermissionFromRole(model.PERMISSION_LIST_TEAM_CHANNELS.Id, model.TEAM_USER_ROLE_ID)
|
||||
|
||||
t.Run("Search for a BasicDeletedChannel, which the user is a member of", func(t *testing.T) {
|
||||
search.Term = th.BasicDeletedChannel.Name
|
||||
channelList, resp := Client.SearchArchivedChannels(th.BasicTeam.Id, search)
|
||||
CheckNoError(t, resp)
|
||||
|
||||
channelNames := []string{}
|
||||
for _, c := range channelList {
|
||||
channelNames = append(channelNames, c.Name)
|
||||
}
|
||||
require.Contains(t, channelNames, th.BasicDeletedChannel.Name)
|
||||
})
|
||||
|
||||
t.Run("Remove the user from BasicDeletedChannel and search again, should still return", func(t *testing.T) {
|
||||
th.App.RemoveUserFromChannel(th.BasicUser.Id, th.BasicUser.Id, th.BasicDeletedChannel)
|
||||
|
||||
search.Term = th.BasicDeletedChannel.Name
|
||||
channelList, resp := Client.SearchArchivedChannels(th.BasicTeam.Id, search)
|
||||
CheckNoError(t, resp)
|
||||
|
||||
channelNames := []string{}
|
||||
for _, c := range channelList {
|
||||
channelNames = append(channelNames, c.Name)
|
||||
}
|
||||
require.Contains(t, channelNames, th.BasicDeletedChannel.Name)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSearchAllChannels(t *testing.T) {
|
||||
th := Setup().InitBasic()
|
||||
defer th.TearDown()
|
||||
|
||||
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
@@ -86,7 +86,7 @@ func createUser(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
user.SanitizeInput()
|
||||
user.SanitizeInput(c.IsSystemAdmin())
|
||||
|
||||
tokenId := r.URL.Query().Get("t")
|
||||
inviteId := r.URL.Query().Get("iid")
|
||||
|
||||
@@ -110,10 +110,15 @@ func TestCreateUserInputFilter(t *testing.T) {
|
||||
_, resp := th.SystemAdminClient.CreateUser(user)
|
||||
CheckBadRequestStatus(t, resp)
|
||||
})
|
||||
|
||||
t.Run("AuthServiceFilter", func(t *testing.T) {
|
||||
user := &model.User{Email: "foobar+testdomainrestriction@mattermost.org", Password: "Password1", Username: GenerateTestUsername(), AuthService: "ldap"}
|
||||
t.Run("ValidAuthServiceFilter", func(t *testing.T) {
|
||||
user := &model.User{Email: "foobar+testdomainrestriction@mattermost.org", Username: GenerateTestUsername(), AuthService: "ldap", AuthData: model.NewString("999099")}
|
||||
_, resp := th.SystemAdminClient.CreateUser(user)
|
||||
CheckNoError(t, resp)
|
||||
})
|
||||
|
||||
t.Run("InvalidAuthServiceFilter", func(t *testing.T) {
|
||||
user := &model.User{Email: "foobar+testdomainrestriction@mattermost.org", Password: "Password1", Username: GenerateTestUsername(), AuthService: "ldap"}
|
||||
_, resp := th.Client.CreateUser(user)
|
||||
CheckBadRequestStatus(t, resp)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1260,8 +1260,8 @@ func (a *App) GetAllChannelsCount(opts model.ChannelSearchOpts) (int64, *model.A
|
||||
return a.Srv.Store.Channel().GetAllChannelsCount(storeOpts)
|
||||
}
|
||||
|
||||
func (a *App) GetDeletedChannels(teamId string, offset int, limit int) (*model.ChannelList, *model.AppError) {
|
||||
return a.Srv.Store.Channel().GetDeleted(teamId, offset, limit)
|
||||
func (a *App) GetDeletedChannels(teamId string, offset int, limit int, userId string) (*model.ChannelList, *model.AppError) {
|
||||
return a.Srv.Store.Channel().GetDeleted(teamId, offset, limit, userId)
|
||||
}
|
||||
|
||||
func (a *App) GetChannelsUserNotIn(teamId string, userId string, offset int, limit int) (*model.ChannelList, *model.AppError) {
|
||||
@@ -1894,6 +1894,12 @@ func (a *App) SearchChannels(teamId string, term string) (*model.ChannelList, *m
|
||||
return a.Srv.Store.Channel().SearchInTeam(teamId, term, includeDeleted)
|
||||
}
|
||||
|
||||
func (a *App) SearchArchivedChannels(teamId string, term string, userId string) (*model.ChannelList, *model.AppError) {
|
||||
term = strings.TrimSpace(term)
|
||||
|
||||
return a.Srv.Store.Channel().SearchArchivedInTeam(teamId, term, userId)
|
||||
}
|
||||
|
||||
func (a *App) SearchChannelsForUser(userId, teamId, term string) (*model.ChannelList, *model.AppError) {
|
||||
includeDeleted := *a.Config().TeamSettings.ExperimentalViewArchivedChannels
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/mattermost/mattermost-server/model"
|
||||
)
|
||||
@@ -42,6 +43,15 @@ func TestInviteProvider(t *testing.T) {
|
||||
userAndInvalidPrivate := "@" + basicUser3.Username + " ~" + privateChannel2.Name
|
||||
deactivatedUserPublicChannel := "@" + deactivatedUser.Username + " ~" + channel.Name
|
||||
|
||||
groupChannel := th.createChannel(th.BasicTeam, model.CHANNEL_PRIVATE)
|
||||
var err *model.AppError
|
||||
_, err = th.App.AddChannelMember(th.BasicUser.Id, groupChannel, "", "")
|
||||
require.Nil(t, err)
|
||||
groupChannel.GroupConstrained = model.NewBool(true)
|
||||
groupChannel, _ = th.App.UpdateChannel(groupChannel)
|
||||
|
||||
groupChannelNonUser := "@" + th.BasicUser2.Username + " ~" + groupChannel.Name
|
||||
|
||||
tests := []struct {
|
||||
desc string
|
||||
expected string
|
||||
@@ -97,6 +107,11 @@ func TestInviteProvider(t *testing.T) {
|
||||
expected: "api.command_invite.user_not_in_team.app_error",
|
||||
msg: basicUser4.Username,
|
||||
},
|
||||
{
|
||||
desc: "try to add a user not part of the group to a group channel",
|
||||
expected: "api.command_invite.group_constrained_user_denied",
|
||||
msg: groupChannelNonUser,
|
||||
},
|
||||
{
|
||||
desc: "try to add a user to a private channel with no permission",
|
||||
expected: "api.command_invite.private_channel.app_error",
|
||||
@@ -116,3 +131,59 @@ func TestInviteProvider(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestInviteGroup(t *testing.T) {
|
||||
th := Setup(t).InitBasic()
|
||||
defer th.TearDown()
|
||||
|
||||
th.BasicTeam.GroupConstrained = model.NewBool(true)
|
||||
var err *model.AppError
|
||||
_, _ = th.App.AddTeamMember(th.BasicTeam.Id, th.BasicUser.Id)
|
||||
_, err = th.App.AddTeamMember(th.BasicTeam.Id, th.BasicUser2.Id)
|
||||
require.Nil(t, err)
|
||||
th.BasicTeam, _ = th.App.UpdateTeam(th.BasicTeam)
|
||||
|
||||
privateChannel := th.createChannel(th.BasicTeam, model.CHANNEL_PRIVATE)
|
||||
|
||||
groupChannelUser1 := "@" + th.BasicUser.Username + " ~" + privateChannel.Name
|
||||
groupChannelUser2 := "@" + th.BasicUser2.Username + " ~" + privateChannel.Name
|
||||
basicUser3 := th.CreateUser()
|
||||
groupChannelUser3 := "@" + basicUser3.Username + " ~" + privateChannel.Name
|
||||
|
||||
InviteP := InviteProvider{}
|
||||
args := &model.CommandArgs{
|
||||
T: func(s string, args ...interface{}) string { return s },
|
||||
ChannelId: th.BasicChannel.Id,
|
||||
TeamId: th.BasicTeam.Id,
|
||||
Session: model.Session{UserId: th.BasicUser.Id, TeamMembers: []*model.TeamMember{{TeamId: th.BasicTeam.Id, Roles: model.TEAM_USER_ROLE_ID}}},
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
desc string
|
||||
expected string
|
||||
msg string
|
||||
}{
|
||||
{
|
||||
desc: "try to add an existing user part of the group to a group channel",
|
||||
expected: "api.command_invite.user_already_in_channel.app_error",
|
||||
msg: groupChannelUser1,
|
||||
},
|
||||
{
|
||||
desc: "try to add a user part of the group to a group channel",
|
||||
expected: "api.command_invite.success",
|
||||
msg: groupChannelUser2,
|
||||
},
|
||||
{
|
||||
desc: "try to add a user NOT part of the group to a group channel",
|
||||
expected: "api.command_invite.user_not_in_team.app_error",
|
||||
msg: groupChannelUser3,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
actual := InviteP.DoCommand(th.App, args, test.msg).Text
|
||||
assert.Equal(t, test.expected, actual)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,7 +83,7 @@ func (a *App) LimitedClientConfig() map[string]string {
|
||||
return a.Srv.limitedClientConfig
|
||||
}
|
||||
|
||||
// Registers a function with a given to be called when the config is reloaded and may have changed. The function
|
||||
// Registers a function with a given listener to be called when the config is reloaded and may have changed. The function
|
||||
// will be called with two arguments: the old config and the new config. AddConfigListener returns a unique ID
|
||||
// for the listener that can later be used to remove it.
|
||||
func (s *Server) AddConfigListener(listener func(*model.Config, *model.Config)) string {
|
||||
@@ -104,7 +104,7 @@ func (a *App) RemoveConfigListener(id string) {
|
||||
}
|
||||
|
||||
// ensurePostActionCookieSecret ensures that the key for encrypting PostActionCookie exists
|
||||
// and future calls to PostAcrionCookieSecret will always return a valid key, same on all
|
||||
// and future calls to PostActionCookieSecret will always return a valid key, same on all
|
||||
// servers in the cluster
|
||||
func (a *App) ensurePostActionCookieSecret() error {
|
||||
if a.Srv.postActionCookieSecret != nil {
|
||||
|
||||
@@ -7,7 +7,6 @@ import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/mail"
|
||||
"net/url"
|
||||
"path"
|
||||
"strings"
|
||||
@@ -525,8 +524,6 @@ func (a *App) SendMail(to, subject, htmlBody string) *model.AppError {
|
||||
func (a *App) SendMailWithEmbeddedFiles(to, subject, htmlBody string, embeddedFiles map[string]io.Reader) *model.AppError {
|
||||
license := a.License()
|
||||
config := a.Config()
|
||||
fromMail := mail.Address{Name: *config.EmailSettings.FeedbackName, Address: *config.EmailSettings.FeedbackEmail}
|
||||
replyTo := mail.Address{Name: *config.EmailSettings.FeedbackName, Address: *config.EmailSettings.ReplyToAddress}
|
||||
|
||||
return mailservice.SendMailUsingConfigAdvanced(to, to, fromMail, replyTo, subject, htmlBody, nil, embeddedFiles, nil, config, license != nil && *license.Features.Compliance)
|
||||
return mailservice.SendMailWithEmbeddedFilesUsingConfig(to, subject, htmlBody, embeddedFiles, config, license != nil && *license.Features.Compliance)
|
||||
}
|
||||
|
||||
@@ -100,7 +100,7 @@ func (a *App) sendNotificationEmail(notification *postNotification, user *model.
|
||||
|
||||
a.Srv.Go(func() {
|
||||
if err := a.SendNotificationMail(user.Email, html.UnescapeString(subjectText), bodyText); err != nil {
|
||||
mlog.Error("Error while sending the email", mlog.String("email", user.Email), mlog.Err(err))
|
||||
mlog.Error("Error while sending the email", mlog.String("user_email", user.Email), mlog.Err(err))
|
||||
}
|
||||
})
|
||||
|
||||
@@ -285,7 +285,7 @@ func getFormattedPostTime(user *model.User, post *model.Post, useMilitaryTime bo
|
||||
func (a *App) generateHyperlinkForChannels(postMessage, teamName, teamURL string) string {
|
||||
team, err := a.GetTeamByName(teamName)
|
||||
if err != nil {
|
||||
mlog.Error("Encountered error while looking up team by name", mlog.String("Team Name", teamName), mlog.Err(err))
|
||||
mlog.Error("Encountered error while looking up team by name", mlog.String("team_name", teamName), mlog.Err(err))
|
||||
return postMessage
|
||||
}
|
||||
|
||||
|
||||
@@ -186,7 +186,7 @@ func NewServer(options ...Option) (*Server, error) {
|
||||
return nil, errors.Wrapf(err, "unable to load Mattermost translation files")
|
||||
}
|
||||
|
||||
err := s.RunOldAppInitalization()
|
||||
err := s.RunOldAppInitialization()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -18,11 +18,11 @@ import (
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// This is a bridge between the old and new initalization for the context refactor.
|
||||
// It calls app layer initalization code that then turns around and acts on the server.
|
||||
// Don't add anything new here, new initilization should be done in the server and
|
||||
// This is a bridge between the old and new initialization for the context refactor.
|
||||
// It calls app layer initialization code that then turns around and acts on the server.
|
||||
// Don't add anything new here, new initialization should be done in the server and
|
||||
// performed in the NewServer function.
|
||||
func (s *Server) RunOldAppInitalization() error {
|
||||
func (s *Server) RunOldAppInitialization() error {
|
||||
s.FakeApp().CreatePushNotificationsHub()
|
||||
s.FakeApp().StartPushNotificationsHubWorkers()
|
||||
|
||||
|
||||
@@ -8,7 +8,6 @@ import (
|
||||
"encoding/json"
|
||||
"image"
|
||||
"image/color"
|
||||
"math/rand"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
@@ -74,8 +73,7 @@ func TestCreateOAuthUser(t *testing.T) {
|
||||
th := Setup(t).InitBasic()
|
||||
defer th.TearDown()
|
||||
|
||||
r := rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||
glUser := oauthgitlab.GitLabUser{Id: int64(r.Intn(1000)) + 1, Username: "o" + model.NewId(), Email: model.NewId() + "@simulator.amazonses.com", Name: "Joram Wilander"}
|
||||
glUser := oauthgitlab.GitLabUser{Id: 42, Username: "o" + model.NewId(), Email: model.NewId() + "@simulator.amazonses.com", Name: "Joram Wilander"}
|
||||
|
||||
json := glUser.ToJson()
|
||||
user, err := th.App.CreateOAuthUser(model.USER_AUTH_SERVICE_GITLAB, strings.NewReader(json), th.BasicTeam.Id)
|
||||
@@ -253,8 +251,8 @@ func TestUpdateOAuthUserAttrs(t *testing.T) {
|
||||
|
||||
var user, user2 *model.User
|
||||
var gitlabUserObj oauthgitlab.GitLabUser
|
||||
user, gitlabUserObj = createGitlabUser(t, th.App, username, email)
|
||||
user2, _ = createGitlabUser(t, th.App, username2, email2)
|
||||
user, gitlabUserObj = createGitlabUser(t, th.App, 1, username, email)
|
||||
user2, _ = createGitlabUser(t, th.App, 2, username2, email2)
|
||||
|
||||
t.Run("UpdateUsername", func(t *testing.T) {
|
||||
t.Run("NoExistingUserWithSameUsername", func(t *testing.T) {
|
||||
@@ -443,9 +441,8 @@ func getGitlabUserPayload(gitlabUser oauthgitlab.GitLabUser, t *testing.T) []byt
|
||||
return payload
|
||||
}
|
||||
|
||||
func createGitlabUser(t *testing.T, a *App, username string, email string) (*model.User, oauthgitlab.GitLabUser) {
|
||||
r := rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||
gitlabUserObj := oauthgitlab.GitLabUser{Id: int64(r.Intn(1000)) + 1, Username: username, Login: "user1", Email: email, Name: "Test User"}
|
||||
func createGitlabUser(t *testing.T, a *App, id int64, username string, email string) (*model.User, oauthgitlab.GitLabUser) {
|
||||
gitlabUserObj := oauthgitlab.GitLabUser{Id: id, Username: username, Login: "user1", Email: email, Name: "Test User"}
|
||||
gitlabUser := getGitlabUserPayload(gitlabUserObj, t)
|
||||
|
||||
var user *model.User
|
||||
|
||||
@@ -21,7 +21,7 @@ services:
|
||||
POSTGRES_PASSWORD: mostest
|
||||
POSTGRES_DB: mattermost_test
|
||||
minio:
|
||||
image: "minio/minio:RELEASE.2019-08-14T20-37-41Z"
|
||||
image: "minio/minio:RELEASE.2019-10-11T00-38-09Z"
|
||||
command: "server /data"
|
||||
networks:
|
||||
- mm-test
|
||||
|
||||
@@ -72,16 +72,16 @@ func runServer(configStore config.Store, disableConfigWatch bool, usedPlatform b
|
||||
mlog.Error("The platform binary has been deprecated, please switch to using the mattermost binary.")
|
||||
}
|
||||
|
||||
api := api4.Init(server, server.AppOptions, server.Router)
|
||||
wsapi.Init(server.FakeApp(), server.WebSocketRouter)
|
||||
web.New(server, server.AppOptions, server.Router)
|
||||
|
||||
serverErr := server.Start()
|
||||
if serverErr != nil {
|
||||
mlog.Critical(serverErr.Error())
|
||||
return serverErr
|
||||
}
|
||||
|
||||
api := api4.Init(server, server.AppOptions, server.Router)
|
||||
wsapi.Init(server.FakeApp(), server.WebSocketRouter)
|
||||
web.New(server, server.AppOptions, server.Router)
|
||||
|
||||
// If we allow testing then listen for manual testing URL hits
|
||||
if *server.Config().ServiceSettings.EnableTesting {
|
||||
manualtesting.Init(api)
|
||||
|
||||
2
go.mod
2
go.mod
@@ -50,7 +50,7 @@ require (
|
||||
github.com/mattn/go-runewidth v0.0.4 // indirect
|
||||
github.com/mattn/go-sqlite3 v1.11.0
|
||||
github.com/miekg/dns v1.1.19 // indirect
|
||||
github.com/minio/minio-go/v6 v6.0.38
|
||||
github.com/minio/minio-go/v6 v6.0.40
|
||||
github.com/mitchellh/go-testing-interface v1.0.0 // indirect
|
||||
github.com/muesli/smartcrop v0.3.0 // indirect
|
||||
github.com/olekukonko/tablewriter v0.0.1 // indirect
|
||||
|
||||
4
go.sum
4
go.sum
@@ -263,8 +263,8 @@ github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5
|
||||
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
||||
github.com/miekg/dns v1.1.19 h1:0ymbfaLG1/utH2+BydNiF+dx1jSEmdr/nylOtkGHZZg=
|
||||
github.com/miekg/dns v1.1.19/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso=
|
||||
github.com/minio/minio-go/v6 v6.0.38 h1:zd3yagckaBVAMJT+HsbpURx9ndqYQp/N/udc1UVS72E=
|
||||
github.com/minio/minio-go/v6 v6.0.38/go.mod h1:qD0lajrGW49lKZLtXKtCB4X/qkMf0a5tBvN2PaZg7Gg=
|
||||
github.com/minio/minio-go/v6 v6.0.40 h1:MlSCSXvItiu2jINMxYdhUU99KR4446Db+0iAU1IKaZ0=
|
||||
github.com/minio/minio-go/v6 v6.0.40/go.mod h1:qD0lajrGW49lKZLtXKtCB4X/qkMf0a5tBvN2PaZg7Gg=
|
||||
github.com/minio/sha256-simd v0.1.1 h1:5QHSlgo3nt5yKOJrC7W8w7X+NFl8cMPZm96iu8kKUJU=
|
||||
github.com/minio/sha256-simd v0.1.1/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM=
|
||||
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
|
||||
|
||||
@@ -764,7 +764,7 @@
|
||||
},
|
||||
{
|
||||
"id": "api.command_invite.group_constrained_user_denied",
|
||||
"translation": "User cannot be added to this channel because it is constrained to group members only."
|
||||
"translation": "This channel is managed by groups. This user is not part of a group that is synched to this channel."
|
||||
},
|
||||
{
|
||||
"id": "api.command_invite.hint",
|
||||
@@ -1864,7 +1864,7 @@
|
||||
},
|
||||
{
|
||||
"id": "api.team.add_members.user_denied",
|
||||
"translation": "Team membership denied to the following users because of group constraints: {{ .UserIDs }}"
|
||||
"translation": "This team is managed by groups. This user is not part of a group that is synched to this team."
|
||||
},
|
||||
{
|
||||
"id": "api.team.add_user_to_team.added",
|
||||
|
||||
@@ -2235,6 +2235,16 @@ func (c *Client4) SearchChannels(teamId string, search *ChannelSearch) ([]*Chann
|
||||
return ChannelSliceFromJson(r.Body), BuildResponse(r)
|
||||
}
|
||||
|
||||
// SearchArchivedChannels returns the archived channels on a team matching the provided search term.
|
||||
func (c *Client4) SearchArchivedChannels(teamId string, search *ChannelSearch) ([]*Channel, *Response) {
|
||||
r, err := c.DoApiPost(c.GetChannelsForTeamRoute(teamId)+"/search_archived", search.ToJson())
|
||||
if err != nil {
|
||||
return nil, BuildErrorResponse(r, err)
|
||||
}
|
||||
defer closeBody(r)
|
||||
return ChannelSliceFromJson(r.Body), BuildResponse(r)
|
||||
}
|
||||
|
||||
// SearchAllChannels search in all the channels. Must be a system administrator.
|
||||
func (c *Client4) SearchAllChannels(search *ChannelSearch) (*ChannelListWithTeamData, *Response) {
|
||||
r, err := c.DoApiPost(c.GetChannelsRoute()+"/search", search.ToJson())
|
||||
|
||||
@@ -24,109 +24,182 @@ func TestFileInfoIsValid(t *testing.T) {
|
||||
Path: "fake/path.png",
|
||||
}
|
||||
|
||||
require.Nil(t, info.IsValid())
|
||||
t.Run("Valid File Info", func(t *testing.T) {
|
||||
assert.Nil(t, info.IsValid())
|
||||
})
|
||||
|
||||
info.Id = ""
|
||||
require.NotNil(t, info.IsValid(), "empty Id isn't valid")
|
||||
t.Run("Empty ID is not valid", func(t *testing.T) {
|
||||
info.Id = ""
|
||||
assert.NotNil(t, info.IsValid(), "empty Id isn't valid")
|
||||
info.Id = NewId()
|
||||
})
|
||||
|
||||
info.Id = NewId()
|
||||
info.CreateAt = 0
|
||||
require.NotNil(t, info.IsValid(), "empty CreateAt isn't valid")
|
||||
t.Run("CreateAt 0 is not valid", func(t *testing.T) {
|
||||
info.CreateAt = 0
|
||||
assert.NotNil(t, info.IsValid(), "empty CreateAt isn't valid")
|
||||
info.CreateAt = 1234
|
||||
})
|
||||
|
||||
info.CreateAt = 1234
|
||||
info.UpdateAt = 0
|
||||
require.NotNil(t, info.IsValid(), "empty UpdateAt isn't valid")
|
||||
t.Run("UpdateAt 0 is not valid", func(t *testing.T) {
|
||||
info.UpdateAt = 0
|
||||
assert.NotNil(t, info.IsValid(), "empty UpdateAt isn't valid")
|
||||
info.UpdateAt = 1234
|
||||
})
|
||||
|
||||
info.UpdateAt = 1234
|
||||
info.PostId = NewId()
|
||||
require.Nil(t, info.IsValid())
|
||||
t.Run("New Post ID is valid", func(t *testing.T) {
|
||||
info.PostId = NewId()
|
||||
assert.Nil(t, info.IsValid())
|
||||
})
|
||||
|
||||
info.Path = ""
|
||||
require.NotNil(t, info.IsValid(), "empty Path isn't valid")
|
||||
|
||||
info.Path = "fake/path.png"
|
||||
require.Nil(t, info.IsValid())
|
||||
t.Run("Empty path is not valid", func(t *testing.T) {
|
||||
info.Path = ""
|
||||
assert.NotNil(t, info.IsValid(), "empty Path isn't valid")
|
||||
info.Path = "fake/path.png"
|
||||
})
|
||||
}
|
||||
|
||||
func TestFileInfoIsImage(t *testing.T) {
|
||||
info := &FileInfo{MimeType: "image/png"}
|
||||
assert.True(t, info.IsImage(), "file is an image")
|
||||
info := &FileInfo{}
|
||||
t.Run("MimeType set to image/png is considered an image", func(t *testing.T) {
|
||||
info.MimeType = "image/png"
|
||||
assert.True(t, info.IsImage(), "PNG file should be considered as an image")
|
||||
})
|
||||
|
||||
info.MimeType = "text/plain"
|
||||
assert.False(t, info.IsImage(), "file is not an image")
|
||||
t.Run("MimeType set to text/plain is not considered an image", func(t *testing.T) {
|
||||
info.MimeType = "text/plain"
|
||||
assert.False(t, info.IsImage(), "Text file should not be considered as an image")
|
||||
})
|
||||
}
|
||||
|
||||
func TestGetInfoForFile(t *testing.T) {
|
||||
fakeFile := make([]byte, 1000)
|
||||
|
||||
info, errApp := GetInfoForBytes("file.txt", fakeFile)
|
||||
require.Nil(t, errApp)
|
||||
assert.Equalf(t, info.Name, "file.txt", "Got incorrect filename: %v", info.Name)
|
||||
assert.Equalf(t, info.Extension, "txt", "Got incorrect extension: %v", info.Extension)
|
||||
assert.EqualValuesf(t, info.Size, 1000, "Got incorrect size: %v", info.Size)
|
||||
assert.Truef(t, strings.HasPrefix(info.MimeType, "text/plain"), "Got incorrect mime type: %v", info.MimeType)
|
||||
assert.Equalf(t, info.Width, 0, "Got incorrect width: %v", info.Width)
|
||||
assert.Equalf(t, info.Height, 0, "Got incorrect height: %v", info.Height)
|
||||
assert.Falsef(t, info.HasPreviewImage, "Got incorrect has preview image: %v", info.HasPreviewImage)
|
||||
|
||||
pngFile, err := ioutil.ReadFile("../tests/test.png")
|
||||
require.Nilf(t, err, "Failed to load test.png")
|
||||
|
||||
info, err = GetInfoForBytes("test.png", pngFile)
|
||||
require.Nil(t, err)
|
||||
assert.Equalf(t, info.Name, "test.png", "Got incorrect filename: %v", info.Name)
|
||||
assert.Equalf(t, info.Extension, "png", "Got incorrect extension: %v", info.Extension)
|
||||
assert.EqualValues(t, info.Size, 279591, "Got incorrect size: %v", info.Size)
|
||||
assert.Equalf(t, info.MimeType, "image/png", "Got incorrect mime type: %v", info.MimeType)
|
||||
assert.Equalf(t, info.Width, 408, "Got incorrect width: %v", info.Width)
|
||||
assert.Equalf(t, info.Height, 336, "Got incorrect height: %v", info.Height)
|
||||
assert.Truef(t, info.HasPreviewImage, "Got incorrect has preview image: %v", info.HasPreviewImage)
|
||||
|
||||
// base 64 encoded version of handtinywhite.gif from http://probablyprogramming.com/2009/03/15/the-tiniest-gif-ever
|
||||
gifFile, _ := base64.StdEncoding.DecodeString("R0lGODlhAQABAIABAP///wAAACwAAAAAAQABAAACAkQBADs=")
|
||||
info, err = GetInfoForBytes("handtinywhite.gif", gifFile)
|
||||
require.Nil(t, err)
|
||||
assert.Equalf(t, info.Name, "handtinywhite.gif", "Got incorrect filename: %v", info.Name)
|
||||
assert.Equalf(t, info.Extension, "gif", "Got incorrect extension: %v", info.Extension)
|
||||
assert.EqualValuesf(t, info.Size, 35, "Got incorrect size: %v", info.Size)
|
||||
assert.Equalf(t, info.MimeType, "image/gif", "Got incorrect mime type: %v", info.MimeType)
|
||||
assert.Equalf(t, info.Width, 1, "Got incorrect width: %v", info.Width)
|
||||
assert.Equalf(t, info.Height, 1, "Got incorrect height: %v", info.Height)
|
||||
assert.Truef(t, info.HasPreviewImage, "Got incorrect has preview image: %v", info.HasPreviewImage)
|
||||
|
||||
animatedGifFile, err := ioutil.ReadFile("../tests/testgif.gif")
|
||||
require.Nilf(t, err, "Failed to load testgif.gif")
|
||||
|
||||
info, err = GetInfoForBytes("testgif.gif", animatedGifFile)
|
||||
require.Nil(t, err)
|
||||
assert.Equalf(t, info.Name, "testgif.gif", "Got incorrect filename: %v", info.Name)
|
||||
assert.Equalf(t, info.Extension, "gif", "Got incorrect extension: %v", info.Extension)
|
||||
assert.EqualValuesf(t, info.Size, 38689, "Got incorrect size: %v", info.Size)
|
||||
assert.Equalf(t, info.MimeType, "image/gif", "Got incorrect mime type: %v", info.MimeType)
|
||||
assert.Equalf(t, info.Width, 118, "Got incorrect width: %v", info.Width)
|
||||
assert.Equalf(t, info.Height, 118, "Got incorrect height: %v", info.Height)
|
||||
assert.Falsef(t, info.HasPreviewImage, "Got incorrect has preview image: %v", info.HasPreviewImage)
|
||||
var ttc = []struct {
|
||||
testName string
|
||||
filename string
|
||||
file []byte
|
||||
usePrefixForMime bool
|
||||
expectedExtension string
|
||||
expectedSize int
|
||||
expectedMime string
|
||||
expectedWidth int
|
||||
expectedHeight int
|
||||
expectedHasPreviewImage bool
|
||||
}{
|
||||
{
|
||||
testName: "Text File",
|
||||
filename: "file.txt",
|
||||
file: fakeFile,
|
||||
usePrefixForMime: true,
|
||||
expectedExtension: "txt",
|
||||
expectedSize: 1000,
|
||||
expectedMime: "text/plain",
|
||||
expectedWidth: 0,
|
||||
expectedHeight: 0,
|
||||
expectedHasPreviewImage: false,
|
||||
},
|
||||
{
|
||||
testName: "PNG file",
|
||||
filename: "test.png",
|
||||
file: pngFile,
|
||||
usePrefixForMime: false,
|
||||
expectedExtension: "png",
|
||||
expectedSize: 279591,
|
||||
expectedMime: "image/png",
|
||||
expectedWidth: 408,
|
||||
expectedHeight: 336,
|
||||
expectedHasPreviewImage: true,
|
||||
},
|
||||
{
|
||||
testName: "Static Gif File",
|
||||
filename: "handtinywhite.gif",
|
||||
file: gifFile,
|
||||
usePrefixForMime: false,
|
||||
expectedExtension: "gif",
|
||||
expectedSize: 35,
|
||||
expectedMime: "image/gif",
|
||||
expectedWidth: 1,
|
||||
expectedHeight: 1,
|
||||
expectedHasPreviewImage: true,
|
||||
},
|
||||
{
|
||||
testName: "Animated Gif File",
|
||||
filename: "testgif.gif",
|
||||
file: animatedGifFile,
|
||||
usePrefixForMime: false,
|
||||
expectedExtension: "gif",
|
||||
expectedSize: 38689,
|
||||
expectedMime: "image/gif",
|
||||
expectedWidth: 118,
|
||||
expectedHeight: 118,
|
||||
expectedHasPreviewImage: false,
|
||||
},
|
||||
{
|
||||
testName: "No extension File",
|
||||
filename: "filewithoutextension",
|
||||
file: fakeFile,
|
||||
usePrefixForMime: false,
|
||||
expectedExtension: "",
|
||||
expectedSize: 1000,
|
||||
expectedMime: "",
|
||||
expectedWidth: 0,
|
||||
expectedHeight: 0,
|
||||
expectedHasPreviewImage: false,
|
||||
},
|
||||
{
|
||||
// Always make the extension lower case to make it easier to use in other places
|
||||
testName: "Uppercase extension File",
|
||||
filename: "file.TXT",
|
||||
file: fakeFile,
|
||||
usePrefixForMime: true,
|
||||
expectedExtension: "txt",
|
||||
expectedSize: 1000,
|
||||
expectedMime: "text/plain",
|
||||
expectedWidth: 0,
|
||||
expectedHeight: 0,
|
||||
expectedHasPreviewImage: false,
|
||||
},
|
||||
{
|
||||
// Don't error out for image formats we don't support
|
||||
testName: "Not supported File",
|
||||
filename: "file.tif",
|
||||
file: fakeFile,
|
||||
usePrefixForMime: false,
|
||||
expectedExtension: "tif",
|
||||
expectedSize: 1000,
|
||||
expectedMime: "image/tiff",
|
||||
expectedWidth: 0,
|
||||
expectedHeight: 0,
|
||||
expectedHasPreviewImage: false,
|
||||
},
|
||||
}
|
||||
|
||||
info, err = GetInfoForBytes("filewithoutextension", fakeFile)
|
||||
require.Nil(t, err)
|
||||
assert.Equalf(t, info.Name, "filewithoutextension", "Got incorrect filename: %v", info.Name)
|
||||
assert.Equalf(t, info.Extension, "", "Got incorrect extension: %v", info.Extension)
|
||||
assert.EqualValuesf(t, info.Size, 1000, "Got incorrect size: %v", info.Size)
|
||||
assert.Equalf(t, info.MimeType, "", "Got incorrect mime type: %v", info.MimeType)
|
||||
assert.Equalf(t, info.Width, 0, "Got incorrect width: %v", info.Width)
|
||||
assert.Equalf(t, info.Height, 0, "Got incorrect height: %v", info.Height)
|
||||
assert.Falsef(t, info.HasPreviewImage, "Got incorrect has preview image: %v", info.HasPreviewImage)
|
||||
for _, tc := range ttc {
|
||||
t.Run(tc.testName, func(t *testing.T) {
|
||||
info, errApp := GetInfoForBytes(tc.filename, tc.file)
|
||||
require.Nil(t, errApp)
|
||||
|
||||
// Always make the extension lower case to make it easier to use in other places
|
||||
info, err = GetInfoForBytes("file.TXT", fakeFile)
|
||||
require.Nil(t, err)
|
||||
assert.Equalf(t, info.Name, "file.TXT", "Got incorrect filename: %v", info.Name)
|
||||
assert.Equalf(t, info.Extension, "txt", "Got incorrect extension: %v", info.Extension)
|
||||
assert.Equalf(t, tc.filename, info.Name, "Got incorrect filename: %v", info.Name)
|
||||
assert.Equalf(t, tc.expectedExtension, info.Extension, "Got incorrect extension: %v", info.Extension)
|
||||
assert.EqualValuesf(t, tc.expectedSize, info.Size, "Got incorrect size: %v", info.Size)
|
||||
assert.Equalf(t, tc.expectedWidth, info.Width, "Got incorrect width: %v", info.Width)
|
||||
assert.Equalf(t, tc.expectedHeight, info.Height, "Got incorrect height: %v", info.Height)
|
||||
assert.Equalf(t, tc.expectedHasPreviewImage, info.HasPreviewImage, "Got incorrect has preview image: %v", info.HasPreviewImage)
|
||||
|
||||
// Don't error out for image formats we don't support
|
||||
info, err = GetInfoForBytes("file.tif", fakeFile)
|
||||
require.Nil(t, err)
|
||||
assert.Equalf(t, info.Name, "file.tif", "Got incorrect filename: %v", info.Name)
|
||||
assert.Equalf(t, info.Extension, "tif", "Got incorrect extension: %v", info.Extension)
|
||||
assert.True(t, info.MimeType == "image/x-tiff" || info.MimeType == "image/tiff", "Got incorrect mime type: %v", info.MimeType)
|
||||
if tc.usePrefixForMime {
|
||||
assert.Truef(t, strings.HasPrefix(info.MimeType, tc.expectedMime), "Got incorrect mime type: %v", info.MimeType)
|
||||
} else {
|
||||
assert.Equalf(t, tc.expectedMime, info.MimeType, "Got incorrect mime type: %v", info.MimeType)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -512,9 +512,11 @@ func (u *User) Sanitize(options map[string]bool) {
|
||||
}
|
||||
|
||||
// Remove any input data from the user object that is not user controlled
|
||||
func (u *User) SanitizeInput() {
|
||||
u.AuthData = NewString("")
|
||||
u.AuthService = ""
|
||||
func (u *User) SanitizeInput(isAdmin bool) {
|
||||
if !isAdmin {
|
||||
u.AuthData = NewString("")
|
||||
u.AuthService = ""
|
||||
}
|
||||
u.LastPasswordUpdate = 0
|
||||
u.LastPictureUpdate = 0
|
||||
u.FailedAttempts = 0
|
||||
|
||||
@@ -9,6 +9,9 @@ import (
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// Helpers provide a common patterns plugins use.
|
||||
//
|
||||
// Plugins obtain access to the Helpers by embedding MattermostPlugin.
|
||||
type Helpers interface {
|
||||
// EnsureBot either returns an existing bot user matching the given bot, or creates a bot user from the given bot.
|
||||
// Returns the id of the resulting bot.
|
||||
@@ -55,6 +58,7 @@ type Helpers interface {
|
||||
KVSetWithExpiryJSON(key string, value interface{}, expireInSeconds int64) error
|
||||
}
|
||||
|
||||
// HelpersImpl implements the helpers interface with an API that retrieves data on behalf of the plugin.
|
||||
type HelpersImpl struct {
|
||||
API API
|
||||
}
|
||||
|
||||
@@ -4,12 +4,14 @@
|
||||
package plugin
|
||||
|
||||
import (
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/mattermost/mattermost-server/model"
|
||||
"github.com/mattermost/mattermost-server/utils"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
func (p *HelpersImpl) EnsureBot(bot *model.Bot) (retBotId string, retErr error) {
|
||||
// EnsureBot implements Helpers.EnsureBot
|
||||
func (p *HelpersImpl) EnsureBot(bot *model.Bot) (retBotID string, retErr error) {
|
||||
err := p.ensureServerVersion("5.10.0")
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "failed to ensure bot")
|
||||
@@ -23,34 +25,34 @@ func (p *HelpersImpl) EnsureBot(bot *model.Bot) (retBotId string, retErr error)
|
||||
// If we fail for any reason, this could be a race between creation of bot and
|
||||
// retrieval from another EnsureBot. Just try the basic retrieve existing again.
|
||||
defer func() {
|
||||
if retBotId == "" || retErr != nil {
|
||||
if retBotID == "" || retErr != nil {
|
||||
var err error
|
||||
var botIdBytes []byte
|
||||
var botIDBytes []byte
|
||||
|
||||
err = utils.ProgressiveRetry(func() error {
|
||||
botIdBytes, err = p.API.KVGet(BOT_USER_KEY)
|
||||
botIDBytes, err = p.API.KVGet(BOT_USER_KEY)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
if err == nil && botIdBytes != nil {
|
||||
retBotId = string(botIdBytes)
|
||||
if err == nil && botIDBytes != nil {
|
||||
retBotID = string(botIDBytes)
|
||||
retErr = nil
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
botIdBytes, kvGetErr := p.API.KVGet(BOT_USER_KEY)
|
||||
botIDBytes, kvGetErr := p.API.KVGet(BOT_USER_KEY)
|
||||
if kvGetErr != nil {
|
||||
return "", errors.Wrap(kvGetErr, "failed to get bot")
|
||||
}
|
||||
|
||||
// If the bot has already been created, there is nothing to do.
|
||||
if botIdBytes != nil {
|
||||
botId := string(botIdBytes)
|
||||
return botId, nil
|
||||
if botIDBytes != nil {
|
||||
botID := string(botIDBytes)
|
||||
return botID, nil
|
||||
}
|
||||
|
||||
// Check for an existing bot user with that username. If one exists, then use that.
|
||||
|
||||
@@ -24,6 +24,18 @@ import (
|
||||
"github.com/mattermost/mattermost-server/utils"
|
||||
)
|
||||
|
||||
type mailData struct {
|
||||
mimeTo string
|
||||
smtpTo string
|
||||
from mail.Address
|
||||
replyTo mail.Address
|
||||
subject string
|
||||
htmlBody string
|
||||
attachments []*model.FileInfo
|
||||
embeddedFiles map[string]io.Reader
|
||||
mimeHeaders map[string]string
|
||||
}
|
||||
|
||||
// smtpClient is implemented by an smtp.Client. See https://golang.org/pkg/net/smtp/#Client.
|
||||
//
|
||||
type smtpClient interface {
|
||||
@@ -204,15 +216,29 @@ func TestConnection(config *model.Config) {
|
||||
defer c.Close()
|
||||
}
|
||||
|
||||
func SendMailUsingConfig(to, subject, htmlBody string, config *model.Config, enableComplianceFeatures bool) *model.AppError {
|
||||
func SendMailWithEmbeddedFilesUsingConfig(to, subject, htmlBody string, embeddedFiles map[string]io.Reader, config *model.Config, enableComplianceFeatures bool) *model.AppError {
|
||||
fromMail := mail.Address{Name: *config.EmailSettings.FeedbackName, Address: *config.EmailSettings.FeedbackEmail}
|
||||
replyTo := mail.Address{Name: *config.EmailSettings.FeedbackName, Address: *config.EmailSettings.ReplyToAddress}
|
||||
|
||||
return SendMailUsingConfigAdvanced(to, to, fromMail, replyTo, subject, htmlBody, nil, nil, nil, config, enableComplianceFeatures)
|
||||
mail := mailData{
|
||||
mimeTo: to,
|
||||
smtpTo: to,
|
||||
from: fromMail,
|
||||
replyTo: replyTo,
|
||||
subject: subject,
|
||||
htmlBody: htmlBody,
|
||||
embeddedFiles: embeddedFiles,
|
||||
}
|
||||
|
||||
return sendMailUsingConfigAdvanced(mail, config, enableComplianceFeatures)
|
||||
}
|
||||
|
||||
func SendMailUsingConfig(to, subject, htmlBody string, config *model.Config, enableComplianceFeatures bool) *model.AppError {
|
||||
return SendMailWithEmbeddedFilesUsingConfig(to, subject, htmlBody, nil, config, enableComplianceFeatures)
|
||||
}
|
||||
|
||||
// allows for sending an email with attachments and differing MIME/SMTP recipients
|
||||
func SendMailUsingConfigAdvanced(mimeTo, smtpTo string, from, replyTo mail.Address, subject, htmlBody string, attachments []*model.FileInfo, embeddedFiles map[string]io.Reader, mimeHeaders map[string]string, config *model.Config, enableComplianceFeatures bool) *model.AppError {
|
||||
func sendMailUsingConfigAdvanced(mail mailData, config *model.Config, enableComplianceFeatures bool) *model.AppError {
|
||||
if len(*config.EmailSettings.SMTPServer) == 0 {
|
||||
return nil
|
||||
}
|
||||
@@ -235,34 +261,34 @@ func SendMailUsingConfigAdvanced(mimeTo, smtpTo string, from, replyTo mail.Addre
|
||||
return err
|
||||
}
|
||||
|
||||
return SendMail(c, mimeTo, smtpTo, from, replyTo, subject, htmlBody, attachments, embeddedFiles, mimeHeaders, fileBackend, time.Now())
|
||||
return SendMail(c, mail, fileBackend, time.Now())
|
||||
}
|
||||
|
||||
func SendMail(c smtpClient, mimeTo, smtpTo string, from, replyTo mail.Address, subject, htmlBody string, attachments []*model.FileInfo, embeddedFiles map[string]io.Reader, mimeHeaders map[string]string, fileBackend filesstore.FileBackend, date time.Time) *model.AppError {
|
||||
mlog.Debug("sending mail", mlog.String("to", smtpTo), mlog.String("subject", subject))
|
||||
func SendMail(c smtpClient, mail mailData, fileBackend filesstore.FileBackend, date time.Time) *model.AppError {
|
||||
mlog.Debug("sending mail", mlog.String("to", mail.smtpTo), mlog.String("subject", mail.subject))
|
||||
|
||||
htmlMessage := "\r\n<html><body>" + htmlBody + "</body></html>"
|
||||
htmlMessage := "\r\n<html><body>" + mail.htmlBody + "</body></html>"
|
||||
|
||||
txtBody, err := html2text.FromString(htmlBody)
|
||||
txtBody, err := html2text.FromString(mail.htmlBody)
|
||||
if err != nil {
|
||||
mlog.Warn("Unable to convert html body to text", mlog.Err(err))
|
||||
txtBody = ""
|
||||
}
|
||||
|
||||
headers := map[string][]string{
|
||||
"From": {from.String()},
|
||||
"To": {mimeTo},
|
||||
"Subject": {encodeRFC2047Word(subject)},
|
||||
"From": {mail.from.String()},
|
||||
"To": {mail.mimeTo},
|
||||
"Subject": {encodeRFC2047Word(mail.subject)},
|
||||
"Content-Transfer-Encoding": {"8bit"},
|
||||
"Auto-Submitted": {"auto-generated"},
|
||||
"Precedence": {"bulk"},
|
||||
}
|
||||
|
||||
if len(replyTo.Address) > 0 {
|
||||
headers["Reply-To"] = []string{replyTo.String()}
|
||||
if len(mail.replyTo.Address) > 0 {
|
||||
headers["Reply-To"] = []string{mail.replyTo.String()}
|
||||
}
|
||||
|
||||
for k, v := range mimeHeaders {
|
||||
for k, v := range mail.mimeHeaders {
|
||||
headers[k] = []string{encodeRFC2047Word(v)}
|
||||
}
|
||||
|
||||
@@ -272,11 +298,11 @@ func SendMail(c smtpClient, mimeTo, smtpTo string, from, replyTo mail.Address, s
|
||||
m.SetBody("text/plain", txtBody)
|
||||
m.AddAlternative("text/html", htmlMessage)
|
||||
|
||||
for name, reader := range embeddedFiles {
|
||||
for name, reader := range mail.embeddedFiles {
|
||||
m.EmbedReader(name, reader)
|
||||
}
|
||||
|
||||
for _, fileInfo := range attachments {
|
||||
for _, fileInfo := range mail.attachments {
|
||||
bytes, err := fileBackend.ReadFile(fileInfo.Path)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -290,11 +316,11 @@ func SendMail(c smtpClient, mimeTo, smtpTo string, from, replyTo mail.Address, s
|
||||
}))
|
||||
}
|
||||
|
||||
if err = c.Mail(from.Address); err != nil {
|
||||
if err = c.Mail(mail.from.Address); err != nil {
|
||||
return model.NewAppError("SendMail", "utils.mail.send_mail.from_address.app_error", nil, err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
|
||||
if err = c.Rcpt(smtpTo); err != nil {
|
||||
if err = c.Rcpt(mail.smtpTo); err != nil {
|
||||
return model.NewAppError("SendMail", "utils.mail.send_mail.to_address.app_error", nil, err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
|
||||
|
||||
@@ -128,6 +128,50 @@ func TestSendMailUsingConfig(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestSendMailWithEmbeddedFilesUsingConfig(t *testing.T) {
|
||||
utils.T = utils.GetUserTranslations("en")
|
||||
|
||||
fs, err := config.NewFileStore("config.json", false)
|
||||
require.Nil(t, err)
|
||||
|
||||
cfg := fs.Get()
|
||||
|
||||
var emailTo = "test@example.com"
|
||||
var emailSubject = "Testing this email"
|
||||
var emailBody = "This is a test from autobot"
|
||||
|
||||
//Delete all the messages before check the sample email
|
||||
DeleteMailBox(emailTo)
|
||||
|
||||
embeddedFiles := map[string]io.Reader{
|
||||
"test1.png": bytes.NewReader([]byte("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx")),
|
||||
"test2.png": bytes.NewReader([]byte("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx")),
|
||||
}
|
||||
err2 := SendMailWithEmbeddedFilesUsingConfig(emailTo, emailSubject, emailBody, embeddedFiles, cfg, true)
|
||||
require.Nil(t, err2, "Should connect to the SMTP Server")
|
||||
|
||||
//Check if the email was send to the right email address
|
||||
var resultsMailbox JSONMessageHeaderInbucket
|
||||
err3 := RetryInbucket(5, func() error {
|
||||
var err error
|
||||
resultsMailbox, err = GetMailBox(emailTo)
|
||||
return err
|
||||
})
|
||||
if err3 != nil {
|
||||
t.Log(err3)
|
||||
t.Log("No email was received, maybe due load on the server. Skipping this verification")
|
||||
} else {
|
||||
if len(resultsMailbox) > 0 {
|
||||
require.Contains(t, resultsMailbox[0].To[0], emailTo, "Wrong To: recipient")
|
||||
resultsEmail, err := GetMessageFromMailbox(emailTo, resultsMailbox[0].ID)
|
||||
require.Nil(t, err, "Could not get message from mailbox")
|
||||
require.Contains(t, emailBody, resultsEmail.Body.Text, "Wrong received message %s", resultsEmail.Body.Text)
|
||||
// Usign the message size because the inbucket API doesn't return embedded attachments through the API
|
||||
require.Greater(t, resultsEmail.Size, 1500, "the file size should be more because the embedded attachemtns")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSendMailUsingConfigAdvanced(t *testing.T) {
|
||||
utils.T = utils.GetUserTranslations("en")
|
||||
|
||||
@@ -136,15 +180,8 @@ func TestSendMailUsingConfigAdvanced(t *testing.T) {
|
||||
|
||||
cfg := fs.Get()
|
||||
|
||||
var mimeTo = "test@example.com"
|
||||
var smtpTo = "test2@example.com"
|
||||
var from = mail.Address{Name: "Nobody", Address: "nobody@mattermost.com"}
|
||||
var replyTo = mail.Address{Name: "ReplyTo", Address: "reply_to@mattermost.com"}
|
||||
var emailSubject = "Testing this email"
|
||||
var emailBody = "This is a test from autobot"
|
||||
|
||||
//Delete all the messages before check the sample email
|
||||
DeleteMailBox(smtpTo)
|
||||
DeleteMailBox("test2@example.com")
|
||||
|
||||
fileBackend, err := filesstore.NewFileBackend(&cfg.FileSettings, true)
|
||||
assert.Nil(t, err)
|
||||
@@ -178,31 +215,43 @@ func TestSendMailUsingConfigAdvanced(t *testing.T) {
|
||||
headers := make(map[string]string)
|
||||
headers["TestHeader"] = "TestValue"
|
||||
|
||||
err = SendMailUsingConfigAdvanced(mimeTo, smtpTo, from, replyTo, emailSubject, emailBody, attachments, embeddedFiles, headers, cfg, true)
|
||||
mail := mailData{
|
||||
mimeTo: "test@example.com",
|
||||
smtpTo: "test2@example.com",
|
||||
from: mail.Address{Name: "Nobody", Address: "nobody@mattermost.com"},
|
||||
replyTo: mail.Address{Name: "ReplyTo", Address: "reply_to@mattermost.com"},
|
||||
subject: "Testing this email",
|
||||
htmlBody: "This is a test from autobot",
|
||||
attachments: attachments,
|
||||
embeddedFiles: embeddedFiles,
|
||||
mimeHeaders: headers,
|
||||
}
|
||||
|
||||
err = sendMailUsingConfigAdvanced(mail, cfg, true)
|
||||
require.Nil(t, err, "Should connect to the STMP Server: %v", err)
|
||||
|
||||
//Check if the email was send to the right email address
|
||||
var resultsMailbox JSONMessageHeaderInbucket
|
||||
err = RetryInbucket(5, func() error {
|
||||
var mailErr error
|
||||
resultsMailbox, mailErr = GetMailBox(smtpTo)
|
||||
resultsMailbox, mailErr = GetMailBox(mail.smtpTo)
|
||||
return mailErr
|
||||
})
|
||||
require.Nil(t, err, "No emails found for address %s. error: %v", smtpTo, err)
|
||||
require.Nil(t, err, "No emails found for address %s. error: %v", mail.smtpTo, err)
|
||||
require.NotEqual(t, len(resultsMailbox), 0)
|
||||
|
||||
require.Contains(t, resultsMailbox[0].To[0], mimeTo, "Wrong To recipient")
|
||||
require.Contains(t, resultsMailbox[0].To[0], mail.mimeTo, "Wrong To recipient")
|
||||
|
||||
resultsEmail, err := GetMessageFromMailbox(smtpTo, resultsMailbox[0].ID)
|
||||
resultsEmail, err := GetMessageFromMailbox(mail.smtpTo, resultsMailbox[0].ID)
|
||||
require.Nil(t, err)
|
||||
|
||||
require.Contains(t, emailBody, resultsEmail.Body.Text, "Wrong received message")
|
||||
require.Contains(t, mail.htmlBody, resultsEmail.Body.Text, "Wrong received message")
|
||||
|
||||
// verify that the To header of the email message is set to the MIME recipient, even though we got it out of the SMTP recipient's email inbox
|
||||
assert.Equal(t, mimeTo, resultsEmail.Header["To"][0])
|
||||
assert.Equal(t, mail.mimeTo, resultsEmail.Header["To"][0])
|
||||
|
||||
// verify that the MIME from address is correct - unfortunately, we can't verify the SMTP from address
|
||||
assert.Equal(t, from.String(), resultsEmail.Header["From"][0])
|
||||
assert.Equal(t, mail.from.String(), resultsEmail.Header["From"][0])
|
||||
|
||||
// check that the custom mime headers came through - header case seems to get mutated
|
||||
assert.Equal(t, "TestValue", resultsEmail.Header["Testheader"][0])
|
||||
@@ -330,7 +379,8 @@ func TestSendMail(t *testing.T) {
|
||||
|
||||
for testName, tc := range testCases {
|
||||
t.Run(testName, func(t *testing.T) {
|
||||
appErr = SendMail(mocm, "", "", mail.Address{}, tc.replyTo, "", "", nil, nil, nil, mockBackend, time.Now())
|
||||
mail := mailData{"", "", mail.Address{}, tc.replyTo, "", "", nil, nil, nil}
|
||||
appErr = SendMail(mocm, mail, mockBackend, time.Now())
|
||||
require.Nil(t, appErr)
|
||||
if len(tc.contains) > 0 {
|
||||
require.Contains(t, string(mocm.data), tc.contains)
|
||||
|
||||
@@ -1036,7 +1036,7 @@ func (s SqlChannelStore) GetPublicChannelsForTeam(teamId string, offset int, lim
|
||||
PublicChannels pc ON (pc.Id = Channels.Id)
|
||||
WHERE
|
||||
pc.TeamId = :TeamId
|
||||
AND pc.DeleteAt = 0
|
||||
AND pc.DeleteAt = 0
|
||||
ORDER BY pc.DisplayName
|
||||
LIMIT :Limit
|
||||
OFFSET :Offset
|
||||
@@ -1242,10 +1242,24 @@ func (s SqlChannelStore) GetDeletedByName(teamId string, name string) (*model.Ch
|
||||
return &channel, nil
|
||||
}
|
||||
|
||||
func (s SqlChannelStore) GetDeleted(teamId string, offset int, limit int) (*model.ChannelList, *model.AppError) {
|
||||
func (s SqlChannelStore) GetDeleted(teamId string, offset int, limit int, userId string) (*model.ChannelList, *model.AppError) {
|
||||
channels := &model.ChannelList{}
|
||||
|
||||
if _, err := s.GetReplica().Select(channels, "SELECT * FROM Channels WHERE (TeamId = :TeamId OR TeamId = '') AND DeleteAt != 0 ORDER BY DisplayName LIMIT :Limit OFFSET :Offset", map[string]interface{}{"TeamId": teamId, "Limit": limit, "Offset": offset}); err != nil {
|
||||
query := `
|
||||
SELECT * FROM Channels
|
||||
WHERE (TeamId = :TeamId OR TeamId = '')
|
||||
AND DeleteAt != 0
|
||||
AND Type != 'P'
|
||||
UNION
|
||||
SELECT * FROM Channels
|
||||
WHERE (TeamId = :TeamId OR TeamId = '')
|
||||
AND DeleteAt != 0
|
||||
AND Type = 'P'
|
||||
AND Id IN (SELECT ChannelId FROM ChannelMembers WHERE UserId = :UserId)
|
||||
ORDER BY DisplayName LIMIT :Limit OFFSET :Offset
|
||||
`
|
||||
|
||||
if _, err := s.GetReplica().Select(channels, query, map[string]interface{}{"TeamId": teamId, "Limit": limit, "Offset": offset, "UserId": userId}); err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
return nil, model.NewAppError("SqlChannelStore.GetDeleted", "store.sql_channel.get_deleted.missing.app_error", nil, "teamId="+teamId+", "+err.Error(), http.StatusNotFound)
|
||||
}
|
||||
@@ -2245,6 +2259,57 @@ func (s SqlChannelStore) SearchInTeam(teamId string, term string, includeDeleted
|
||||
})
|
||||
}
|
||||
|
||||
func (s SqlChannelStore) SearchArchivedInTeam(teamId string, term string, userId string) (*model.ChannelList, *model.AppError) {
|
||||
publicChannels, publicErr := s.performSearch(`
|
||||
SELECT
|
||||
Channels.*
|
||||
FROM
|
||||
Channels
|
||||
JOIN
|
||||
Channels c ON (c.Id = Channels.Id)
|
||||
WHERE
|
||||
c.TeamId = :TeamId
|
||||
SEARCH_CLAUSE
|
||||
AND c.DeleteAt != 0
|
||||
AND c.Type != 'P'
|
||||
ORDER BY c.DisplayName
|
||||
LIMIT 100
|
||||
`, term, map[string]interface{}{
|
||||
"TeamId": teamId,
|
||||
"UserId": userId,
|
||||
})
|
||||
|
||||
privateChannels, privateErr := s.performSearch(`
|
||||
SELECT
|
||||
Channels.*
|
||||
FROM
|
||||
Channels
|
||||
JOIN
|
||||
Channels c ON (c.Id = Channels.Id)
|
||||
WHERE
|
||||
c.TeamId = :TeamId
|
||||
SEARCH_CLAUSE
|
||||
AND c.DeleteAt != 0
|
||||
AND c.Type = 'P'
|
||||
AND c.Id IN (SELECT ChannelId FROM ChannelMembers WHERE UserId = :UserId)
|
||||
ORDER BY c.DisplayName
|
||||
LIMIT 100
|
||||
`, term, map[string]interface{}{
|
||||
"TeamId": teamId,
|
||||
"UserId": userId,
|
||||
})
|
||||
|
||||
output := *publicChannels
|
||||
output = append(output, *privateChannels...)
|
||||
|
||||
outputErr := publicErr
|
||||
if privateErr != nil {
|
||||
outputErr = privateErr
|
||||
}
|
||||
|
||||
return &output, outputErr
|
||||
}
|
||||
|
||||
func (s SqlChannelStore) SearchForUserInTeam(userId string, teamId string, term string, includeDeleted bool) (*model.ChannelList, *model.AppError) {
|
||||
deleteFilter := "AND c.DeleteAt = 0"
|
||||
if includeDeleted {
|
||||
|
||||
@@ -162,7 +162,7 @@ func NewSqlSupplier(settings model.SqlSettings, metrics einterfaces.MetricsInter
|
||||
os.Exit(EXIT_CREATE_TABLE)
|
||||
}
|
||||
|
||||
err = UpgradeDatabase(supplier, model.CurrentVersion)
|
||||
err = upgradeDatabase(supplier, model.CurrentVersion)
|
||||
if err != nil {
|
||||
mlog.Critical("Failed to upgrade database.", mlog.Err(err))
|
||||
time.Sleep(time.Second)
|
||||
|
||||
@@ -70,10 +70,10 @@ const (
|
||||
EXIT_TEAM_INVITEID_MIGRATION_FAILED = 1006
|
||||
)
|
||||
|
||||
// UpgradeDatabase attempts to migrate the schema to the latest supported version.
|
||||
// upgradeDatabase attempts to migrate the schema to the latest supported version.
|
||||
// The value of model.CurrentVersion is accepted as a parameter for unit testing, but it is not
|
||||
// used to stop migrations at that version.
|
||||
func UpgradeDatabase(sqlStore SqlStore, currentModelVersionString string) error {
|
||||
func upgradeDatabase(sqlStore SqlStore, currentModelVersionString string) error {
|
||||
currentModelVersion, err := semver.Parse(currentModelVersionString)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "failed to parse current model version %s", currentModelVersionString)
|
||||
@@ -122,47 +122,47 @@ func UpgradeDatabase(sqlStore SqlStore, currentModelVersionString string) error
|
||||
|
||||
// Otherwise, apply any necessary migrations. Note that these methods currently invoke
|
||||
// os.Exit instead of returning an error.
|
||||
UpgradeDatabaseToVersion31(sqlStore)
|
||||
UpgradeDatabaseToVersion32(sqlStore)
|
||||
UpgradeDatabaseToVersion33(sqlStore)
|
||||
UpgradeDatabaseToVersion34(sqlStore)
|
||||
UpgradeDatabaseToVersion35(sqlStore)
|
||||
UpgradeDatabaseToVersion36(sqlStore)
|
||||
UpgradeDatabaseToVersion37(sqlStore)
|
||||
UpgradeDatabaseToVersion38(sqlStore)
|
||||
UpgradeDatabaseToVersion39(sqlStore)
|
||||
UpgradeDatabaseToVersion310(sqlStore)
|
||||
UpgradeDatabaseToVersion40(sqlStore)
|
||||
UpgradeDatabaseToVersion41(sqlStore)
|
||||
UpgradeDatabaseToVersion42(sqlStore)
|
||||
UpgradeDatabaseToVersion43(sqlStore)
|
||||
UpgradeDatabaseToVersion44(sqlStore)
|
||||
UpgradeDatabaseToVersion45(sqlStore)
|
||||
UpgradeDatabaseToVersion46(sqlStore)
|
||||
UpgradeDatabaseToVersion47(sqlStore)
|
||||
UpgradeDatabaseToVersion471(sqlStore)
|
||||
UpgradeDatabaseToVersion472(sqlStore)
|
||||
UpgradeDatabaseToVersion48(sqlStore)
|
||||
UpgradeDatabaseToVersion481(sqlStore)
|
||||
UpgradeDatabaseToVersion49(sqlStore)
|
||||
UpgradeDatabaseToVersion410(sqlStore)
|
||||
UpgradeDatabaseToVersion50(sqlStore)
|
||||
UpgradeDatabaseToVersion51(sqlStore)
|
||||
UpgradeDatabaseToVersion52(sqlStore)
|
||||
UpgradeDatabaseToVersion53(sqlStore)
|
||||
UpgradeDatabaseToVersion54(sqlStore)
|
||||
UpgradeDatabaseToVersion55(sqlStore)
|
||||
UpgradeDatabaseToVersion56(sqlStore)
|
||||
UpgradeDatabaseToVersion57(sqlStore)
|
||||
UpgradeDatabaseToVersion58(sqlStore)
|
||||
UpgradeDatabaseToVersion59(sqlStore)
|
||||
UpgradeDatabaseToVersion510(sqlStore)
|
||||
UpgradeDatabaseToVersion511(sqlStore)
|
||||
UpgradeDatabaseToVersion512(sqlStore)
|
||||
UpgradeDatabaseToVersion513(sqlStore)
|
||||
UpgradeDatabaseToVersion514(sqlStore)
|
||||
UpgradeDatabaseToVersion515(sqlStore)
|
||||
UpgradeDatabaseToVersion516(sqlStore)
|
||||
upgradeDatabaseToVersion31(sqlStore)
|
||||
upgradeDatabaseToVersion32(sqlStore)
|
||||
upgradeDatabaseToVersion33(sqlStore)
|
||||
upgradeDatabaseToVersion34(sqlStore)
|
||||
upgradeDatabaseToVersion35(sqlStore)
|
||||
upgradeDatabaseToVersion36(sqlStore)
|
||||
upgradeDatabaseToVersion37(sqlStore)
|
||||
upgradeDatabaseToVersion38(sqlStore)
|
||||
upgradeDatabaseToVersion39(sqlStore)
|
||||
upgradeDatabaseToVersion310(sqlStore)
|
||||
upgradeDatabaseToVersion40(sqlStore)
|
||||
upgradeDatabaseToVersion41(sqlStore)
|
||||
upgradeDatabaseToVersion42(sqlStore)
|
||||
upgradeDatabaseToVersion43(sqlStore)
|
||||
upgradeDatabaseToVersion44(sqlStore)
|
||||
upgradeDatabaseToVersion45(sqlStore)
|
||||
upgradeDatabaseToVersion46(sqlStore)
|
||||
upgradeDatabaseToVersion47(sqlStore)
|
||||
upgradeDatabaseToVersion471(sqlStore)
|
||||
upgradeDatabaseToVersion472(sqlStore)
|
||||
upgradeDatabaseToVersion48(sqlStore)
|
||||
upgradeDatabaseToVersion481(sqlStore)
|
||||
upgradeDatabaseToVersion49(sqlStore)
|
||||
upgradeDatabaseToVersion410(sqlStore)
|
||||
upgradeDatabaseToVersion50(sqlStore)
|
||||
upgradeDatabaseToVersion51(sqlStore)
|
||||
upgradeDatabaseToVersion52(sqlStore)
|
||||
upgradeDatabaseToVersion53(sqlStore)
|
||||
upgradeDatabaseToVersion54(sqlStore)
|
||||
upgradeDatabaseToVersion55(sqlStore)
|
||||
upgradeDatabaseToVersion56(sqlStore)
|
||||
upgradeDatabaseToVersion57(sqlStore)
|
||||
upgradeDatabaseToVersion58(sqlStore)
|
||||
upgradeDatabaseToVersion59(sqlStore)
|
||||
upgradeDatabaseToVersion510(sqlStore)
|
||||
upgradeDatabaseToVersion511(sqlStore)
|
||||
upgradeDatabaseToVersion512(sqlStore)
|
||||
upgradeDatabaseToVersion513(sqlStore)
|
||||
upgradeDatabaseToVersion514(sqlStore)
|
||||
upgradeDatabaseToVersion515(sqlStore)
|
||||
upgradeDatabaseToVersion516(sqlStore)
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -187,14 +187,14 @@ func shouldPerformUpgrade(sqlStore SqlStore, currentSchemaVersion string, expect
|
||||
return false
|
||||
}
|
||||
|
||||
func UpgradeDatabaseToVersion31(sqlStore SqlStore) {
|
||||
func upgradeDatabaseToVersion31(sqlStore SqlStore) {
|
||||
if shouldPerformUpgrade(sqlStore, VERSION_3_0_0, VERSION_3_1_0) {
|
||||
sqlStore.CreateColumnIfNotExists("OutgoingWebhooks", "ContentType", "varchar(128)", "varchar(128)", "")
|
||||
saveSchemaVersion(sqlStore, VERSION_3_1_0)
|
||||
}
|
||||
}
|
||||
|
||||
func UpgradeDatabaseToVersion32(sqlStore SqlStore) {
|
||||
func upgradeDatabaseToVersion32(sqlStore SqlStore) {
|
||||
if shouldPerformUpgrade(sqlStore, VERSION_3_1_0, VERSION_3_2_0) {
|
||||
sqlStore.CreateColumnIfNotExists("TeamMembers", "DeleteAt", "bigint(20)", "bigint", "0")
|
||||
|
||||
@@ -208,7 +208,7 @@ func themeMigrationFailed(err error) {
|
||||
os.Exit(EXIT_THEME_MIGRATION)
|
||||
}
|
||||
|
||||
func UpgradeDatabaseToVersion33(sqlStore SqlStore) {
|
||||
func upgradeDatabaseToVersion33(sqlStore SqlStore) {
|
||||
if shouldPerformUpgrade(sqlStore, VERSION_3_2_0, VERSION_3_3_0) {
|
||||
if sqlStore.DoesColumnExist("Users", "ThemeProps") {
|
||||
params := map[string]interface{}{
|
||||
@@ -291,7 +291,7 @@ func UpgradeDatabaseToVersion33(sqlStore SqlStore) {
|
||||
}
|
||||
}
|
||||
|
||||
func UpgradeDatabaseToVersion34(sqlStore SqlStore) {
|
||||
func upgradeDatabaseToVersion34(sqlStore SqlStore) {
|
||||
if shouldPerformUpgrade(sqlStore, VERSION_3_3_0, VERSION_3_4_0) {
|
||||
sqlStore.CreateColumnIfNotExists("Status", "Manual", "BOOLEAN", "BOOLEAN", "0")
|
||||
sqlStore.CreateColumnIfNotExists("Status", "ActiveChannel", "varchar(26)", "varchar(26)", "")
|
||||
@@ -300,7 +300,7 @@ func UpgradeDatabaseToVersion34(sqlStore SqlStore) {
|
||||
}
|
||||
}
|
||||
|
||||
func UpgradeDatabaseToVersion35(sqlStore SqlStore) {
|
||||
func upgradeDatabaseToVersion35(sqlStore SqlStore) {
|
||||
if shouldPerformUpgrade(sqlStore, VERSION_3_4_0, VERSION_3_5_0) {
|
||||
sqlStore.GetMaster().Exec("UPDATE Users SET Roles = 'system_user' WHERE Roles = ''")
|
||||
sqlStore.GetMaster().Exec("UPDATE Users SET Roles = 'system_user system_admin' WHERE Roles = 'system_admin'")
|
||||
@@ -323,7 +323,7 @@ func UpgradeDatabaseToVersion35(sqlStore SqlStore) {
|
||||
}
|
||||
}
|
||||
|
||||
func UpgradeDatabaseToVersion36(sqlStore SqlStore) {
|
||||
func upgradeDatabaseToVersion36(sqlStore SqlStore) {
|
||||
if shouldPerformUpgrade(sqlStore, VERSION_3_5_0, VERSION_3_6_0) {
|
||||
sqlStore.CreateColumnIfNotExists("Posts", "HasReactions", "tinyint", "boolean", "0")
|
||||
|
||||
@@ -340,7 +340,7 @@ func UpgradeDatabaseToVersion36(sqlStore SqlStore) {
|
||||
}
|
||||
}
|
||||
|
||||
func UpgradeDatabaseToVersion37(sqlStore SqlStore) {
|
||||
func upgradeDatabaseToVersion37(sqlStore SqlStore) {
|
||||
if shouldPerformUpgrade(sqlStore, VERSION_3_6_0, VERSION_3_7_0) {
|
||||
// Add EditAt column to Posts
|
||||
sqlStore.CreateColumnIfNotExists("Posts", "EditAt", " bigint", " bigint", "0")
|
||||
@@ -349,7 +349,7 @@ func UpgradeDatabaseToVersion37(sqlStore SqlStore) {
|
||||
}
|
||||
}
|
||||
|
||||
func UpgradeDatabaseToVersion38(sqlStore SqlStore) {
|
||||
func upgradeDatabaseToVersion38(sqlStore SqlStore) {
|
||||
if shouldPerformUpgrade(sqlStore, VERSION_3_7_0, VERSION_3_8_0) {
|
||||
// Add the IsPinned column to posts.
|
||||
sqlStore.CreateColumnIfNotExists("Posts", "IsPinned", "boolean", "boolean", "0")
|
||||
@@ -358,7 +358,7 @@ func UpgradeDatabaseToVersion38(sqlStore SqlStore) {
|
||||
}
|
||||
}
|
||||
|
||||
func UpgradeDatabaseToVersion39(sqlStore SqlStore) {
|
||||
func upgradeDatabaseToVersion39(sqlStore SqlStore) {
|
||||
if shouldPerformUpgrade(sqlStore, VERSION_3_8_0, VERSION_3_9_0) {
|
||||
sqlStore.CreateColumnIfNotExists("OAuthAccessData", "Scope", "varchar(128)", "varchar(128)", model.DEFAULT_SCOPE)
|
||||
sqlStore.RemoveTableIfExists("PasswordRecovery")
|
||||
@@ -367,19 +367,19 @@ func UpgradeDatabaseToVersion39(sqlStore SqlStore) {
|
||||
}
|
||||
}
|
||||
|
||||
func UpgradeDatabaseToVersion310(sqlStore SqlStore) {
|
||||
func upgradeDatabaseToVersion310(sqlStore SqlStore) {
|
||||
if shouldPerformUpgrade(sqlStore, VERSION_3_9_0, VERSION_3_10_0) {
|
||||
saveSchemaVersion(sqlStore, VERSION_3_10_0)
|
||||
}
|
||||
}
|
||||
|
||||
func UpgradeDatabaseToVersion40(sqlStore SqlStore) {
|
||||
func upgradeDatabaseToVersion40(sqlStore SqlStore) {
|
||||
if shouldPerformUpgrade(sqlStore, VERSION_3_10_0, VERSION_4_0_0) {
|
||||
saveSchemaVersion(sqlStore, VERSION_4_0_0)
|
||||
}
|
||||
}
|
||||
|
||||
func UpgradeDatabaseToVersion41(sqlStore SqlStore) {
|
||||
func upgradeDatabaseToVersion41(sqlStore SqlStore) {
|
||||
if shouldPerformUpgrade(sqlStore, VERSION_4_0_0, VERSION_4_1_0) {
|
||||
// Increase maximum length of the Users table Roles column.
|
||||
if sqlStore.GetMaxLengthOfColumnIfExists("Users", "Roles") != "256" {
|
||||
@@ -392,19 +392,19 @@ func UpgradeDatabaseToVersion41(sqlStore SqlStore) {
|
||||
}
|
||||
}
|
||||
|
||||
func UpgradeDatabaseToVersion42(sqlStore SqlStore) {
|
||||
func upgradeDatabaseToVersion42(sqlStore SqlStore) {
|
||||
if shouldPerformUpgrade(sqlStore, VERSION_4_1_0, VERSION_4_2_0) {
|
||||
saveSchemaVersion(sqlStore, VERSION_4_2_0)
|
||||
}
|
||||
}
|
||||
|
||||
func UpgradeDatabaseToVersion43(sqlStore SqlStore) {
|
||||
func upgradeDatabaseToVersion43(sqlStore SqlStore) {
|
||||
if shouldPerformUpgrade(sqlStore, VERSION_4_2_0, VERSION_4_3_0) {
|
||||
saveSchemaVersion(sqlStore, VERSION_4_3_0)
|
||||
}
|
||||
}
|
||||
|
||||
func UpgradeDatabaseToVersion44(sqlStore SqlStore) {
|
||||
func upgradeDatabaseToVersion44(sqlStore SqlStore) {
|
||||
if shouldPerformUpgrade(sqlStore, VERSION_4_3_0, VERSION_4_4_0) {
|
||||
// Add the IsActive column to UserAccessToken.
|
||||
sqlStore.CreateColumnIfNotExists("UserAccessTokens", "IsActive", "boolean", "boolean", "1")
|
||||
@@ -413,13 +413,13 @@ func UpgradeDatabaseToVersion44(sqlStore SqlStore) {
|
||||
}
|
||||
}
|
||||
|
||||
func UpgradeDatabaseToVersion45(sqlStore SqlStore) {
|
||||
func upgradeDatabaseToVersion45(sqlStore SqlStore) {
|
||||
if shouldPerformUpgrade(sqlStore, VERSION_4_4_0, VERSION_4_5_0) {
|
||||
saveSchemaVersion(sqlStore, VERSION_4_5_0)
|
||||
}
|
||||
}
|
||||
|
||||
func UpgradeDatabaseToVersion46(sqlStore SqlStore) {
|
||||
func upgradeDatabaseToVersion46(sqlStore SqlStore) {
|
||||
if shouldPerformUpgrade(sqlStore, VERSION_4_5_0, VERSION_4_6_0) {
|
||||
sqlStore.CreateColumnIfNotExists("IncomingWebhooks", "Username", "varchar(64)", "varchar(64)", "")
|
||||
sqlStore.CreateColumnIfNotExists("IncomingWebhooks", "IconURL", "varchar(1024)", "varchar(1024)", "")
|
||||
@@ -427,7 +427,7 @@ func UpgradeDatabaseToVersion46(sqlStore SqlStore) {
|
||||
}
|
||||
}
|
||||
|
||||
func UpgradeDatabaseToVersion47(sqlStore SqlStore) {
|
||||
func upgradeDatabaseToVersion47(sqlStore SqlStore) {
|
||||
if shouldPerformUpgrade(sqlStore, VERSION_4_6_0, VERSION_4_7_0) {
|
||||
sqlStore.AlterColumnTypeIfExists("Users", "Position", "varchar(128)", "varchar(128)")
|
||||
sqlStore.AlterColumnTypeIfExists("OAuthAuthData", "State", "varchar(1024)", "varchar(1024)")
|
||||
@@ -437,37 +437,37 @@ func UpgradeDatabaseToVersion47(sqlStore SqlStore) {
|
||||
}
|
||||
}
|
||||
|
||||
// If any new instances started with 4.7, they would have the bad Email column on the
|
||||
// ChannelMemberHistory table. So for those cases we need to do an upgrade between
|
||||
// 4.7.0 and 4.7.1
|
||||
func UpgradeDatabaseToVersion471(sqlStore SqlStore) {
|
||||
func upgradeDatabaseToVersion471(sqlStore SqlStore) {
|
||||
// If any new instances started with 4.7, they would have the bad Email column on the
|
||||
// ChannelMemberHistory table. So for those cases we need to do an upgrade between
|
||||
// 4.7.0 and 4.7.1
|
||||
if shouldPerformUpgrade(sqlStore, VERSION_4_7_0, VERSION_4_7_1) {
|
||||
sqlStore.RemoveColumnIfExists("ChannelMemberHistory", "Email")
|
||||
saveSchemaVersion(sqlStore, VERSION_4_7_1)
|
||||
}
|
||||
}
|
||||
|
||||
func UpgradeDatabaseToVersion472(sqlStore SqlStore) {
|
||||
func upgradeDatabaseToVersion472(sqlStore SqlStore) {
|
||||
if shouldPerformUpgrade(sqlStore, VERSION_4_7_1, VERSION_4_7_2) {
|
||||
sqlStore.RemoveIndexIfExists("idx_channels_displayname", "Channels")
|
||||
saveSchemaVersion(sqlStore, VERSION_4_7_2)
|
||||
}
|
||||
}
|
||||
|
||||
func UpgradeDatabaseToVersion48(sqlStore SqlStore) {
|
||||
func upgradeDatabaseToVersion48(sqlStore SqlStore) {
|
||||
if shouldPerformUpgrade(sqlStore, VERSION_4_7_2, VERSION_4_8_0) {
|
||||
saveSchemaVersion(sqlStore, VERSION_4_8_0)
|
||||
}
|
||||
}
|
||||
|
||||
func UpgradeDatabaseToVersion481(sqlStore SqlStore) {
|
||||
func upgradeDatabaseToVersion481(sqlStore SqlStore) {
|
||||
if shouldPerformUpgrade(sqlStore, VERSION_4_8_0, VERSION_4_8_1) {
|
||||
sqlStore.RemoveIndexIfExists("idx_channels_displayname", "Channels")
|
||||
saveSchemaVersion(sqlStore, VERSION_4_8_1)
|
||||
}
|
||||
}
|
||||
|
||||
func UpgradeDatabaseToVersion49(sqlStore SqlStore) {
|
||||
func upgradeDatabaseToVersion49(sqlStore SqlStore) {
|
||||
// This version of Mattermost includes an App-Layer migration which migrates from hard-coded roles configured by
|
||||
// a number of parameters in `config.json` to a `Roles` table in the database. The migration code can be seen
|
||||
// in the file `app/app.go` in the function `DoAdvancedPermissionsMigration()`.
|
||||
@@ -485,7 +485,7 @@ func UpgradeDatabaseToVersion49(sqlStore SqlStore) {
|
||||
}
|
||||
}
|
||||
|
||||
func UpgradeDatabaseToVersion410(sqlStore SqlStore) {
|
||||
func upgradeDatabaseToVersion410(sqlStore SqlStore) {
|
||||
if shouldPerformUpgrade(sqlStore, VERSION_4_9_0, VERSION_4_10_0) {
|
||||
|
||||
sqlStore.RemoveIndexIfExists("Name_2", "Channels")
|
||||
@@ -497,7 +497,7 @@ func UpgradeDatabaseToVersion410(sqlStore SqlStore) {
|
||||
}
|
||||
}
|
||||
|
||||
func UpgradeDatabaseToVersion50(sqlStore SqlStore) {
|
||||
func upgradeDatabaseToVersion50(sqlStore SqlStore) {
|
||||
// This version of Mattermost includes an App-Layer migration which migrates from hard-coded emojis configured
|
||||
// in `config.json` to a `Permission` in the database. The migration code can be seen
|
||||
// in the file `app/app.go` in the function `DoEmojisPermissionsMigration()`.
|
||||
@@ -536,13 +536,13 @@ func UpgradeDatabaseToVersion50(sqlStore SqlStore) {
|
||||
}
|
||||
}
|
||||
|
||||
func UpgradeDatabaseToVersion51(sqlStore SqlStore) {
|
||||
func upgradeDatabaseToVersion51(sqlStore SqlStore) {
|
||||
if shouldPerformUpgrade(sqlStore, VERSION_5_0_0, VERSION_5_1_0) {
|
||||
saveSchemaVersion(sqlStore, VERSION_5_1_0)
|
||||
}
|
||||
}
|
||||
|
||||
func UpgradeDatabaseToVersion52(sqlStore SqlStore) {
|
||||
func upgradeDatabaseToVersion52(sqlStore SqlStore) {
|
||||
if shouldPerformUpgrade(sqlStore, VERSION_5_1_0, VERSION_5_2_0) {
|
||||
sqlStore.CreateColumnIfNotExists("OutgoingWebhooks", "Username", "varchar(64)", "varchar(64)", "")
|
||||
sqlStore.CreateColumnIfNotExists("OutgoingWebhooks", "IconURL", "varchar(1024)", "varchar(1024)", "")
|
||||
@@ -550,13 +550,13 @@ func UpgradeDatabaseToVersion52(sqlStore SqlStore) {
|
||||
}
|
||||
}
|
||||
|
||||
func UpgradeDatabaseToVersion53(sqlStore SqlStore) {
|
||||
func upgradeDatabaseToVersion53(sqlStore SqlStore) {
|
||||
if shouldPerformUpgrade(sqlStore, VERSION_5_2_0, VERSION_5_3_0) {
|
||||
saveSchemaVersion(sqlStore, VERSION_5_3_0)
|
||||
}
|
||||
}
|
||||
|
||||
func UpgradeDatabaseToVersion54(sqlStore SqlStore) {
|
||||
func upgradeDatabaseToVersion54(sqlStore SqlStore) {
|
||||
if shouldPerformUpgrade(sqlStore, VERSION_5_3_0, VERSION_5_4_0) {
|
||||
sqlStore.AlterColumnTypeIfExists("OutgoingWebhooks", "Description", "varchar(500)", "varchar(500)")
|
||||
sqlStore.AlterColumnTypeIfExists("IncomingWebhooks", "Description", "varchar(500)", "varchar(500)")
|
||||
@@ -569,13 +569,13 @@ func UpgradeDatabaseToVersion54(sqlStore SqlStore) {
|
||||
}
|
||||
}
|
||||
|
||||
func UpgradeDatabaseToVersion55(sqlStore SqlStore) {
|
||||
func upgradeDatabaseToVersion55(sqlStore SqlStore) {
|
||||
if shouldPerformUpgrade(sqlStore, VERSION_5_4_0, VERSION_5_5_0) {
|
||||
saveSchemaVersion(sqlStore, VERSION_5_5_0)
|
||||
}
|
||||
}
|
||||
|
||||
func UpgradeDatabaseToVersion56(sqlStore SqlStore) {
|
||||
func upgradeDatabaseToVersion56(sqlStore SqlStore) {
|
||||
if shouldPerformUpgrade(sqlStore, VERSION_5_5_0, VERSION_5_6_0) {
|
||||
sqlStore.CreateColumnIfNotExists("PluginKeyValueStore", "ExpireAt", "bigint(20)", "bigint", "0")
|
||||
|
||||
@@ -595,15 +595,15 @@ func UpgradeDatabaseToVersion56(sqlStore SqlStore) {
|
||||
|
||||
}
|
||||
|
||||
func UpgradeDatabaseToVersion57(sqlStore SqlStore) {
|
||||
func upgradeDatabaseToVersion57(sqlStore SqlStore) {
|
||||
if shouldPerformUpgrade(sqlStore, VERSION_5_6_0, VERSION_5_7_0) {
|
||||
saveSchemaVersion(sqlStore, VERSION_5_7_0)
|
||||
}
|
||||
}
|
||||
|
||||
func UpgradeDatabaseToVersion58(sqlStore SqlStore) {
|
||||
func upgradeDatabaseToVersion58(sqlStore SqlStore) {
|
||||
if shouldPerformUpgrade(sqlStore, VERSION_5_7_0, VERSION_5_8_0) {
|
||||
// idx_channels_txt was removed in `UpgradeDatabaseToVersion50`, but merged as part of
|
||||
// idx_channels_txt was removed in `upgradeDatabaseToVersion50`, but merged as part of
|
||||
// v5.1, so the migration wouldn't apply to anyone upgrading from v5.0. Remove it again to
|
||||
// bring the upgraded (from v5.0) and fresh install schemas back in sync.
|
||||
sqlStore.RemoveIndexIfExists("idx_channels_txt", "Channels")
|
||||
@@ -621,13 +621,13 @@ func UpgradeDatabaseToVersion58(sqlStore SqlStore) {
|
||||
}
|
||||
}
|
||||
|
||||
func UpgradeDatabaseToVersion59(sqlStore SqlStore) {
|
||||
func upgradeDatabaseToVersion59(sqlStore SqlStore) {
|
||||
if shouldPerformUpgrade(sqlStore, VERSION_5_8_0, VERSION_5_9_0) {
|
||||
saveSchemaVersion(sqlStore, VERSION_5_9_0)
|
||||
}
|
||||
}
|
||||
|
||||
func UpgradeDatabaseToVersion510(sqlStore SqlStore) {
|
||||
func upgradeDatabaseToVersion510(sqlStore SqlStore) {
|
||||
if shouldPerformUpgrade(sqlStore, VERSION_5_9_0, VERSION_5_10_0) {
|
||||
sqlStore.CreateColumnIfNotExistsNoDefault("Channels", "GroupConstrained", "tinyint(4)", "boolean")
|
||||
sqlStore.CreateColumnIfNotExistsNoDefault("Teams", "GroupConstrained", "tinyint(4)", "boolean")
|
||||
@@ -639,7 +639,7 @@ func UpgradeDatabaseToVersion510(sqlStore SqlStore) {
|
||||
}
|
||||
}
|
||||
|
||||
func UpgradeDatabaseToVersion511(sqlStore SqlStore) {
|
||||
func upgradeDatabaseToVersion511(sqlStore SqlStore) {
|
||||
if shouldPerformUpgrade(sqlStore, VERSION_5_10_0, VERSION_5_11_0) {
|
||||
// Enforce all teams have an InviteID set
|
||||
var teams []*model.Team
|
||||
@@ -658,7 +658,7 @@ func UpgradeDatabaseToVersion511(sqlStore SqlStore) {
|
||||
}
|
||||
}
|
||||
|
||||
func UpgradeDatabaseToVersion512(sqlStore SqlStore) {
|
||||
func upgradeDatabaseToVersion512(sqlStore SqlStore) {
|
||||
if shouldPerformUpgrade(sqlStore, VERSION_5_11_0, VERSION_5_12_0) {
|
||||
sqlStore.CreateColumnIfNotExistsNoDefault("TeamMembers", "SchemeGuest", "boolean", "boolean")
|
||||
sqlStore.CreateColumnIfNotExistsNoDefault("ChannelMembers", "SchemeGuest", "boolean", "boolean")
|
||||
@@ -674,7 +674,7 @@ func UpgradeDatabaseToVersion512(sqlStore SqlStore) {
|
||||
}
|
||||
}
|
||||
|
||||
func UpgradeDatabaseToVersion513(sqlStore SqlStore) {
|
||||
func upgradeDatabaseToVersion513(sqlStore SqlStore) {
|
||||
if shouldPerformUpgrade(sqlStore, VERSION_5_12_0, VERSION_5_13_0) {
|
||||
// The previous jobs ran once per minute, cluttering the Jobs table with somewhat useless entries. Clean that up.
|
||||
sqlStore.GetMaster().Exec("DELETE FROM Jobs WHERE Type = 'plugins'")
|
||||
@@ -683,19 +683,19 @@ func UpgradeDatabaseToVersion513(sqlStore SqlStore) {
|
||||
}
|
||||
}
|
||||
|
||||
func UpgradeDatabaseToVersion514(sqlStore SqlStore) {
|
||||
func upgradeDatabaseToVersion514(sqlStore SqlStore) {
|
||||
if shouldPerformUpgrade(sqlStore, VERSION_5_13_0, VERSION_5_14_0) {
|
||||
saveSchemaVersion(sqlStore, VERSION_5_14_0)
|
||||
}
|
||||
}
|
||||
|
||||
func UpgradeDatabaseToVersion515(sqlStore SqlStore) {
|
||||
func upgradeDatabaseToVersion515(sqlStore SqlStore) {
|
||||
if shouldPerformUpgrade(sqlStore, VERSION_5_14_0, VERSION_5_15_0) {
|
||||
saveSchemaVersion(sqlStore, VERSION_5_15_0)
|
||||
}
|
||||
}
|
||||
|
||||
func UpgradeDatabaseToVersion516(sqlStore SqlStore) {
|
||||
func upgradeDatabaseToVersion516(sqlStore SqlStore) {
|
||||
if shouldPerformUpgrade(sqlStore, VERSION_5_15_0, VERSION_5_16_0) {
|
||||
if sqlStore.DriverName() == model.DATABASE_DRIVER_POSTGRES {
|
||||
sqlStore.GetMaster().Exec("ALTER TABLE Tokens ALTER COLUMN Extra TYPE varchar(2048)")
|
||||
|
||||
@@ -15,41 +15,41 @@ func TestStoreUpgrade(t *testing.T) {
|
||||
sqlStore := ss.(SqlStore)
|
||||
|
||||
t.Run("invalid currentModelVersion", func(t *testing.T) {
|
||||
err := UpgradeDatabase(sqlStore, "notaversion")
|
||||
err := upgradeDatabase(sqlStore, "notaversion")
|
||||
require.EqualError(t, err, "failed to parse current model version notaversion: No Major.Minor.Patch elements found")
|
||||
})
|
||||
|
||||
t.Run("upgrade from invalid version", func(t *testing.T) {
|
||||
saveSchemaVersion(sqlStore, "invalid")
|
||||
err := UpgradeDatabase(sqlStore, "5.8.0")
|
||||
err := upgradeDatabase(sqlStore, "5.8.0")
|
||||
require.EqualError(t, err, "failed to parse database schema version invalid: No Major.Minor.Patch elements found")
|
||||
require.Equal(t, "invalid", sqlStore.GetCurrentSchemaVersion())
|
||||
})
|
||||
|
||||
t.Run("upgrade from unsupported version", func(t *testing.T) {
|
||||
saveSchemaVersion(sqlStore, "2.0.0")
|
||||
err := UpgradeDatabase(sqlStore, "5.8.0")
|
||||
err := upgradeDatabase(sqlStore, "5.8.0")
|
||||
require.EqualError(t, err, "Database schema version 2.0.0 is no longer supported. This Mattermost server supports automatic upgrades from schema version 3.0.0 through schema version 5.8.0. Please manually upgrade to at least version 3.0.0 before continuing.")
|
||||
require.Equal(t, "2.0.0", sqlStore.GetCurrentSchemaVersion())
|
||||
})
|
||||
|
||||
t.Run("upgrade from earliest supported version", func(t *testing.T) {
|
||||
saveSchemaVersion(sqlStore, VERSION_3_0_0)
|
||||
err := UpgradeDatabase(sqlStore, CURRENT_SCHEMA_VERSION)
|
||||
err := upgradeDatabase(sqlStore, CURRENT_SCHEMA_VERSION)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, CURRENT_SCHEMA_VERSION, sqlStore.GetCurrentSchemaVersion())
|
||||
})
|
||||
|
||||
t.Run("upgrade from no existing version", func(t *testing.T) {
|
||||
saveSchemaVersion(sqlStore, "")
|
||||
err := UpgradeDatabase(sqlStore, CURRENT_SCHEMA_VERSION)
|
||||
err := upgradeDatabase(sqlStore, CURRENT_SCHEMA_VERSION)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, CURRENT_SCHEMA_VERSION, sqlStore.GetCurrentSchemaVersion())
|
||||
})
|
||||
|
||||
t.Run("upgrade schema running earlier minor version", func(t *testing.T) {
|
||||
saveSchemaVersion(sqlStore, "5.1.0")
|
||||
err := UpgradeDatabase(sqlStore, "5.8.0")
|
||||
err := upgradeDatabase(sqlStore, "5.8.0")
|
||||
require.NoError(t, err)
|
||||
// Assert CURRENT_SCHEMA_VERSION, not 5.8.0, since the migrations will move
|
||||
// past 5.8.0 regardless of the input parameter.
|
||||
@@ -58,21 +58,21 @@ func TestStoreUpgrade(t *testing.T) {
|
||||
|
||||
t.Run("upgrade schema running later minor version", func(t *testing.T) {
|
||||
saveSchemaVersion(sqlStore, "5.29.0")
|
||||
err := UpgradeDatabase(sqlStore, "5.8.0")
|
||||
err := upgradeDatabase(sqlStore, "5.8.0")
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "5.29.0", sqlStore.GetCurrentSchemaVersion())
|
||||
})
|
||||
|
||||
t.Run("upgrade schema running earlier major version", func(t *testing.T) {
|
||||
saveSchemaVersion(sqlStore, "4.1.0")
|
||||
err := UpgradeDatabase(sqlStore, CURRENT_SCHEMA_VERSION)
|
||||
err := upgradeDatabase(sqlStore, CURRENT_SCHEMA_VERSION)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, CURRENT_SCHEMA_VERSION, sqlStore.GetCurrentSchemaVersion())
|
||||
})
|
||||
|
||||
t.Run("upgrade schema running later major version", func(t *testing.T) {
|
||||
saveSchemaVersion(sqlStore, "6.0.0")
|
||||
err := UpgradeDatabase(sqlStore, "5.8.0")
|
||||
err := upgradeDatabase(sqlStore, "5.8.0")
|
||||
require.EqualError(t, err, "Database schema version 6.0.0 is not supported. This Mattermost server supports only >=5.8.0, <6.0.0. Please upgrade to at least version 6.0.0 before continuing.")
|
||||
require.Equal(t, "6.0.0", sqlStore.GetCurrentSchemaVersion())
|
||||
})
|
||||
|
||||
@@ -129,7 +129,7 @@ type ChannelStore interface {
|
||||
GetByNames(team_id string, names []string, allowFromCache bool) ([]*model.Channel, *model.AppError)
|
||||
GetByNameIncludeDeleted(team_id string, name string, allowFromCache bool) (*model.Channel, *model.AppError)
|
||||
GetDeletedByName(team_id string, name string) (*model.Channel, *model.AppError)
|
||||
GetDeleted(team_id string, offset int, limit int) (*model.ChannelList, *model.AppError)
|
||||
GetDeleted(team_id string, offset int, limit int, userId string) (*model.ChannelList, *model.AppError)
|
||||
GetChannels(teamId string, userId string, includeDeleted bool) (*model.ChannelList, *model.AppError)
|
||||
GetAllChannels(page, perPage int, opts ChannelSearchOpts) (*model.ChannelListWithTeamData, *model.AppError)
|
||||
GetAllChannelsCount(opts ChannelSearchOpts) (int64, *model.AppError)
|
||||
@@ -175,6 +175,7 @@ type ChannelStore interface {
|
||||
AutocompleteInTeamForSearch(teamId string, userId string, term string, includeDeleted bool) (*model.ChannelList, *model.AppError)
|
||||
SearchAllChannels(term string, opts ChannelSearchOpts) (*model.ChannelListWithTeamData, *model.AppError)
|
||||
SearchInTeam(teamId string, term string, includeDeleted bool) (*model.ChannelList, *model.AppError)
|
||||
SearchArchivedInTeam(teamId string, term string, userId string) (*model.ChannelList, *model.AppError)
|
||||
SearchForUserInTeam(userId string, teamId string, term string, includeDeleted bool) (*model.ChannelList, *model.AppError)
|
||||
SearchMore(userId string, teamId string, term string) (*model.ChannelList, *model.AppError)
|
||||
SearchGroupChannels(userId, term string) (*model.ChannelList, *model.AppError)
|
||||
|
||||
@@ -687,13 +687,15 @@ func testChannelStoreGetDeleted(t *testing.T, ss store.Store) {
|
||||
o1.Name = "zz" + model.NewId() + "b"
|
||||
o1.Type = model.CHANNEL_OPEN
|
||||
|
||||
userId := model.NewId()
|
||||
|
||||
_, err := ss.Channel().Save(&o1, -1)
|
||||
require.Nil(t, err)
|
||||
|
||||
err = ss.Channel().Delete(o1.Id, model.GetMillis())
|
||||
require.Nil(t, err, "channel should have been deleted")
|
||||
|
||||
list, err := ss.Channel().GetDeleted(o1.TeamId, 0, 100)
|
||||
list, err := ss.Channel().GetDeleted(o1.TeamId, 0, 100, userId)
|
||||
require.Nil(t, err, err)
|
||||
require.Len(t, *list, 1, "wrong list")
|
||||
require.Equal(t, o1.Name, (*list)[0].Name, "missing channel")
|
||||
@@ -706,7 +708,7 @@ func testChannelStoreGetDeleted(t *testing.T, ss store.Store) {
|
||||
_, err = ss.Channel().Save(&o2, -1)
|
||||
require.Nil(t, err)
|
||||
|
||||
list, err = ss.Channel().GetDeleted(o1.TeamId, 0, 100)
|
||||
list, err = ss.Channel().GetDeleted(o1.TeamId, 0, 100, userId)
|
||||
require.Nil(t, err, err)
|
||||
require.Len(t, *list, 1, "wrong list")
|
||||
|
||||
@@ -722,15 +724,15 @@ func testChannelStoreGetDeleted(t *testing.T, ss store.Store) {
|
||||
err = ss.Channel().Delete(o3.Id, model.GetMillis())
|
||||
require.Nil(t, err, "channel should have been deleted")
|
||||
|
||||
list, err = ss.Channel().GetDeleted(o1.TeamId, 0, 100)
|
||||
list, err = ss.Channel().GetDeleted(o1.TeamId, 0, 100, userId)
|
||||
require.Nil(t, err, err)
|
||||
require.Len(t, *list, 2, "wrong list length")
|
||||
|
||||
list, err = ss.Channel().GetDeleted(o1.TeamId, 0, 1)
|
||||
list, err = ss.Channel().GetDeleted(o1.TeamId, 0, 1, userId)
|
||||
require.Nil(t, err, err)
|
||||
require.Len(t, *list, 1, "wrong list length")
|
||||
|
||||
list, err = ss.Channel().GetDeleted(o1.TeamId, 1, 1)
|
||||
list, err = ss.Channel().GetDeleted(o1.TeamId, 1, 1, userId)
|
||||
require.Nil(t, err, err)
|
||||
require.Len(t, *list, 1, "wrong list length")
|
||||
|
||||
|
||||
@@ -647,7 +647,7 @@ func (_m *ChannelStore) GetChannelsByScheme(schemeId string, offset int, limit i
|
||||
}
|
||||
|
||||
// GetDeleted provides a mock function with given fields: team_id, offset, limit
|
||||
func (_m *ChannelStore) GetDeleted(team_id string, offset int, limit int) (*model.ChannelList, *model.AppError) {
|
||||
func (_m *ChannelStore) GetDeleted(team_id string, offset int, limit int, userId string) (*model.ChannelList, *model.AppError) {
|
||||
ret := _m.Called(team_id, offset, limit)
|
||||
|
||||
var r0 *model.ChannelList
|
||||
@@ -1539,6 +1539,31 @@ func (_m *ChannelStore) SearchInTeam(teamId string, term string, includeDeleted
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// SearchArchivedInTeam provides a mock function with given fields: teamId, term, userId
|
||||
func (_m *ChannelStore) SearchArchivedInTeam(teamId string, term string, userId string) (*model.ChannelList, *model.AppError) {
|
||||
ret := _m.Called(teamId, term, userId)
|
||||
|
||||
var r0 *model.ChannelList
|
||||
if rf, ok := ret.Get(0).(func(string, string, string) *model.ChannelList); ok {
|
||||
r0 = rf(teamId, term, userId)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*model.ChannelList)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 *model.AppError
|
||||
if rf, ok := ret.Get(1).(func(string, string, string) *model.AppError); ok {
|
||||
r1 = rf(teamId, term, userId)
|
||||
} else {
|
||||
if ret.Get(1) != nil {
|
||||
r1 = ret.Get(1).(*model.AppError)
|
||||
}
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// SearchMore provides a mock function with given fields: userId, teamId, term
|
||||
func (_m *ChannelStore) SearchMore(userId string, teamId string, term string) (*model.ChannelList, *model.AppError) {
|
||||
ret := _m.Called(userId, teamId, term)
|
||||
|
||||
@@ -904,10 +904,10 @@ func (s *TimerLayerChannelStore) GetChannelsByScheme(schemeId string, offset int
|
||||
return resultVar0, resultVar1
|
||||
}
|
||||
|
||||
func (s *TimerLayerChannelStore) GetDeleted(team_id string, offset int, limit int) (*model.ChannelList, *model.AppError) {
|
||||
func (s *TimerLayerChannelStore) GetDeleted(team_id string, offset int, limit int, userId string) (*model.ChannelList, *model.AppError) {
|
||||
start := timemodule.Now()
|
||||
|
||||
resultVar0, resultVar1 := s.ChannelStore.GetDeleted(team_id, offset, limit)
|
||||
resultVar0, resultVar1 := s.ChannelStore.GetDeleted(team_id, offset, limit, userId)
|
||||
|
||||
elapsed := float64(timemodule.Since(start)) / float64(timemodule.Second)
|
||||
if s.Root.Metrics != nil {
|
||||
|
||||
@@ -292,7 +292,7 @@
|
||||
{{template "unsupported_browser-system_browser" .Props.SystemBrowser}}
|
||||
{{end}}
|
||||
<div class='learn-more-about-sup'>
|
||||
<a href='https://docs.mattermost.com/install/requirements.html#pc-web' target='_blank'>{{.Props.LearnMoreString}}</a>
|
||||
<a href='https://docs.mattermost.com/install/requirements.html#pc-web' target='_blank' rel='noopener noreferrer'>{{.Props.LearnMoreString}}</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -14,26 +14,20 @@ import (
|
||||
|
||||
func TestValidateLicense(t *testing.T) {
|
||||
b1 := []byte("junk")
|
||||
if ok, _ := ValidateLicense(b1); ok {
|
||||
t.Fatal("should have failed - bad license")
|
||||
}
|
||||
ok, _ := ValidateLicense(b1)
|
||||
require.False(t, ok, "should have failed - bad license")
|
||||
|
||||
b2 := []byte("junkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunk")
|
||||
if ok, _ := ValidateLicense(b2); ok {
|
||||
t.Fatal("should have failed - bad license")
|
||||
}
|
||||
ok, _ = ValidateLicense(b2)
|
||||
require.False(t, ok, "should have failed - bad license")
|
||||
}
|
||||
|
||||
func TestGetLicenseFileLocation(t *testing.T) {
|
||||
fileName := GetLicenseFileLocation("")
|
||||
if len(fileName) == 0 {
|
||||
t.Fatal("invalid default file name")
|
||||
}
|
||||
require.NotEmpty(t, fileName, "invalid default file name")
|
||||
|
||||
fileName = GetLicenseFileLocation("mattermost.mattermost-license")
|
||||
if fileName != "mattermost.mattermost-license" {
|
||||
t.Fatal("invalid file name")
|
||||
}
|
||||
require.Equal(t, fileName, "mattermost.mattermost-license", "invalid file name")
|
||||
}
|
||||
|
||||
func TestGetLicenseFileFromDisk(t *testing.T) {
|
||||
|
||||
@@ -5,6 +5,8 @@ package utils
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestUrlEncode(t *testing.T) {
|
||||
@@ -12,24 +14,15 @@ func TestUrlEncode(t *testing.T) {
|
||||
toEncode := "testing 1 2 3"
|
||||
encoded := UrlEncode(toEncode)
|
||||
|
||||
if encoded != "testing%201%202%203" {
|
||||
t.Log(encoded)
|
||||
t.Fatal("should be equal")
|
||||
}
|
||||
require.Equal(t, encoded, "testing%201%202%203")
|
||||
|
||||
toEncode = "testing123"
|
||||
encoded = UrlEncode(toEncode)
|
||||
|
||||
if encoded != "testing123" {
|
||||
t.Log(encoded)
|
||||
t.Fatal("should be equal")
|
||||
}
|
||||
require.Equal(t, encoded, "testing123")
|
||||
|
||||
toEncode = "testing$#~123"
|
||||
encoded = UrlEncode(toEncode)
|
||||
|
||||
if encoded != "testing%24%23~123" {
|
||||
t.Log(encoded)
|
||||
t.Fatal("should be equal")
|
||||
}
|
||||
require.Equal(t, encoded, "testing%24%23~123")
|
||||
}
|
||||
|
||||
42
vendor/github.com/minio/minio-go/v6/api-list.go
сгенерированный
поставляемый
42
vendor/github.com/minio/minio-go/v6/api-list.go
сгенерированный
поставляемый
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* MinIO Go Library for Amazon S3 Compatible Cloud Storage
|
||||
* Copyright 2015-2017 MinIO, Inc.
|
||||
* Copyright 2015-2019 MinIO, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -208,12 +208,10 @@ func (c Client) listObjectsV2Query(bucketName, objectPrefix, continuationToken s
|
||||
urlValues.Set("fetch-owner", "true")
|
||||
}
|
||||
|
||||
// maxkeys should default to 1000 or less.
|
||||
if maxkeys == 0 || maxkeys > 1000 {
|
||||
maxkeys = 1000
|
||||
}
|
||||
// Set max keys.
|
||||
urlValues.Set("max-keys", fmt.Sprintf("%d", maxkeys))
|
||||
if maxkeys > 0 {
|
||||
urlValues.Set("max-keys", fmt.Sprintf("%d", maxkeys))
|
||||
}
|
||||
|
||||
// Set start-after
|
||||
if startAfter != "" {
|
||||
@@ -248,15 +246,15 @@ func (c Client) listObjectsV2Query(bucketName, objectPrefix, continuationToken s
|
||||
return listBucketResult, errors.New("Truncated response should have continuation token set")
|
||||
}
|
||||
|
||||
for _, obj := range listBucketResult.Contents {
|
||||
obj.Key, err = url.QueryUnescape(obj.Key)
|
||||
for i, obj := range listBucketResult.Contents {
|
||||
listBucketResult.Contents[i].Key, err = url.QueryUnescape(obj.Key)
|
||||
if err != nil {
|
||||
return listBucketResult, err
|
||||
}
|
||||
}
|
||||
|
||||
for _, obj := range listBucketResult.CommonPrefixes {
|
||||
obj.Prefix, err = url.QueryUnescape(obj.Prefix)
|
||||
for i, obj := range listBucketResult.CommonPrefixes {
|
||||
listBucketResult.CommonPrefixes[i].Prefix, err = url.QueryUnescape(obj.Prefix)
|
||||
if err != nil {
|
||||
return listBucketResult, err
|
||||
}
|
||||
@@ -401,12 +399,10 @@ func (c Client) listObjectsQuery(bucketName, objectPrefix, objectMarker, delimit
|
||||
urlValues.Set("marker", objectMarker)
|
||||
}
|
||||
|
||||
// maxkeys should default to 1000 or less.
|
||||
if maxkeys == 0 || maxkeys > 1000 {
|
||||
maxkeys = 1000
|
||||
}
|
||||
// Set max keys.
|
||||
urlValues.Set("max-keys", fmt.Sprintf("%d", maxkeys))
|
||||
if maxkeys > 0 {
|
||||
urlValues.Set("max-keys", fmt.Sprintf("%d", maxkeys))
|
||||
}
|
||||
|
||||
// Always set encoding-type
|
||||
urlValues.Set("encoding-type", "url")
|
||||
@@ -433,15 +429,15 @@ func (c Client) listObjectsQuery(bucketName, objectPrefix, objectMarker, delimit
|
||||
return listBucketResult, err
|
||||
}
|
||||
|
||||
for _, obj := range listBucketResult.Contents {
|
||||
obj.Key, err = url.QueryUnescape(obj.Key)
|
||||
for i, obj := range listBucketResult.Contents {
|
||||
listBucketResult.Contents[i].Key, err = url.QueryUnescape(obj.Key)
|
||||
if err != nil {
|
||||
return listBucketResult, err
|
||||
}
|
||||
}
|
||||
|
||||
for _, obj := range listBucketResult.CommonPrefixes {
|
||||
obj.Prefix, err = url.QueryUnescape(obj.Prefix)
|
||||
for i, obj := range listBucketResult.CommonPrefixes {
|
||||
listBucketResult.CommonPrefixes[i].Prefix, err = url.QueryUnescape(obj.Prefix)
|
||||
if err != nil {
|
||||
return listBucketResult, err
|
||||
}
|
||||
@@ -642,15 +638,15 @@ func (c Client) listMultipartUploadsQuery(bucketName, keyMarker, uploadIDMarker,
|
||||
return listMultipartUploadsResult, err
|
||||
}
|
||||
|
||||
for _, obj := range listMultipartUploadsResult.Uploads {
|
||||
obj.Key, err = url.QueryUnescape(obj.Key)
|
||||
for i, obj := range listMultipartUploadsResult.Uploads {
|
||||
listMultipartUploadsResult.Uploads[i].Key, err = url.QueryUnescape(obj.Key)
|
||||
if err != nil {
|
||||
return listMultipartUploadsResult, err
|
||||
}
|
||||
}
|
||||
|
||||
for _, obj := range listMultipartUploadsResult.CommonPrefixes {
|
||||
obj.Prefix, err = url.QueryUnescape(obj.Prefix)
|
||||
for i, obj := range listMultipartUploadsResult.CommonPrefixes {
|
||||
listMultipartUploadsResult.CommonPrefixes[i].Prefix, err = url.QueryUnescape(obj.Prefix)
|
||||
if err != nil {
|
||||
return listMultipartUploadsResult, err
|
||||
}
|
||||
|
||||
11
vendor/github.com/minio/minio-go/v6/api-notification.go
сгенерированный
поставляемый
11
vendor/github.com/minio/minio-go/v6/api-notification.go
сгенерированный
поставляемый
@@ -200,6 +200,11 @@ func (c Client) ListenBucketNotification(bucketName, prefix, suffix string, even
|
||||
for bio.Scan() {
|
||||
var notificationInfo NotificationInfo
|
||||
if err = json.Unmarshal(bio.Bytes(), ¬ificationInfo); err != nil {
|
||||
// Unexpected error during json unmarshal, send
|
||||
// the error to caller for actionable as needed.
|
||||
notificationInfoCh <- NotificationInfo{
|
||||
Err: err,
|
||||
}
|
||||
closeResponse(resp)
|
||||
continue
|
||||
}
|
||||
@@ -211,7 +216,11 @@ func (c Client) ListenBucketNotification(bucketName, prefix, suffix string, even
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if err = bio.Err(); err != nil {
|
||||
notificationInfoCh <- NotificationInfo{
|
||||
Err: err,
|
||||
}
|
||||
}
|
||||
// Close current connection before looping further.
|
||||
closeResponse(resp)
|
||||
}
|
||||
|
||||
2
vendor/github.com/minio/minio-go/v6/api.go
сгенерированный
поставляемый
2
vendor/github.com/minio/minio-go/v6/api.go
сгенерированный
поставляемый
@@ -104,7 +104,7 @@ type Options struct {
|
||||
// Global constants.
|
||||
const (
|
||||
libraryName = "minio-go"
|
||||
libraryVersion = "v6.0.38"
|
||||
libraryVersion = "v6.0.40"
|
||||
)
|
||||
|
||||
// User Agent should always following the below style.
|
||||
|
||||
3
vendor/github.com/minio/minio-go/v6/go.sum
сгенерированный
поставляемый
3
vendor/github.com/minio/minio-go/v6/go.sum
сгенерированный
поставляемый
@@ -1,3 +1,4 @@
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=
|
||||
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
||||
@@ -10,6 +11,7 @@ github.com/minio/sha256-simd v0.1.1 h1:5QHSlgo3nt5yKOJrC7W8w7X+NFl8cMPZm96iu8kKU
|
||||
github.com/minio/sha256-simd v0.1.1/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM=
|
||||
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
|
||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
|
||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||
@@ -18,6 +20,7 @@ github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1
|
||||
github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a h1:pa8hGb/2YqsZKovtsgrwcDH1RZhVbTKCjLp47XpqCDs=
|
||||
github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190513172903-22d7a77e9e5f h1:R423Cnkcp5JABoeemiGEPlt9tHXFfw5kvc0yqlxRPWo=
|
||||
|
||||
2
vendor/modules.txt
поставляемый
2
vendor/modules.txt
поставляемый
@@ -132,7 +132,7 @@ github.com/mattn/go-sqlite3
|
||||
github.com/matttproud/golang_protobuf_extensions/pbutil
|
||||
# github.com/miekg/dns v1.1.19
|
||||
github.com/miekg/dns
|
||||
# github.com/minio/minio-go/v6 v6.0.38
|
||||
# github.com/minio/minio-go/v6 v6.0.40
|
||||
github.com/minio/minio-go/v6
|
||||
github.com/minio/minio-go/v6/pkg/credentials
|
||||
github.com/minio/minio-go/v6/pkg/encrypt
|
||||
|
||||
@@ -60,7 +60,7 @@ func (w *Web) InitStatic() {
|
||||
func root(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
if !CheckClientCompatability(r.UserAgent()) {
|
||||
renderUnsuppportedBrowser(c.App, w, r)
|
||||
renderUnsupportedBrowser(c.App, w, r)
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -44,7 +44,7 @@ type SystemBrowser struct {
|
||||
MakeDefaultString string
|
||||
}
|
||||
|
||||
func renderUnsuppportedBrowser(app *app.App, w http.ResponseWriter, r *http.Request) {
|
||||
func renderUnsupportedBrowser(app *app.App, w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Cache-Control", "no-store")
|
||||
page := utils.NewHTMLTemplate(app.HTMLTemplates(), "unsupported_browser")
|
||||
|
||||
|
||||
Ссылка в новой задаче
Block a user