github.com/haalcala/mattermost-server-change-repo/v5@v5.33.2/services/slackimport/converters.go (about)

     1  // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
     2  // See LICENSE.txt for license information.
     3  
     4  package slackimport
     5  
     6  import (
     7  	"regexp"
     8  	"strconv"
     9  	"strings"
    10  
    11  	"github.com/mattermost/mattermost-server/v5/mlog"
    12  )
    13  
    14  func slackConvertTimeStamp(ts string) int64 {
    15  	timeString := strings.SplitN(ts, ".", 2)[0]
    16  
    17  	timeStamp, err := strconv.ParseInt(timeString, 10, 64)
    18  	if err != nil {
    19  		mlog.Warn("Slack Import: Bad timestamp detected.")
    20  		return 1
    21  	}
    22  	return timeStamp * 1000 // Convert to milliseconds
    23  }
    24  
    25  func slackConvertChannelName(channelName string, channelId string) string {
    26  	newName := strings.Trim(channelName, "_-")
    27  	if len(newName) == 1 {
    28  		return "slack-channel-" + newName
    29  	}
    30  
    31  	if isValidChannelNameCharacters(newName) {
    32  		return newName
    33  	}
    34  	return strings.ToLower(channelId)
    35  }
    36  
    37  func slackConvertUserMentions(users []slackUser, posts map[string][]slackPost) map[string][]slackPost {
    38  	var regexes = make(map[string]*regexp.Regexp, len(users))
    39  	for _, user := range users {
    40  		r, err := regexp.Compile("<@" + user.Id + `(\|` + user.Username + ")?>")
    41  		if err != nil {
    42  			mlog.Warn("Slack Import: Unable to compile the @mention, matching regular expression for the Slack user.", mlog.String("user_name", user.Username), mlog.String("user_id", user.Id))
    43  			continue
    44  		}
    45  		regexes["@"+user.Username] = r
    46  	}
    47  
    48  	// Special cases.
    49  	regexes["@here"], _ = regexp.Compile(`<!here\|@here>`)
    50  	regexes["@channel"], _ = regexp.Compile("<!channel>")
    51  	regexes["@all"], _ = regexp.Compile("<!everyone>")
    52  
    53  	for channelName, channelPosts := range posts {
    54  		for postIdx, post := range channelPosts {
    55  			for mention, r := range regexes {
    56  				post.Text = r.ReplaceAllString(post.Text, mention)
    57  				posts[channelName][postIdx] = post
    58  			}
    59  		}
    60  	}
    61  
    62  	return posts
    63  }
    64  
    65  func slackConvertChannelMentions(channels []slackChannel, posts map[string][]slackPost) map[string][]slackPost {
    66  	var regexes = make(map[string]*regexp.Regexp, len(channels))
    67  	for _, channel := range channels {
    68  		r, err := regexp.Compile("<#" + channel.Id + `(\|` + channel.Name + ")?>")
    69  		if err != nil {
    70  			mlog.Warn("Slack Import: Unable to compile the !channel, matching regular expression for the Slack channel.", mlog.String("channel_id", channel.Id), mlog.String("channel_name", channel.Name))
    71  			continue
    72  		}
    73  		regexes["~"+channel.Name] = r
    74  	}
    75  
    76  	for channelName, channelPosts := range posts {
    77  		for postIdx, post := range channelPosts {
    78  			for channelReplace, r := range regexes {
    79  				post.Text = r.ReplaceAllString(post.Text, channelReplace)
    80  				posts[channelName][postIdx] = post
    81  			}
    82  		}
    83  	}
    84  
    85  	return posts
    86  }
    87  
    88  func slackConvertPostsMarkup(posts map[string][]slackPost) map[string][]slackPost {
    89  	regexReplaceAllString := []struct {
    90  		regex *regexp.Regexp
    91  		rpl   string
    92  	}{
    93  		// URL
    94  		{
    95  			regexp.MustCompile(`<([^|<>]+)\|([^|<>]+)>`),
    96  			"[$2]($1)",
    97  		},
    98  		// bold
    99  		{
   100  			regexp.MustCompile(`(^|[\s.;,])\*(\S[^*\n]+)\*`),
   101  			"$1**$2**",
   102  		},
   103  		// strikethrough
   104  		{
   105  			regexp.MustCompile(`(^|[\s.;,])\~(\S[^~\n]+)\~`),
   106  			"$1~~$2~~",
   107  		},
   108  		// single paragraph blockquote
   109  		// Slack converts > character to &gt;
   110  		{
   111  			regexp.MustCompile(`(?sm)^&gt;`),
   112  			">",
   113  		},
   114  	}
   115  
   116  	regexReplaceAllStringFunc := []struct {
   117  		regex *regexp.Regexp
   118  		fn    func(string) string
   119  	}{
   120  		// multiple paragraphs blockquotes
   121  		{
   122  			regexp.MustCompile(`(?sm)^>&gt;&gt;(.+)$`),
   123  			func(src string) string {
   124  				// remove >>> prefix, might have leading \n
   125  				prefixRegexp := regexp.MustCompile(`^([\n])?>&gt;&gt;(.*)`)
   126  				src = prefixRegexp.ReplaceAllString(src, "$1$2")
   127  				// append > to start of line
   128  				appendRegexp := regexp.MustCompile(`(?m)^`)
   129  				return appendRegexp.ReplaceAllString(src, ">$0")
   130  			},
   131  		},
   132  	}
   133  
   134  	for channelName, channelPosts := range posts {
   135  		for postIdx, post := range channelPosts {
   136  			result := post.Text
   137  
   138  			for _, rule := range regexReplaceAllString {
   139  				result = rule.regex.ReplaceAllString(result, rule.rpl)
   140  			}
   141  
   142  			for _, rule := range regexReplaceAllStringFunc {
   143  				result = rule.regex.ReplaceAllStringFunc(result, rule.fn)
   144  			}
   145  			posts[channelName][postIdx].Text = result
   146  		}
   147  	}
   148  
   149  	return posts
   150  }