* [MM-45564] - Notify Admin v2

* add dummy data

* update dummy data

* add store methods

* experiment with recurring task

* complete saving of the notification

* make improvements

* make improvements

* add store layer tests

* fix lint

* update store layer tests

* add app layer unit tests

* add store layers

* add app layer tests

* fix lint

* fix lint

* fix tests

* fix tests lint

* fix lint

* fix lint

* fix retry layer test

* add notifications manual trigger

* filter notifications based on current plan

* add test case

* temp change

* feedback impl

* fix translations

* change job scheduler

* refactor job

* fix store layer tests

* extract i18n

* fix lint

* fix translations

* fix translations

* add license statement for new file

* feedback impl-2

* fix lint

* update make file

* add intl ids

* improve

* fix lint

* feedback impl

* move code and rename files

* fix lint

* feedback impl

* add config for trigger notifications api

* fix tests

* tmp change

* undo temp changes

Co-authored-by: Mattermod <mattermod@users.noreply.github.com>
Этот коммит содержится в:
Allan Guwatudde
2022-09-02 13:52:48 +03:00
коммит произвёл GitHub
родитель c11ad8995f
Коммит bd42f0cd8c
39 изменённых файлов: 1789 добавлений и 278 удалений

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

@@ -8020,20 +8020,36 @@ func (c *Client4) ValidateWorkspaceBusinessEmail() (*Response, error) {
return BuildResponse(r), nil
}
func (c *Client4) NotifyAdmin(nr *NotifyAdminToUpgradeRequest) int {
func (c *Client4) NotifyAdmin(nr *NotifyAdminToUpgradeRequest) (int, error) {
nrJSON, err := json.Marshal(nr)
if err != nil {
return 0
return 0, err
}
r, err := c.DoAPIPost(c.cloudRoute()+"/notify-admin-to-upgrade", string(nrJSON))
r, err := c.DoAPIPost("/users/notify-admin", string(nrJSON))
if err != nil {
return r.StatusCode
return r.StatusCode, err
}
closeBody(r)
return r.StatusCode
return r.StatusCode, nil
}
func (c *Client4) TriggerNotifyAdmin(nr *NotifyAdminToUpgradeRequest) (int, error) {
nrJSON, err := json.Marshal(nr)
if err != nil {
return 0, err
}
r, err := c.DoAPIPost("/users/trigger-notify-admin-posts", string(nrJSON))
if err != nil {
return r.StatusCode, err
}
closeBody(r)
return r.StatusCode, nil
}
func (c *Client4) ValidateBusinessEmail(email *ValidateBusinessEmailRequest) (*Response, error) {

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

@@ -4,8 +4,6 @@
package model
import (
"os"
"strconv"
"strings"
)
@@ -42,9 +40,6 @@ const (
SubscriptionFamilyOnPrem = SubscriptionFamily("on-prem")
)
const defaultCloudNotifyAdminCoolOffDays = 30
const CloudNotifyAdminInfo = "cloud_notify_admin_info"
// Product model represents a product on the cloud system.
type Product struct {
ID string `json:"id"`
@@ -258,23 +253,3 @@ type ProductLimits struct {
Messages *MessagesLimits `json:"messages,omitempty"`
Teams *TeamsLimits `json:"teams,omitempty"`
}
type NotifyAdminToUpgradeRequest struct {
CurrentTeamId string `json:"current_team_id"`
}
type AdminNotificationUserInfo struct {
LastUserIDToNotify string
LastNotificationTimestamp int64
}
func CanNotify(lastNotificationTimestamp int64) bool {
coolOffPeriodDaysEnv := os.Getenv("MM_CLOUD_NOTIFY_ADMIN_COOL_OFF_DAYS")
coolOffPeriodDays, parseError := strconv.ParseFloat(coolOffPeriodDaysEnv, 64)
if parseError != nil {
coolOffPeriodDays = defaultCloudNotifyAdminCoolOffDays
}
daysToMillis := coolOffPeriodDays * 24 * 60 * 60 * 1000
timeDiff := GetMillis() - lastNotificationTimestamp
return timeDiff >= int64(daysToMillis)
}

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

@@ -361,6 +361,7 @@ type ServiceSettings struct {
ExperimentalEnableDefaultChannelLeaveJoinMessages *bool `access:"experimental_features"`
ExperimentalGroupUnreadChannels *string `access:"experimental_features"`
EnableAPITeamDeletion *bool
EnableAPITriggerAdminNotifications *bool
EnableAPIUserDeletion *bool
ExperimentalEnableHardenedMode *bool `access:"experimental_features"`
ExperimentalStrictCSRFEnforcement *bool `access:"experimental_features,write_restrictable,cloud_restrictable"`
@@ -754,6 +755,10 @@ func (s *ServiceSettings) SetDefaults(isUpdate bool) {
s.EnableAPITeamDeletion = NewBool(false)
}
if s.EnableAPITriggerAdminNotifications == nil {
s.EnableAPITriggerAdminNotifications = NewBool(false)
}
if s.EnableAPIUserDeletion == nil {
s.EnableAPIUserDeletion = NewBool(false)
}

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

@@ -28,6 +28,8 @@ const (
JobTypeResendInvitationEmail = "resend_invitation_email"
JobTypeExtractContent = "extract_content"
JobTypeLastAccessiblePost = "last_accessible_post"
JobTypeUpgradeNotifyAdmin = "upgrade_notify_admin"
JobTypeTrialNotifyAdmin = "trial_notify_admin"
JobStatusPending = "pending"
JobStatusInProgress = "in_progress"

75
model/notify_admin.go Обычный файл
Просмотреть файл

@@ -0,0 +1,75 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
package model
import (
"fmt"
"net/http"
)
type MattermostPaidFeature string
const (
PaidFeatureGuestAccounts = MattermostPaidFeature("mattermost.feature.guest_accounts")
PaidFeatureCustomUsergroups = MattermostPaidFeature("mattermost.feature.custom_user_groups")
PaidFeatureCreateMultipleTeams = MattermostPaidFeature("mattermost.feature.create_multiple_teams")
PaidFeatureStartcall = MattermostPaidFeature("mattermost.feature.start_call")
PaidFeaturePlaybooksRetrospective = MattermostPaidFeature("mattermost.feature.playbooks_retro")
PaidFeatureUnlimitedMessages = MattermostPaidFeature("mattermost.feature.unlimited_messages")
PaidFeatureUnlimitedFileStorage = MattermostPaidFeature("mattermost.feature.unlimited_file_storage")
PaidFeatureUnlimitedIntegrations = MattermostPaidFeature("mattermost.feature.unlimited_integrations")
PaidFeatureUnlimitedBoardcards = MattermostPaidFeature("mattermost.feature.unlimited_board_cards")
PaidFeatureAllProfessionalfeatures = MattermostPaidFeature("mattermost.feature.all_professional")
PaidFeatureAllEnterprisefeatures = MattermostPaidFeature("mattermost.feature.all_enterprise")
)
var validSKUs map[string]struct{} = map[string]struct{}{
LicenseShortSkuProfessional: {},
LicenseShortSkuEnterprise: {},
}
// These are the features a non admin would typically ping an admin about
var paidFeatures map[MattermostPaidFeature]struct{} = map[MattermostPaidFeature]struct{}{
PaidFeatureGuestAccounts: {},
PaidFeatureCustomUsergroups: {},
PaidFeatureCreateMultipleTeams: {},
PaidFeatureStartcall: {},
PaidFeaturePlaybooksRetrospective: {},
PaidFeatureUnlimitedMessages: {},
PaidFeatureUnlimitedFileStorage: {},
PaidFeatureUnlimitedIntegrations: {},
PaidFeatureUnlimitedBoardcards: {},
PaidFeatureAllProfessionalfeatures: {},
PaidFeatureAllEnterprisefeatures: {},
}
type NotifyAdminToUpgradeRequest struct {
TrialNotification bool `json:"trial_notification"`
RequiredPlan string `json:"required_plan"`
RequiredFeature MattermostPaidFeature `json:"required_feature"`
}
type NotifyAdminData struct {
CreateAt int64 `json:"create_at,omitempty"`
UserId string `json:"user_id"`
RequiredPlan string `json:"required_plan"`
RequiredFeature MattermostPaidFeature `json:"required_feature"`
Trial bool `json:"trial"`
}
func (nad *NotifyAdminData) IsValid() *AppError {
if _, planOk := validSKUs[nad.RequiredPlan]; !planOk {
return NewAppError("NotifyAdmin.IsValid", fmt.Sprintf("Invalid plan, %s provided", nad.RequiredPlan), nil, "", http.StatusBadRequest)
}
if _, featureOk := paidFeatures[nad.RequiredFeature]; !featureOk {
return NewAppError("NotifyAdmin.IsValid", fmt.Sprintf("Invalid feature, %s provided", nad.RequiredFeature), nil, "", http.StatusBadRequest)
}
return nil
}
func (nad *NotifyAdminData) PreSave() {
nad.CreateAt = GetMillis()
}