mattermost-community-enterp.../cmd/mmctl/commands/sampledata_util.go
Claude ec1f89217a Merge: Complete Mattermost Server with Community Enterprise
Full Mattermost server source with integrated Community Enterprise features.
Includes vendor directory for offline/air-gapped builds.

Structure:
- enterprise-impl/: Enterprise feature implementations
- enterprise-community/: Init files that register implementations
- enterprise/: Bridge imports (community_imports.go)
- vendor/: All dependencies for offline builds

Build (online):
  go build ./cmd/mattermost

Build (offline/air-gapped):
  go build -mod=vendor ./cmd/mattermost

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-17 23:59:07 +09:00

462 lines
11 KiB
Go

// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
//nolint:gosec
package commands
import (
"fmt"
"math/rand"
"slices"
"sort"
"strings"
"time"
"github.com/mattermost/mattermost/server/public/model"
"github.com/mattermost/mattermost/server/v8/channels/app"
"github.com/mattermost/mattermost/server/v8/channels/app/imports"
"github.com/icrowley/fake"
)
func randomPastTime(seconds int) int64 {
now := time.Now()
today := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, time.FixedZone("UTC", 0))
return (today.Unix() * 1000) - int64(rand.Intn(seconds*1000))
}
func sortedRandomDates(size int) []int64 {
dates := make([]int64, size)
for i := range size {
dates[i] = randomPastTime(50000)
}
slices.Sort(dates)
return dates
}
func randomEmoji() string {
emojis := []string{"+1", "-1", "heart", "blush"}
return emojis[rand.Intn(len(emojis))]
}
func randomReaction(users []string, parentCreateAt int64) app.ReactionImportData {
user := users[rand.Intn(len(users))]
emoji := randomEmoji()
date := parentCreateAt + int64(rand.Intn(100000))
return app.ReactionImportData{
User: &user,
EmojiName: &emoji,
CreateAt: &date,
}
}
func randomReply(users []string, parentCreateAt int64) imports.ReplyImportData {
user := users[rand.Intn(len(users))]
message := randomMessage(users)
date := parentCreateAt + int64(rand.Intn(100000))
return imports.ReplyImportData{
User: &user,
Message: &message,
CreateAt: &date,
}
}
func randomMessage(users []string) string {
var message string
switch rand.Intn(30) {
case 0:
mention := users[rand.Intn(len(users))]
message = "@" + mention + " " + fake.Sentence()
case 1:
switch rand.Intn(2) {
case 0:
mattermostVideos := []string{"Q4MgnxbpZas", "BFo7E9-Kc_E", "LsMLR-BHsKg", "MRmGDhlMhNA", "mUOPxT7VgWc"}
message = "https://www.youtube.com/watch?v=" + mattermostVideos[rand.Intn(len(mattermostVideos))]
case 1:
mattermostTweets := []string{"943119062334353408", "949370809528832005", "948539688171819009", "939122439115681792", "938061722027425797"}
message = "https://twitter.com/mattermosthq/status/" + mattermostTweets[rand.Intn(len(mattermostTweets))]
}
case 2:
message = ""
if rand.Intn(2) == 0 {
message += fake.Sentence()
}
for i := 0; i < rand.Intn(4)+1; i++ {
message += "\n * " + fake.Word()
}
default:
if rand.Intn(2) == 0 {
message = fake.Sentence()
} else {
message = fake.Paragraph()
}
if rand.Intn(3) == 0 {
message += "\n" + fake.Sentence()
}
if rand.Intn(3) == 0 {
message += "\n" + fake.Sentence()
}
if rand.Intn(3) == 0 {
message += "\n" + fake.Sentence()
}
}
return message
}
func createUser(idx int, teamMemberships int, channelMemberships int, teamsAndChannels map[string][]string, profileImages []string, userType string) imports.LineImportData {
firstName := fake.FirstName()
lastName := fake.LastName()
position := fake.JobTitle()
username := fmt.Sprintf("%s.%s", strings.ToLower(firstName), strings.ToLower(lastName))
roles := "system_user"
var password string
var email string
switch userType {
case guestUser:
password = fmt.Sprintf("SampleGu@st-%d", idx)
email = fmt.Sprintf("guest-%d@sample.mattermost.com", idx)
roles = "system_guest"
if idx == 0 {
username = "guest"
password = "SampleGu@st1"
email = "guest@sample.mattermost.com"
}
case deactivatedUser:
password = fmt.Sprintf("SampleDe@ctivated-%d", idx)
email = fmt.Sprintf("deactivated-%d@sample.mattermost.com", idx)
default:
password = fmt.Sprintf("SampleUs@r-%d", idx)
email = fmt.Sprintf("user-%d@sample.mattermost.com", idx)
if idx == 0 {
username = "sysadmin"
password = "Sys@dmin-sample1"
email = "sysadmin@sample.mattermost.com"
} else if idx == 1 {
username = "user-1"
}
if idx%5 == 0 {
roles = "system_admin system_user"
}
}
// The 75% of the users have custom profile image
var profileImage *string
if rand.Intn(4) != 0 {
profileImageSelector := rand.Int()
if len(profileImages) > 0 {
profileImage = &profileImages[profileImageSelector%len(profileImages)]
}
}
useMilitaryTime := "false"
if idx != 0 && rand.Intn(2) == 0 {
useMilitaryTime = "true"
}
collapsePreviews := "false"
if idx != 0 && rand.Intn(2) == 0 {
collapsePreviews = "true"
}
messageDisplay := "clean"
if idx != 0 && rand.Intn(2) == 0 {
messageDisplay = "compact"
}
channelDisplayMode := "full"
if idx != 0 && rand.Intn(2) == 0 {
channelDisplayMode = "centered"
}
// Some users has nickname
nickname := ""
if rand.Intn(5) == 0 {
nickname = fake.Company()
}
// sysadmin, user-1 and user-2 users skip tutorial steps
// Other half of users also skip tutorial steps
tutorialStep := "999"
if idx > 2 {
switch rand.Intn(6) {
case 1:
tutorialStep = "1"
case 2:
tutorialStep = "2"
case 3:
tutorialStep = "3"
}
}
teams := []imports.UserTeamImportData{}
possibleTeams := []string{}
for teamName := range teamsAndChannels {
possibleTeams = append(possibleTeams, teamName)
}
sort.Strings(possibleTeams)
for range teamMemberships {
if len(possibleTeams) == 0 {
break
}
position := rand.Intn(len(possibleTeams))
team := possibleTeams[position]
possibleTeams = append(possibleTeams[:position], possibleTeams[position+1:]...)
if teamChannels, err := teamsAndChannels[team]; err {
teams = append(teams, createTeamMembership(channelMemberships, teamChannels, &team, userType == guestUser))
}
}
var deleteAt int64
if userType == deactivatedUser {
deleteAt = model.GetMillis()
}
user := imports.UserImportData{
Avatar: imports.Avatar{
ProfileImage: profileImage,
},
Username: &username,
Email: &email,
Password: &password,
Nickname: &nickname,
FirstName: &firstName,
LastName: &lastName,
Position: &position,
Roles: &roles,
Teams: &teams,
UseMilitaryTime: &useMilitaryTime,
CollapsePreviews: &collapsePreviews,
MessageDisplay: &messageDisplay,
ChannelDisplayMode: &channelDisplayMode,
TutorialStep: &tutorialStep,
DeleteAt: &deleteAt,
}
return imports.LineImportData{
Type: "user",
User: &user,
}
}
func createTeamMembership(numOfchannels int, teamChannels []string, teamName *string, guest bool) imports.UserTeamImportData {
roles := "team_user"
if guest {
roles = "team_guest"
} else if rand.Intn(5) == 0 {
roles = "team_user team_admin"
}
channels := []imports.UserChannelImportData{}
teamChannelsCopy := append([]string(nil), teamChannels...)
for range numOfchannels {
if len(teamChannelsCopy) == 0 {
break
}
position := rand.Intn(len(teamChannelsCopy))
channelName := teamChannelsCopy[position]
teamChannelsCopy = append(teamChannelsCopy[:position], teamChannelsCopy[position+1:]...)
channels = append(channels, createChannelMembership(channelName, guest))
}
return imports.UserTeamImportData{
Name: teamName,
Roles: &roles,
Channels: &channels,
}
}
func createChannelMembership(channelName string, guest bool) imports.UserChannelImportData {
roles := "channel_user"
if guest {
roles = "channel_guest"
} else if rand.Intn(5) == 0 {
roles = "channel_user channel_admin"
}
favorite := rand.Intn(5) == 0
return imports.UserChannelImportData{
Name: &channelName,
Roles: &roles,
Favorite: &favorite,
}
}
func getSampleTeamName(idx int) string {
for {
name := fmt.Sprintf("%s-%d", fake.Word(), idx)
if !model.IsReservedTeamName(name) {
return name
}
}
}
func createTeam(idx int) imports.LineImportData {
displayName := fake.Word()
name := getSampleTeamName(idx)
allowOpenInvite := rand.Intn(2) == 0
description := fake.Paragraph()
if len(description) > 255 {
description = description[0:255]
}
teamType := "O"
if rand.Intn(2) == 0 {
teamType = "I"
}
team := imports.TeamImportData{
DisplayName: &displayName,
Name: &name,
AllowOpenInvite: &allowOpenInvite,
Description: &description,
Type: &teamType,
}
return imports.LineImportData{
Type: "team",
Team: &team,
}
}
func createChannel(idx int, teamName string) imports.LineImportData {
displayName := fake.Word()
name := fmt.Sprintf("%s-%d", fake.Word(), idx)
header := fake.Paragraph()
purpose := fake.Paragraph()
if len(purpose) > 250 {
purpose = purpose[0:250]
}
channelType := model.ChannelTypePrivate
if rand.Intn(2) == 0 {
channelType = model.ChannelTypeOpen
}
channel := imports.ChannelImportData{
Team: &teamName,
Name: &name,
DisplayName: &displayName,
Type: &channelType,
Header: &header,
Purpose: &purpose,
}
return imports.LineImportData{
Type: "channel",
Channel: &channel,
}
}
func createPost(team string, channel string, allUsers []string, createAt int64) imports.LineImportData {
message := randomMessage(allUsers)
user := allUsers[rand.Intn(len(allUsers))]
// Some messages are flagged by a user
flaggedBy := []string{}
if rand.Intn(10) == 0 {
flaggedBy = append(flaggedBy, allUsers[rand.Intn(len(allUsers))])
}
reactions := []app.ReactionImportData{}
if rand.Intn(10) == 0 {
for {
reactions = append(reactions, randomReaction(allUsers, createAt))
if rand.Intn(3) == 0 {
break
}
}
}
replies := []imports.ReplyImportData{}
if rand.Intn(10) == 0 {
for {
replies = append(replies, randomReply(allUsers, createAt))
if rand.Intn(4) == 0 {
break
}
}
}
post := imports.PostImportData{
Team: &team,
Channel: &channel,
User: &user,
Message: &message,
CreateAt: &createAt,
FlaggedBy: &flaggedBy,
Reactions: &reactions,
Replies: &replies,
}
return imports.LineImportData{
Type: "post",
Post: &post,
}
}
func createDirectChannel(members []string) imports.LineImportData {
header := fake.Sentence()
var p []*imports.DirectChannelMemberImportData
for _, m := range members {
p = append(p, &imports.DirectChannelMemberImportData{
Username: model.NewPointer(m),
})
}
channel := imports.DirectChannelImportData{
Participants: p,
Header: &header,
}
return imports.LineImportData{
Type: "direct_channel",
DirectChannel: &channel,
}
}
func createDirectPost(members []string, createAt int64) imports.LineImportData {
message := randomMessage(members)
user := members[rand.Intn(len(members))]
// Some messages are flagged by an user
flaggedBy := []string{}
if rand.Intn(10) == 0 {
flaggedBy = append(flaggedBy, members[rand.Intn(len(members))])
}
reactions := []app.ReactionImportData{}
if rand.Intn(10) == 0 {
for {
reactions = append(reactions, randomReaction(members, createAt))
if rand.Intn(3) == 0 {
break
}
}
}
replies := []imports.ReplyImportData{}
if rand.Intn(10) == 0 {
for {
replies = append(replies, randomReply(members, createAt))
if rand.Intn(4) == 0 {
break
}
}
}
post := imports.DirectPostImportData{
ChannelMembers: &members,
User: &user,
Message: &message,
CreateAt: &createAt,
FlaggedBy: &flaggedBy,
Reactions: &reactions,
Replies: &replies,
}
return imports.LineImportData{
Type: "direct_post",
DirectPost: &post,
}
}