* Migrate feature/wrangler to mono-repo

* Add wrangler files

* Fix linters, types, etc

* Fix snapshots

* Fix playwright

* Fix pipelines

* Fix more pipeline

* Fixes for pipelines

* More changes for pipeline

* Fix types

* Add support for a feature flag, but leave it defaulted on for spinwick usage for now

* Update snapshot

* fix js error when removing last value of multiselect, support CSV marshaling to string array for textsetting

* Fix linter

* Remove TODO

* Remove another TODO

* fix tests

* Fix i18n

* Add server tests

* Fix linter

* Fix linter

* Use proper icon for dot menu

* Update snapshot

* Add Cypress UI tests for various entrypoints to move thread modal, split SCSS out from forward post into its own thing

* clean up

* fix linter

* More cleanup

* Revert files to master

* Fix linter for e2e tests

* Make ForwardPostChannelSelect channel types configurable with a prop

* Add missing return

* Fixes from PR feedback

* First batch of PR Feedback

* Another batch of PR changes

* Fix linter

* Update snapshots

* Wrangler system messages are translated to each user's locale

* Initially translate Wrangler into system locale rather than initiating user

* More fixes for PR Feedback

* Fix some server tests

* More updates with master. Fixes around pipelines. Enforce Enterprise license on front/back end

* Add tests for dot_menu

* More pipeline fixes

* Fix e2etests prettier

* Update cypress tests, change occurrences of 'Wrangler' with 'Move Thread'

* Fix linter

* Remove enterprise lock

* A couple more occurrences of wrangler strings, and one more enterprise lock

* Fix server tests

* Fix i18n

* Fix e2e linter

* Feature flag shouldn't be on by default

