Skip to content

Commit

Permalink
Add option to choose name generator (#40)
Browse files Browse the repository at this point in the history
  • Loading branch information
jespino committed May 19, 2020
1 parent a4fe8d9 commit 45ef3e2
Show file tree
Hide file tree
Showing 7 changed files with 179 additions and 17 deletions.
1 change: 1 addition & 0 deletions go.mod
Expand Up @@ -4,6 +4,7 @@ go 1.12

require (
github.com/cristalhq/jwt/v2 v2.0.0
github.com/google/uuid v1.1.1
github.com/mattermost/mattermost-server/v5 v5.22.0
github.com/pkg/errors v0.9.1
)
37 changes: 37 additions & 0 deletions plugin.json
Expand Up @@ -51,6 +51,43 @@
"type": "number",
"help_text": "How many minutes is the generated link active, if set smaller then 1, valid time is automaticaly set to 30 minutes.",
"default": 30
},
{
"key": "JitsiNamingScheme",
"display_name": "Meeting naming scheme",
"type": "radio",
"help_text": "How should the plugin choose a meeting name? Some names may cause conflicts if you use them on a public server, like meet.jit.si.",
"default": "english-titlecase",
"options": [
{
"display_name": "English words, title-case (e.g. PlayfulDragonsObserveCuriously)",
"value": "english-titlecase"
},
{
"display_name": "English words, kebab-case (e.g. playful-dragons-observe-curiously)",
"value": "english-kebabcase"
},
{
"display_name": "UUID",
"value": "uuid"
},
{
"display_name": "10 digit code (name conflict risk!)",
"value": "digits"
},
{
"display_name": "10 letter code (name conflict risk!)",
"value": "letters"
},
{
"display_name": "Team name and channel name",
"value": "teamchannel"
},
{
"display_name": "Team name and channel name plus a random hash (More secure)",
"value": "teamchannel-salt"
}
]
}
]
}
Expand Down
10 changes: 8 additions & 2 deletions server/api.go
Expand Up @@ -37,7 +37,7 @@ func (p *Plugin) handleStartMeeting(w http.ResponseWriter, r *http.Request) {
return
}

