[MM-48029] notify admin for plugin install from work templates (#22007)

Co-authored-by: Mattermost Build <build@mattermost.com>
Co-authored-by: Julien Tant <julien@craftyx.fr>
Этот коммит содержится в:
Muhammad S
2023-02-09 02:08:33 +05:00
коммит произвёл GitHub
родитель a72dd120b7
Коммит 3ae70591d0
26 изменённых файлов: 639 добавлений и 100 удалений

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

@@ -573,7 +573,7 @@ type AppIface interface {
FillInChannelsProps(c request.CTX, channelList model.ChannelList) *model.AppError
FilterUsersByVisible(viewer *model.User, otherUsers []*model.User) ([]*model.User, *model.AppError)
FindTeamByName(name string) bool
FinishSendAdminNotifyPost(trial bool, now int64)
FinishSendAdminNotifyPost(trial bool, now int64, pluginBasedData map[string][]*model.NotifyAdminData)
GenerateMfaSecret(userID string) (*model.MfaSecret, *model.AppError)
GeneratePublicLink(siteURL string, info *model.FileInfo) string
GenerateSupportPacket() []model.FileData
@@ -1167,7 +1167,7 @@ type AppIface interface {
UpsertGroupMember(groupID string, userID string) (*model.GroupMember, *model.AppError)
UpsertGroupMembers(groupID string, userIDs []string) ([]*model.GroupMember, *model.AppError)
UpsertGroupSyncable(groupSyncable *model.GroupSyncable) (*model.GroupSyncable, *model.AppError)
UserAlreadyNotifiedOnRequiredFeature(user string, feature model.MattermostPaidFeature) bool
UserAlreadyNotifiedOnRequiredFeature(user string, feature model.MattermostFeature) bool
UserCanSeeOtherUser(userID string, otherUserId string) (bool, *model.AppError)
UserIsFirstAdmin(user *model.User) bool
VerifyEmailFromToken(c request.CTX, userSuppliedTokenString string) *model.AppError

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

@@ -9,6 +9,7 @@ import (
"net/http"
"os"
"strconv"
"strings"
"github.com/mattermost/mattermost-server/v6/app/request"
"github.com/mattermost/mattermost-server/v6/model"
@@ -19,14 +20,16 @@ import (
const lastTrialNotificationTimeStamp = "LAST_TRIAL_NOTIFICATION_TIMESTAMP"
const lastUpgradeNotificationTimeStamp = "LAST_UPGRADE_NOTIFICATION_TIMESTAMP"
const defaultNotifyAdminCoolOffDays = 14
const defaultNotifyAdminCoolOffDays = 0.0104166667 // this is a temp change
func (a *App) SaveAdminNotification(userId string, notifyData *model.NotifyAdminToUpgradeRequest) *model.AppError {
requiredFeature := notifyData.RequiredFeature
requiredPlan := notifyData.RequiredPlan
trial := notifyData.TrialNotification
if a.UserAlreadyNotifiedOnRequiredFeature(userId, requiredFeature) {
isUserAlreadyNotified := a.UserAlreadyNotifiedOnRequiredFeature(userId, requiredFeature)
mlog.Info("SaveAdminNotification")
if isUserAlreadyNotified {
return model.NewAppError("app.SaveAdminNotification", "api.cloud.notify_admin_to_upgrade_error.already_notified", nil, "", http.StatusForbidden)
}
@@ -36,6 +39,7 @@ func (a *App) SaveAdminNotification(userId string, notifyData *model.NotifyAdmin
RequiredFeature: requiredFeature,
Trial: trial,
})
if appErr != nil {
return appErr
}
@@ -57,7 +61,9 @@ func (a *App) DoCheckForAdminNotifications(trial bool) *model.AppError {
}
func (a *App) SaveAdminNotifyData(data *model.NotifyAdminData) (*model.NotifyAdminData, *model.AppError) {
mlog.Info("Trying to save NotifyAdmin data")
d, err := a.Srv().Store().NotifyAdmin().Save(data)
mlog.Info("NotifyAdmin data saved")
if err != nil {
var nfErr *store.ErrNotFound
switch {
@@ -67,6 +73,7 @@ func (a *App) SaveAdminNotifyData(data *model.NotifyAdminData) (*model.NotifyAdm
return nil, model.NewAppError("SaveAdminNotifyData", "app.notify_admin.save.app_error", nil, err.Error(), http.StatusInternalServerError)
}
}
mlog.Info("return from SaveAdminNotifyData")
return d, nil
}
@@ -81,6 +88,8 @@ func filterNotificationData(data []*model.NotifyAdminData, test func(*model.Noti
}
func (a *App) SendNotifyAdminPosts(c *request.Context, workspaceName string, currentSKU string, trial bool) *model.AppError {
mlog.Info("enter SendNotifyAdminPosts")
if !a.CanNotifyAdmin(trial) {
return model.NewAppError("SendNotifyAdminPosts", "app.notify_admin.send_notification_post.app_error", nil, "Cannot notify yet", http.StatusForbidden)
}
@@ -103,6 +112,8 @@ func (a *App) SendNotifyAdminPosts(c *request.Context, workspaceName string, cur
now := model.GetMillis()
data, err := a.Srv().Store().NotifyAdmin().Get(trial)
mlog.Info("SendNotifyAdminPosts")
if err != nil {
return model.NewAppError("SendNotifyAdminPosts", "app.notify_admin.send_notification_post.app_error", nil, err.Error(), http.StatusInternalServerError)
}
@@ -110,58 +121,99 @@ func (a *App) SendNotifyAdminPosts(c *request.Context, workspaceName string, cur
data = filterNotificationData(data, func(nad *model.NotifyAdminData) bool { return nad.RequiredPlan != currentSKU })
if len(data) == 0 {
mlog.Warn("No notification data available")
a.Log().Warn("No notification data available")
return nil
}
userBasedData := a.groupNotifyAdminByUser(data)
featureBasedData := a.groupNotifyAdminByFeature(data)
props := make(model.StringInterface)
userBasedPaidFeatureData, userBasedPluginData := a.groupNotifyAdminByUser(data)
featureBasedData := a.groupNotifyAdminByPaidFeature(data)
pluginBasedData := a.groupNotifyAdminByPlugin(data)
for _, admin := range sysadmins {
T := i18n.GetUserTranslations(admin.Locale)
message := T("app.cloud.upgrade_plan_bot_message", map[string]interface{}{"UsersNum": len(userBasedData), "WorkspaceName": workspaceName})
if len(userBasedData) == 1 {
message = T("app.cloud.upgrade_plan_bot_message_single", map[string]interface{}{"UsersNum": len(userBasedData), "WorkspaceName": workspaceName}) // todo (allan): investigate if translations library can do this
}
if trial {
message = T("app.cloud.trial_plan_bot_message", map[string]interface{}{"UsersNum": len(userBasedData), "WorkspaceName": workspaceName})
if len(userBasedData) == 1 {
message = T("app.cloud.trial_plan_bot_message_single", map[string]interface{}{"UsersNum": len(userBasedData), "WorkspaceName": workspaceName})
}
if len(userBasedPaidFeatureData) > 0 && len(featureBasedData) > 0 {
a.upgradePlanAdminNotifyPost(c, workspaceName, userBasedPaidFeatureData, featureBasedData, systemBot, admin, trial)
}
channel, appErr := a.GetOrCreateDirectChannel(c, systemBot.UserId, admin.Id)
if appErr != nil {
mlog.Warn("Error getting direct channel", mlog.Err(appErr))
continue
}
if len(userBasedPluginData) > 0 {
mlog.Info("SendNotifyAdminPosts", mlog.String("length of user based plugin data", fmt.Sprint(len(userBasedPluginData))))
post := &model.Post{
Message: message,
UserId: systemBot.UserId,
ChannelId: channel.Id,
Type: fmt.Sprintf("%sup_notification", model.PostCustomTypePrefix), // webapp will have to create renderer for this custom post type
}
props["requested_features"] = featureBasedData
props["trial"] = trial
post.SetProps(props)
_, appErr = a.CreatePost(c, post, channel, false, true)
if appErr != nil {
mlog.Warn("Error creating post", mlog.Err(appErr))
continue
a.pluginInstallAdminNotifyPost(c, userBasedPluginData, pluginBasedData, systemBot, admin)
}
}
a.FinishSendAdminNotifyPost(trial, now)
a.FinishSendAdminNotifyPost(trial, now, pluginBasedData)
return nil
}
func (a *App) UserAlreadyNotifiedOnRequiredFeature(user string, feature model.MattermostPaidFeature) bool {
func (a *App) pluginInstallAdminNotifyPost(c *request.Context, userBasedData map[string][]*model.NotifyAdminData, pluginBasedPluginData map[string][]*model.NotifyAdminData, systemBot *model.Bot, admin *model.User) {
props := make(model.StringInterface)
channel, appErr := a.GetOrCreateDirectChannel(c, systemBot.UserId, admin.Id)
if appErr != nil {
a.Log().Warn("Error getting direct channel", mlog.Err(appErr))
return
}
post := &model.Post{
UserId: systemBot.UserId,
ChannelId: channel.Id,
Type: fmt.Sprintf("%spl_notification", model.PostCustomTypePrefix), // webapp will have to create renderer for this custom post type
}
props["requested_plugins_by_plugin_ids"] = pluginBasedPluginData
props["requested_plugins_by_user_ids"] = userBasedData
post.SetProps(props)
mlog.Info("pluginInstallAdminNotifyPost: send props")
_, appErr = a.CreatePost(c, post, channel, false, true)
mlog.Info("pluginInstallAdminNotifyPost: post created")
if appErr != nil {
a.Log().Warn("Error creating post", mlog.Err(appErr))
}
}
func (a *App) upgradePlanAdminNotifyPost(c *request.Context, workspaceName string, userBasedData map[string][]*model.NotifyAdminData, featureBasedData map[model.MattermostFeature][]*model.NotifyAdminData, systemBot *model.Bot, admin *model.User, trial bool) {
props := make(model.StringInterface)
T := i18n.GetUserTranslations(admin.Locale)
message := T("app.cloud.upgrade_plan_bot_message", map[string]interface{}{"UsersNum": len(userBasedData), "WorkspaceName": workspaceName})
if len(userBasedData) == 1 {
message = T("app.cloud.upgrade_plan_bot_message_single", map[string]interface{}{"UsersNum": len(userBasedData), "WorkspaceName": workspaceName}) // todo (allan): investigate if translations library can do this
}
if trial {
message = T("app.cloud.trial_plan_bot_message", map[string]interface{}{"UsersNum": len(userBasedData), "WorkspaceName": workspaceName})
if len(userBasedData) == 1 {
message = T("app.cloud.trial_plan_bot_message_single", map[string]interface{}{"UsersNum": len(userBasedData), "WorkspaceName": workspaceName})
}
}
channel, appErr := a.GetOrCreateDirectChannel(c, systemBot.UserId, admin.Id)
if appErr != nil {
a.Log().Warn("Error getting direct channel", mlog.Err(appErr))
return
}
post := &model.Post{
Message: message,
UserId: systemBot.UserId,
ChannelId: channel.Id,
Type: fmt.Sprintf("%sup_notification", model.PostCustomTypePrefix), // webapp will have to create renderer for this custom post type
}
props["requested_features"] = featureBasedData
props["trial"] = trial
post.SetProps(props)
_, appErr = a.CreatePost(c, post, channel, false, true)
if appErr != nil {
a.Log().Warn("Error creating post", mlog.Err(appErr))
}
}
func (a *App) UserAlreadyNotifiedOnRequiredFeature(user string, feature model.MattermostFeature) bool {
data, err := a.Srv().Store().NotifyAdmin().GetDataByUserIdAndFeature(user, feature)
if err != nil {
return false
@@ -185,13 +237,13 @@ func (a *App) CanNotifyAdmin(trial bool) bool {
if errors.As(sysValErr, &nfErr) { // if no timestamps have been recorded before, system is free to notify
return true
}
mlog.Error("Cannot notify", mlog.Err(sysValErr))
a.Log().Error("Cannot notify", mlog.Err(sysValErr))
return false
}
lastNotificationTimestamp, err := strconv.ParseFloat(sysVal.Value, 64)
if err != nil {
mlog.Error("Cannot notify", mlog.Err(err))
a.Log().Error("Cannot notify", mlog.Err(err))
return false
}
@@ -205,7 +257,9 @@ func (a *App) CanNotifyAdmin(trial bool) bool {
return timeDiff >= int64(daysToMillis)
}
func (a *App) FinishSendAdminNotifyPost(trial bool, now int64) {
func (a *App) FinishSendAdminNotifyPost(trial bool, now int64, pluginBasedData map[string][]*model.NotifyAdminData) {
mlog.Info("FinishSendAdminNotifyPost")
systemVarName := lastUpgradeNotificationTimeStamp
if trial {
systemVarName = lastTrialNotificationTimeStamp
@@ -214,30 +268,64 @@ func (a *App) FinishSendAdminNotifyPost(trial bool, now int64) {
val := strconv.FormatInt(model.GetMillis(), 10)
sysVar := &model.System{Name: systemVarName, Value: val}
if err := a.Srv().Store().System().SaveOrUpdate(sysVar); err != nil {
mlog.Error("Unable to finish send admin notify post job", mlog.Err(err))
a.Log().Error("Unable to finish send admin notify post job", mlog.Err(err))
}
// All the requested features notifications are now sent in a post and can safely be removed except
// the plugin notify admin. We keep it as we do not want the same user to send the notification for the same plugin.
// We update the NotifyAdmin SentAt to keep track of it.
for pluginId := range pluginBasedData {
notifications := pluginBasedData[pluginId]
for _, notification := range notifications {
requiredFeature := notification.RequiredFeature
requiredPlan := notification.RequiredPlan
userId := notification.UserId
if err := a.Srv().Store().NotifyAdmin().Update(userId, requiredPlan, requiredFeature, now); err != nil {
a.Log().Error("Unable to update SentAt for work template feature", mlog.Err(err))
}
}
}
// all the notifications are now sent in a post and can safely be removed
if err := a.Srv().Store().NotifyAdmin().DeleteBefore(trial, now); err != nil {
mlog.Error("Unable to finish send admin notify post job", mlog.Err(err))
a.Log().Error("Unable to finish send admin notify post job", mlog.Err(err))
}
mlog.Info("exit FinishSendAdminNotifyPost")
}
func (a *App) groupNotifyAdminByUser(data []*model.NotifyAdminData) map[string][]*model.NotifyAdminData {
myMap := make(map[string][]*model.NotifyAdminData)
func (a *App) groupNotifyAdminByUser(data []*model.NotifyAdminData) (map[string][]*model.NotifyAdminData, map[string][]*model.NotifyAdminData) {
userBasedPaidFeatureData := make(map[string][]*model.NotifyAdminData)
userBasedPluginData := make(map[string][]*model.NotifyAdminData)
for _, d := range data {
myMap[d.UserId] = append(myMap[d.UserId], d)
if strings.HasPrefix(string(d.RequiredFeature), string(model.PluginFeature)) {
userBasedPluginData[d.UserId] = append(userBasedPluginData[d.UserId], d)
} else {
userBasedPaidFeatureData[d.UserId] = append(userBasedPaidFeatureData[d.UserId], d)
}
}
return myMap
return userBasedPaidFeatureData, userBasedPluginData
}
func (a *App) groupNotifyAdminByFeature(data []*model.NotifyAdminData) map[model.MattermostPaidFeature][]*model.NotifyAdminData {
myMap := make(map[model.MattermostPaidFeature][]*model.NotifyAdminData)
func (a *App) groupNotifyAdminByPaidFeature(data []*model.NotifyAdminData) map[model.MattermostFeature][]*model.NotifyAdminData {
myMap := make(map[model.MattermostFeature][]*model.NotifyAdminData)
for _, d := range data {
if strings.HasPrefix(string(d.RequiredFeature), string(model.PluginFeature)) {
continue
}
myMap[d.RequiredFeature] = append(myMap[d.RequiredFeature], d)
}
return myMap
}
func (a *App) groupNotifyAdminByPlugin(data []*model.NotifyAdminData) map[string][]*model.NotifyAdminData {
myMap := make(map[string][]*model.NotifyAdminData)
for _, d := range data {
if strings.HasPrefix(string(d.RequiredFeature), string(model.PluginFeature)) {
plugins := strings.Split(d.RequiredPlan, ",")
for _, plugin := range plugins {
myMap[plugin] = append(myMap[plugin], d)
}
}
}
return myMap
}

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

@@ -15,9 +15,11 @@ import (
"github.com/stretchr/testify/require"
)
const PluginIdGithub = "github"
func Test_SendNotifyAdminPosts(t *testing.T) {
t.Run("no error sending upgrade post when no notifications are available", func(t *testing.T) {
t.Run("no error sending non trial upgrade post when no notifications are available", func(t *testing.T) {
th := Setup(t).InitBasic()
defer th.TearDown()
@@ -28,7 +30,7 @@ func Test_SendNotifyAdminPosts(t *testing.T) {
require.Nil(t, err)
})
t.Run("no error sending trial post when do notifications are available", func(t *testing.T) {
t.Run("no error sending trial upgrade post when no notifications are available", func(t *testing.T) {
th := Setup(t).InitBasic()
defer th.TearDown()
@@ -45,7 +47,7 @@ func Test_SendNotifyAdminPosts(t *testing.T) {
th.App.Srv().SetLicense(model.NewTestLicense("cloud"))
// some some notifications
// some notifications
_, appErr := th.App.SaveAdminNotifyData(&model.NotifyAdminData{
UserId: th.BasicUser.Id,
RequiredPlan: model.LicenseShortSkuProfessional,
@@ -93,13 +95,13 @@ func Test_SendNotifyAdminPosts(t *testing.T) {
require.Equal(t, "2 members of the test workspace have requested a workspace upgrade for: ", post.Message)
})
t.Run("successfully send trial notification", func(t *testing.T) {
t.Run("successfully send trial upgrade notification", func(t *testing.T) {
th := Setup(t).InitBasic()
defer th.TearDown()
th.App.Srv().SetLicense(model.NewTestLicense("cloud"))
// some some notifications
// some notifications
_, appErr := th.App.SaveAdminNotifyData(&model.NotifyAdminData{
UserId: th.BasicUser.Id,
RequiredPlan: model.LicenseShortSkuProfessional,
@@ -141,13 +143,128 @@ func Test_SendNotifyAdminPosts(t *testing.T) {
require.Equal(t, "1 member of the test workspace has requested starting the Enterprise trial for access to: ", post.Message)
})
t.Run("error when trying to send post before end of cool off period", func(t *testing.T) {
t.Run("successfully send install plugin notification", func(t *testing.T) {
th := Setup(t).InitBasic()
defer th.TearDown()
// some notifications
_, appErr := th.App.SaveAdminNotifyData(&model.NotifyAdminData{
UserId: th.BasicUser.Id,
RequiredPlan: PluginIdGithub,
RequiredFeature: model.PluginFeature,
Trial: false,
})
require.Nil(t, appErr)
ctx := request.NewContext(context.Background(), model.NewId(), model.NewId(), model.NewId(), model.NewId(), model.NewId(), model.Session{}, nil)
appErr = th.App.SendNotifyAdminPosts(ctx, "", "", false)
require.Nil(t, appErr)
bot, appErr := th.App.GetSystemBot()
require.Nil(t, appErr)
var channel *model.Channel
var err error
var timeout = 5 * time.Second
begin := time.Now()
for {
if time.Since(begin) > timeout {
break
}
channel, err = th.App.Srv().Store().Channel().GetByName("", model.GetDMNameFromIds(bot.UserId, th.SystemAdminUser.Id), false)
if err == nil && channel != nil {
break
}
time.Sleep(100 * time.Millisecond)
}
require.NoError(t, err, "Expected message to have been sent within %d seconds", timeout)
postList, err := th.App.Srv().Store().Post().GetPosts(model.GetPostsOptions{ChannelId: channel.Id, Page: 0, PerPage: 1}, false, map[string]bool{})
require.NoError(t, err)
post := postList.Posts[postList.Order[0]]
require.Equal(t, fmt.Sprintf("%spl_notification", model.PostCustomTypePrefix), post.Type)
require.Equal(t, bot.UserId, post.UserId)
})
t.Run("persist notify admin data after sending the install plugin notification", func(t *testing.T) {
th := Setup(t).InitBasic()
defer th.TearDown()
// some notifications
_, appErr := th.App.SaveAdminNotifyData(&model.NotifyAdminData{
UserId: th.BasicUser.Id,
RequiredPlan: PluginIdGithub,
RequiredFeature: model.PluginFeature,
Trial: false,
})
require.Nil(t, appErr)
ctx := request.NewContext(context.Background(), model.NewId(), model.NewId(), model.NewId(), model.NewId(), model.NewId(), model.Session{}, nil)
appErr = th.App.SendNotifyAdminPosts(ctx, "", "", false)
require.Nil(t, appErr)
bot, appErr := th.App.GetSystemBot()
require.Nil(t, appErr)
var channel *model.Channel
var err error
var timeout = 5 * time.Second
begin := time.Now()
for {
if time.Since(begin) > timeout {
break
}
channel, err = th.App.Srv().Store().Channel().GetByName("", model.GetDMNameFromIds(bot.UserId, th.SystemAdminUser.Id), false)
if err == nil && channel != nil {
break
}
time.Sleep(100 * time.Millisecond)
}
require.NoError(t, err, "Expected message to have been sent within %d seconds", timeout)
postList, err := th.App.Srv().Store().Post().GetPosts(model.GetPostsOptions{ChannelId: channel.Id, Page: 0, PerPage: 1}, false, map[string]bool{})
require.NoError(t, err)
post := postList.Posts[postList.Order[0]]
require.Equal(t, fmt.Sprintf("%spl_notification", model.PostCustomTypePrefix), post.Type)
require.Equal(t, bot.UserId, post.UserId)
data, err := th.App.Srv().Store().NotifyAdmin().GetDataByUserIdAndFeature(th.BasicUser.Id, model.PluginFeature)
require.NoError(t, err)
require.Equal(t, len(data), 1)
})
t.Run("error sending more than one notification to the same user and for the same plugin", func(t *testing.T) {
th := Setup(t).InitBasic()
defer th.TearDown()
err := th.App.SaveAdminNotification(th.BasicUser.Id, &model.NotifyAdminToUpgradeRequest{
RequiredPlan: PluginIdGithub,
RequiredFeature: model.PluginFeature,
TrialNotification: false,
})
require.Nil(t, err)
err = th.App.SaveAdminNotification(th.BasicUser.Id, &model.NotifyAdminToUpgradeRequest{
RequiredPlan: PluginIdGithub,
RequiredFeature: model.PluginFeature,
TrialNotification: false,
})
require.Equal(t, err.Error(), "app.SaveAdminNotification: Already notified admin")
})
t.Run("error when trying to send upgrade post before end of cool off period", func(t *testing.T) {
th := Setup(t).InitBasic()
defer th.TearDown()
th.App.Srv().SetLicense(model.NewTestLicense("cloud"))
// some some notifications
// some notifications
_, appErr := th.App.SaveAdminNotifyData(&model.NotifyAdminData{
UserId: th.BasicUser.Id,
RequiredPlan: model.LicenseShortSkuProfessional,
@@ -173,7 +290,7 @@ func Test_SendNotifyAdminPosts(t *testing.T) {
require.Equal(t, appErr.Error(), "SendNotifyAdminPosts: Unable to send notification post., Cannot notify yet")
})
t.Run("can send post at the end of cool off period", func(t *testing.T) {
t.Run("can send upgrade post at the end of cool off period", func(t *testing.T) {
th := Setup(t).InitBasic()
defer th.TearDown()
@@ -182,7 +299,7 @@ func Test_SendNotifyAdminPosts(t *testing.T) {
os.Setenv("MM_NOTIFY_ADMIN_COOL_OFF_DAYS", "0.00003472222222") // set to 3 seconds
defer os.Unsetenv("MM_NOTIFY_ADMIN_COOL_OFF_DAYS")
// some some notifications
// some notifications
_, appErr := th.App.SaveAdminNotifyData(&model.NotifyAdminData{
UserId: th.BasicUser.Id,
RequiredPlan: model.LicenseShortSkuProfessional,
@@ -215,7 +332,7 @@ func Test_SendNotifyAdminPosts(t *testing.T) {
th.App.Srv().SetLicense(model.NewTestLicense("cloud"))
// some some notifications
// some notifications
_, appErr := th.App.SaveAdminNotifyData(&model.NotifyAdminData{
UserId: th.BasicUser.Id,
RequiredPlan: model.LicenseShortSkuProfessional,
@@ -264,4 +381,68 @@ func Test_SendNotifyAdminPosts(t *testing.T) {
require.Equal(t, bot.UserId, post.UserId)
require.Equal(t, "1 member of the test workspace has requested a workspace upgrade for: ", post.Message) // expect only one member's notification even though 2 were added
})
t.Run("correctly send upgrade and install plugin post with the correct user request", func(t *testing.T) {
th := Setup(t).InitBasic()
defer th.TearDown()
os.Setenv("MM_NOTIFY_ADMIN_COOL_OFF_DAYS", "0")
defer os.Unsetenv("MM_NOTIFY_ADMIN_COOL_OFF_DAYS")
th.App.Srv().SetLicense(model.NewTestLicense("cloud"))
ctx := request.NewContext(context.Background(), model.NewId(), model.NewId(), model.NewId(), model.NewId(), model.NewId(), model.Session{}, nil)
// some notifications
_, appErr := th.App.SaveAdminNotifyData(&model.NotifyAdminData{
UserId: th.BasicUser.Id,
RequiredPlan: model.LicenseShortSkuProfessional,
RequiredFeature: model.PaidFeatureGuestAccounts,
Trial: false,
})
require.Nil(t, appErr)
appErr = th.App.SendNotifyAdminPosts(ctx, "test", "", false)
require.Nil(t, appErr)
// some notifications
_, appErr = th.App.SaveAdminNotifyData(&model.NotifyAdminData{
UserId: th.BasicUser.Id,
RequiredPlan: PluginIdGithub,
RequiredFeature: model.PluginFeature,
Trial: false,
})
require.Nil(t, appErr)
appErr = th.App.SendNotifyAdminPosts(ctx, "test", "", false)
require.Nil(t, appErr)
bot, appErr := th.App.GetSystemBot()
require.Nil(t, appErr)
var channel *model.Channel
var err error
var timeout = 5 * time.Second
begin := time.Now()
for {
if time.Since(begin) > timeout {
break
}
channel, err = th.App.Srv().Store().Channel().GetByName("", model.GetDMNameFromIds(bot.UserId, th.SystemAdminUser.Id), false)
if err == nil && channel != nil {
break
}
time.Sleep(100 * time.Millisecond)
}
require.NoError(t, err, "Expected message to have been sent within %d seconds", timeout)
postList, err := th.App.Srv().Store().Post().GetPosts(model.GetPostsOptions{ChannelId: channel.Id, Page: 0, PerPage: 2}, false, map[string]bool{})
require.NoError(t, err)
installPluginPost := postList.Posts[postList.Order[0]]
require.Equal(t, fmt.Sprintf("%spl_notification", model.PostCustomTypePrefix), installPluginPost.Type)
require.Equal(t, bot.UserId, installPluginPost.UserId)
upgradePost := postList.Posts[postList.Order[1]]
require.Equal(t, fmt.Sprintf("%sup_notification", model.PostCustomTypePrefix), upgradePost.Type)
require.Equal(t, bot.UserId, upgradePost.UserId)
require.Equal(t, "1 member of the test workspace has requested a workspace upgrade for: ", upgradePost.Message)
})
}

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

@@ -4430,7 +4430,7 @@ func (a *OpenTracingAppLayer) FindTeamByName(name string) bool {
return resultVar0
}
func (a *OpenTracingAppLayer) FinishSendAdminNotifyPost(trial bool, now int64) {
func (a *OpenTracingAppLayer) FinishSendAdminNotifyPost(trial bool, now int64, pluginBasedData map[string][]*model.NotifyAdminData) {
origCtx := a.ctx
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.FinishSendAdminNotifyPost")
@@ -4442,7 +4442,7 @@ func (a *OpenTracingAppLayer) FinishSendAdminNotifyPost(trial bool, now int64) {
}()
defer span.Finish()
a.app.FinishSendAdminNotifyPost(trial, now)
a.app.FinishSendAdminNotifyPost(trial, now, pluginBasedData)
}
func (a *OpenTracingAppLayer) GenerateMfaSecret(userID string) (*model.MfaSecret, *model.AppError) {
@@ -18521,7 +18521,7 @@ func (a *OpenTracingAppLayer) UpsertGroupSyncable(groupSyncable *model.GroupSync
return resultVar0, resultVar1
}
func (a *OpenTracingAppLayer) UserAlreadyNotifiedOnRequiredFeature(user string, feature model.MattermostPaidFeature) bool {
func (a *OpenTracingAppLayer) UserAlreadyNotifiedOnRequiredFeature(user string, feature model.MattermostFeature) bool {
origCtx := a.ctx
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.UserAlreadyNotifiedOnRequiredFeature")

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

@@ -1543,6 +1543,12 @@ func (s *Server) initJobs() {
notify_admin.MakeScheduler(s.Jobs, s.License(), model.JobTypeTrialNotifyAdmin),
)
s.Jobs.RegisterJobType(
model.JobTypeInstallPluginNotifyAdmin,
notify_admin.MakeInstallPluginNotifyWorker(s.Jobs, New(ServerConnector(s.Channels()))),
notify_admin.MakeInstallPluginScheduler(s.Jobs, s.License(), model.JobTypeInstallPluginNotifyAdmin),
)
s.Jobs.RegisterJobType(
model.JobTypeHostedPurchaseScreening,
hosted_purchase_screening.MakeWorker(s.Jobs, s.License(), s.Store().System()),