* Enable move threads feature in smoke tests (#25657)

* enable move threads feature
* add @prod tag

* Fix move_thread_from_public_channel e2e test

* Fix e2e style

---------

Co-authored-by: Mattermost Build <build@mattermost.com>
Co-authored-by: yasserfaraazkhan <attitude3cena.yf@gmail.com>
Этот коммит содержится в:
Nick Misasi
2023-12-11 15:27:34 -05:00
коммит произвёл GitHub
родитель bfb8320afd
Коммит f0a336ba07
56 изменённых файлов: 3107 добавлений и 16 удалений

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

@@ -4184,6 +4184,21 @@ func (c *Client4) GetPostsBefore(ctx context.Context, channelId, postId string,
return &list, BuildResponse(r), nil
}
// MoveThread moves a thread based on provided post id, and channel id string.
func (c *Client4) MoveThread(ctx context.Context, postId string, params *MoveThreadParams) (*Response, error) {
js, err := json.Marshal(params)
if err != nil {
return nil, NewAppError("MoveThread", "api.marshal_error", nil, "", http.StatusInternalServerError).Wrap(err)
}
r, err := c.DoAPIPost(ctx, c.postRoute(postId)+"/move", string(js))
if err != nil {
return BuildResponse(r), err
}
defer closeBody(r)
return BuildResponse(r), nil
}
// GetPostsAroundLastUnread gets a list of posts around last unread post by a user in a channel.
func (c *Client4) GetPostsAroundLastUnread(ctx context.Context, userId, channelId string, limitBefore, limitAfter int, collapsedThreads bool) (*PostList, *Response, error) {
query := fmt.Sprintf("?limit_before=%v&limit_after=%v", limitBefore, limitAfter)

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

@@ -3108,6 +3108,51 @@ func (s *PluginSettings) SetDefaults(ls LogSettings) {
}
}
type WranglerSettings struct {
PermittedWranglerRoles []string
AllowedEmailDomain []string
MoveThreadMaxCount *int64
MoveThreadToAnotherTeamEnable *bool
MoveThreadFromPrivateChannelEnable *bool
MoveThreadFromDirectMessageChannelEnable *bool
MoveThreadFromGroupMessageChannelEnable *bool
}
func (w *WranglerSettings) SetDefaults() {
if w.PermittedWranglerRoles == nil {
w.PermittedWranglerRoles = make([]string, 0)
}
if w.AllowedEmailDomain == nil {
w.AllowedEmailDomain = make([]string, 0)
}
if w.MoveThreadMaxCount == nil {
w.MoveThreadMaxCount = NewInt64(100)
}
if w.MoveThreadToAnotherTeamEnable == nil {
w.MoveThreadToAnotherTeamEnable = NewBool(false)
}
if w.MoveThreadFromPrivateChannelEnable == nil {
w.MoveThreadFromPrivateChannelEnable = NewBool(false)
}
if w.MoveThreadFromDirectMessageChannelEnable == nil {
w.MoveThreadFromDirectMessageChannelEnable = NewBool(false)
}
if w.MoveThreadFromGroupMessageChannelEnable == nil {
w.MoveThreadFromGroupMessageChannelEnable = NewBool(false)
}
}
func (w *WranglerSettings) IsValid() *AppError {
validDomainRegex := regexp.MustCompile(`^(([a-zA-Z]{1})|([a-zA-Z]{1}[a-zA-Z]{1})|([a-zA-Z]{1}[0-9]{1})|([0-9]{1}[a-zA-Z]{1})|([a-zA-Z0-9][a-zA-Z0-9-_]{1,61}[a-zA-Z0-9]))\.([a-zA-Z]{2,6}|[a-zA-Z0-9-]{2,30}\.[a-zA-Z]{2,3})$`)
for _, domain := range w.AllowedEmailDomain {
if !validDomainRegex.MatchString(domain) && domain != "localhost" {
return NewAppError("Config.IsValid", "model.config.is_valid.move_thread.domain_invalid.app_error", nil, "", http.StatusBadRequest)
}
}
return nil
}
type GlobalRelayMessageExportSettings struct {
CustomerType *string `access:"compliance_compliance_export"` // must be either A9, A10 or CUSTOM, dictates SMTP server url
SMTPUsername *string `access:"compliance_compliance_export"`
@@ -3405,6 +3450,7 @@ type Config struct {
FeatureFlags *FeatureFlags `access:"*_read" json:",omitempty"`
ImportSettings ImportSettings // telemetry: none
ExportSettings ExportSettings
WranglerSettings WranglerSettings
}
func (o *Config) Auditable() map[string]interface{} {
@@ -3520,6 +3566,7 @@ func (o *Config) SetDefaults() {
}
o.ImportSettings.SetDefaults()
o.ExportSettings.SetDefaults()
o.WranglerSettings.SetDefaults()
}
func (o *Config) IsValid() *AppError {
@@ -3610,6 +3657,11 @@ func (o *Config) IsValid() *AppError {
if appErr := o.ImportSettings.isValid(); appErr != nil {
return appErr
}
if appErr := o.WranglerSettings.IsValid(); appErr != nil {
return appErr
}
return nil
}

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

@@ -143,6 +143,24 @@ func TestConfigOverwriteSignatureAlgorithm(t *testing.T) {
require.Equal(t, *c1.SamlSettings.CanonicalAlgorithm, testAlgorithm)
}
func TestWranglerSettingsIsValid(t *testing.T) {
// // Test valid domains
w := &WranglerSettings{
AllowedEmailDomain: []string{"example.com", "subdomain.example.com"},
}
if err := w.IsValid(); err != nil {
t.Errorf("Expected no error for valid domains, but got %v", err)
}
// Test invalid domains
w = &WranglerSettings{
AllowedEmailDomain: []string{"example", "example..com", "example-.com", "-example.com", "example.com.", "example.com-"},
}
if err := w.IsValid(); err == nil {
t.Errorf("Expected error for invalid domains, but got none")
}
}
func TestConfigIsValidDefaultAlgorithms(t *testing.T) {
c1 := Config{}
c1.SetDefaults()

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

@@ -42,6 +42,8 @@ type FeatureFlags struct {
EnableExportDirectDownload bool
MoveThreadsEnabled bool
StreamlinedMarketplace bool
CloudIPFiltering bool
@@ -62,6 +64,7 @@ func (f *FeatureFlags) SetDefaults() {
f.OnboardingTourTips = true
f.CloudReverseTrial = false
f.EnableExportDirectDownload = false
f.MoveThreadsEnabled = false
f.StreamlinedMarketplace = true
f.CloudIPFiltering = false
f.ConsumePostHook = false

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

@@ -45,6 +45,7 @@ const (
PostTypeChannelRestored = "system_channel_restored"
PostTypeEphemeral = "system_ephemeral"
PostTypeChangeChannelPrivacy = "system_change_chan_privacy"
PostTypeWrangler = "system_wrangler"
PostTypeGMConvertedToChannel = "system_gm_to_channel"
PostTypeAddBotTeamsChannels = "add_bot_teams_channels"
PostTypeSystemWarnMetricStatus = "warn_metric_status"
@@ -193,6 +194,10 @@ type GetPersistentNotificationsPostsParams struct {
PerPage int
}
type MoveThreadParams struct {
ChannelId string `json:"channel_id"`
}
type SearchParameter struct {
Terms *string `json:"terms"`
IsOrSearch *bool `json:"is_or_search"`
@@ -444,6 +449,7 @@ func (o *Post) IsValid(maxPostSize int) *AppError {
PostTypeSystemWarnMetricStatus,
PostTypeReminder,
PostTypeMe,
PostTypeWrangler,
PostTypeGMConvertedToChannel:
default:
if !strings.HasPrefix(o.Type, PostCustomTypePrefix) {
@@ -893,3 +899,11 @@ func (o *Post) IsUrgent() bool {
return *postPriority.Priority == PostPriorityUrgent
}
func (o *Post) CleanPost() *Post {
o.Id = ""
o.CreateAt = 0
o.UpdateAt = 0
o.EditAt = 0
return o
}

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

@@ -190,3 +190,39 @@ func (o *PostList) IsChannelId(channelId string) bool {
return true
}
func (o *PostList) BuildWranglerPostList() *WranglerPostList {
wpl := &WranglerPostList{}
o.UniqueOrder()
o.SortByCreateAt()
posts := o.ToSlice()
if len(posts) == 0 {
// Something was sorted wrong or an empty PostList was provided.
return wpl
}
// A separate ID key map to ensure no duplicates.
idKeys := make(map[string]bool)
for i := range posts {
p := posts[len(posts)-i-1]
// Add UserID to metadata if it's new.
if _, ok := idKeys[p.UserId]; !ok {
idKeys[p.UserId] = true
wpl.ThreadUserIDs = append(wpl.ThreadUserIDs, p.UserId)
}
wpl.FileAttachmentCount += int64(len(p.FileIds))
wpl.Posts = append(wpl.Posts, p)
}
// Set metadata for earliest and latest posts
wpl.EarlistPostTimestamp = wpl.RootPost().CreateAt
wpl.LatestPostTimestamp = wpl.Posts[wpl.NumPosts()-1].CreateAt
return wpl
}

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

@@ -1016,6 +1016,12 @@ type UsersWithGroupsAndCount struct {
Count int64 `json:"total_count"`
}
func (u *User) EmailDomain() string {
at := strings.LastIndex(u.Email, "@")
// at >= 0 holds true and this is not checked here. It holds true, because during signup we run `mail.ParseAddress(email)`
return u.Email[at+1:]
}
type UserPostStats struct {
LastLogin int64 `json:"last_login_at,omitempty"`
LastStatusAt *int64 `json:"last_status_at,omitempty"`

33
server/public/model/wrangler.go Обычный файл
Просмотреть файл

@@ -0,0 +1,33 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
package model
// WranglerPostList provides a list of posts along with metadata about those
// posts.
type WranglerPostList struct {
Posts []*Post
ThreadUserIDs []string
EarlistPostTimestamp int64
LatestPostTimestamp int64
FileAttachmentCount int64
}
// NumPosts returns the number of posts in a post list.
func (wpl *WranglerPostList) NumPosts() int {
return len(wpl.Posts)
}
// RootPost returns the root post in a post list.
func (wpl *WranglerPostList) RootPost() *Post {
if wpl.NumPosts() < 1 {
return nil
}
return wpl.Posts[0]
}
// ContainsFileAttachments returns if the post list contains any file attachments.
func (wpl *WranglerPostList) ContainsFileAttachments() bool {
return wpl.FileAttachmentCount != 0
}

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

@@ -85,7 +85,7 @@ func InitTranslations(serverLocale, clientLocale string) error {
defaultClientLocale = clientLocale
var err error
T, err = getTranslationsBySystemLocale()
T, err = GetTranslationsBySystemLocale()
return err
}
@@ -151,7 +151,7 @@ func GetTranslationFuncForDir(dir string) (TranslationFuncByLocal, error) {
}, nil
}
func getTranslationsBySystemLocale() (TranslateFunc, error) {
func GetTranslationsBySystemLocale() (TranslateFunc, error) {
locale := defaultServerLocale
if _, ok := locales[locale]; !ok {
mlog.Warn("Failed to load system translations for selected locale, attempting to fall back to default", mlog.String("locale", locale), mlog.String("default_locale", defaultLocale))