_, appErr := p.API.GetUser(userID)
user, appErr := p.API.GetUser(userID)
if appErr != nil {
http.Error(w, "Forbidden", http.StatusForbidden)
return
Expand All @@ -54,7 +54,13 @@ func (p *Plugin) handleStartMeeting(w http.ResponseWriter, r *http.Request) {
return
}

meetingID, err := p.startMeeting(userID, req.ChannelId, req.Topic, req.Personal)
channel, appErr := p.API.GetChannel(req.ChannelId)
if appErr != nil {
http.Error(w, "Forbidden", http.StatusForbidden)
return
}

meetingID, err := p.startMeeting(user, channel, req.Topic, req.Personal)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
Expand Down
32 changes: 23 additions & 9 deletions server/command.go
Expand Up @@ -10,18 +10,32 @@ import (

const jitsiCommand = "meet"

func commandError(channelId string, detailedError string) (*model.CommandResponse, *model.AppError) {
return &model.CommandResponse{
ResponseType: model.COMMAND_RESPONSE_TYPE_EPHEMERAL,
ChannelId: channelId,
Text: "We could not start a meeting at this time.",
}, &model.AppError{
Message: "We could not start a meeting at this time.",
DetailedError: detailedError,
}
}

func (p *Plugin) ExecuteCommand(c *plugin.Context, args *model.CommandArgs) (*model.CommandResponse, *model.AppError) {
input := strings.TrimSpace(strings.TrimPrefix(args.Command, "/"+jitsiCommand))

if _, err := p.startMeeting(args.UserId, args.ChannelId, input, false); err != nil {
return &model.CommandResponse{
ResponseType: model.COMMAND_RESPONSE_TYPE_EPHEMERAL,
ChannelId: args.ChannelId,
Text: "We could not start a meeting at this time.",
}, &model.AppError{
Message: "We could not start a meeting at this time.",
DetailedError: fmt.Sprintf("startMeeting() threw error: %s", err),
}
user, appErr := p.API.GetUser(args.UserId)
if appErr != nil {
return commandError(args.ChannelId, fmt.Sprintf("getUser() threw error: %s", appErr))
}

channel, appErr := p.API.GetChannel(args.ChannelId)
if appErr != nil {
return commandError(args.ChannelId, fmt.Sprintf("getChannel() threw error: %s", appErr))
}

if _, err := p.startMeeting(user, channel, input, false); err != nil {
return commandError(args.ChannelId, fmt.Sprintf("startMeeting() threw error: %s", appErr))
}

return &model.CommandResponse{}, nil
Expand Down
1 change: 1 addition & 0 deletions server/configuration.go
Expand Up @@ -28,6 +28,7 @@ type configuration struct {
JitsiAppID string
JitsiAppSecret string
JitsiLinkValidTime int
JitsiNamingScheme string
}

// Clone shallow copies the configuration. Your implementation may require a deep copy if
Expand Down
34 changes: 30 additions & 4 deletions server/plugin.go
Expand Up @@ -54,11 +54,37 @@ type Claims struct {
Room string `json:"room,omitempty"`
}

func (p *Plugin) startMeeting(userID string, channelID string, meetingTopic string, personal bool) (string, error) {
func (p *Plugin) startMeeting(user *model.User, channel *model.Channel, meetingTopic string, personal bool) (string, error) {
var meetingID string
meetingID = encodeJitsiMeetingID(meetingTopic)

if len(meetingTopic) < 1 {
meetingID = generateRoomWithoutSeparator()
namingScheme := p.getConfiguration().JitsiNamingScheme

var channelName string
var teamName string

if namingScheme == "teamchannel" || namingScheme == "teamchannel-salt" {
meetingTopic = channel.DisplayName + " Meeting"
channelName = channel.Name
teamName = ""
if channel.Type == model.CHANNEL_DIRECT {
channelName = channel.Name
meetingTopic = user.GetDisplayName(model.SHOW_NICKNAME_FULLNAME) + "'s Meeting"
} else if channel.Type == model.CHANNEL_GROUP {
channelName = channel.Name
meetingTopic = channel.DisplayName + " Meeting"
} else {
team, teamErr := p.API.GetTeam(channel.TeamId)
if teamErr != nil {
teamName = "unknown-team"
} else {
teamName = team.Name
}
}
}

meetingID = generateNameFromSelectedScheme(namingScheme, teamName, channelName)
}
jitsiURL := strings.TrimSpace(p.getConfiguration().JitsiURL)
jitsiURL = strings.TrimRight(jitsiURL, "/")
Expand Down Expand Up @@ -97,8 +123,8 @@ func (p *Plugin) startMeeting(userID string, channelID string, meetingTopic stri
}

post := &model.Post{
UserId: userID,
ChannelId: channelID,
UserId: user.Id,
ChannelId: channel.Id,
Message: fmt.Sprintf("Meeting started at %s.", meetingURL),
Type: "custom_jitsi",
Props: map[string]interface{}{
Expand Down
81 changes: 79 additions & 2 deletions server/randomNameGenerator.go
Expand Up @@ -2,7 +2,10 @@ package main

import (
"math/rand"
"strings"
"time"

"github.com/google/uuid"
)

var PLURALNOUN = []string{"Aliens", "Animals", "Antelopes", "Ants", "Apes", "Apples", "Baboons",
Expand Down Expand Up @@ -101,11 +104,85 @@ var ADJECTIVE = []string{"Abominable", "Accurate", "Adorable", "All", "Alleged",
"Warm", "Weak", "Weird", "WellCooked", "Wild", "Wise", "Witty", "Wonderful",
"Worried", "Yellow", "Young", "Zealous"}

var LETTERS = []rune("abcdefghijklmnopqrstuvwxyz")
var NUMBERS = []rune("0123456789")

func randomElement(s []string) string {
rand.Seed(time.Now().UnixNano())
return s[rand.Intn(len(s)-1)]
}

func generateRoomWithoutSeparator() string {
return (randomElement(ADJECTIVE) + randomElement(PLURALNOUN) + randomElement(VERB) + randomElement(ADVERB))
func randomString(runes []rune, n int) string {
b := make([]rune, n)
for i := range b {
b[i] = runes[rand.Intn(len(runes))]
}
return string(b)
}

func generateEnglishName(delimiter string) string {
var components = []string{
randomElement(ADJECTIVE),
randomElement(PLURALNOUN),
randomElement(VERB),
randomElement(ADVERB),
}
return strings.Join(components, delimiter)
}

func generateEnglishTitleName() string {
return generateEnglishName("")
}

func generateEnglishKebabName() string {
return strings.ToLower(generateEnglishName("-"))
}

func generateUUIDName() string {
id := uuid.New()
return (id.String())
}

func generateDigitsName() string {
return randomString(NUMBERS, 10)
}

func generateLettersName() string {
return randomString(LETTERS, 10)
}

func generateTeamChannelName(teamName string, channelName string, salt bool) string {
name := teamName
if name != "" {
name += "-"
}

name += channelName

if salt {
id := uuid.New()
name += "-" + id.String()
}
return name
}

func generateNameFromSelectedScheme(namingScheme string, teamName string, channelName string) string {
switch namingScheme {
case "english-titlecase":
return generateEnglishTitleName()
case "english-kebabcase":
return generateEnglishKebabName()
case "uuid":
return generateUUIDName()
case "digits":
return generateDigitsName()
case "letters":
return generateLettersName()
case "teamchannel":
return generateTeamChannelName(teamName, channelName, false)
case "teamchannel-salt":
return generateTeamChannelName(teamName, channelName, true)
default:
return generateEnglishTitleName()
}
}

0 comments on commit 45ef3e2

Please sign in to comment.