コード例 #1
0
ファイル: todo.go プロジェクト: errows/slick
func (p *Plugin) detailTask(msg *slick.Message, id string) {
	todo := p.store.Get(msg.Channel)
	index, err := getTaskIndex(id, todo)
	if err != nil {
		msg.ReplyMention("Task not found...")
		return
	}
	task := todo[index]
	msg.Reply(printTaskDetails(task))
}
コード例 #2
0
ファイル: todo.go プロジェクト: errows/slick
func (p *Plugin) deleteTask(msg *slick.Message, id string) {
	todo := p.store.Get(msg.Channel)
	index, err := getTaskIndex(id, todo)
	if err != nil {
		msg.ReplyMention("Task not found...")
		return
	}
	todo = append(todo[:index], todo[index+1:]...)
	p.store.Put(msg.Channel, todo)
	msg.Reply(fmt.Sprintf("Deleted task `%s`", id))
}
コード例 #3
0
ファイル: recognize.go プロジェクト: errows/slick
func (p *Plugin) handleRecognize(listen *slick.Listener, msg *slick.Message) {
	users := msg.Match[1]
	feat := msg.Match[5]

	channel := p.bot.GetChannelByName(p.config.Channel)
	if channel == nil {
		fmt.Println("Didn't find the recognitions, can't handle `!recognition` requests. Searched for:", p.config.Channel)
		return
	}

	recipients := parseRecipients(users)

	if userIsInRecipients(msg.FromUser.ID, recipients) {
		msg.ReplyMention("you can't recognize yourself, can you ?!")
		return
	}

	announcement := p.bot.SendOutgoingMessage(fmt.Sprintf("<@%s|%s> would like to recognize %s\n>>> For %s", msg.FromUser.ID, msg.FromUser.Name, users, feat), channel.ID)

	announcement.AddReaction("+1")
	announcement.AddReaction("dart")
	announcement.AddReaction("tada")
	announcement.AddReaction("100")
	announcement.AddReaction("clap")
	announcement.AddReaction("muscle")
	announcement.AddReaction("nerd_face")
	announcement.AddReaction("joy")

	announcement.OnAck(func(ack *slack.AckMessage) {
		ts := ack.Timestamp
		domain := p.bot.Config.TeamDomain
		url := fmt.Sprintf("https://%s.slack.com/archives/%s/p%s", domain, channel.Name, strings.Replace(ts, ".", "", 1))
		msg.ReplyMention("Great! Everyone can upvote this recognition here %s", url)

		recog := &Recognition{
			MsgTimestamp: ts,
			CreatedAt:    time.Now(),
			Sender:       msg.FromUser.ID,
			Recipients:   recipients,
			Categories:   []string{},
			Reactions: map[string]int{
				msg.FromUser.ID: 1,
			},
		}
		p.store.Put(recog)

		p.bot.PubSub.Pub(recog, "recognition:recognized")

		//fmt.Println("Timestamp for the message:", ts)
	})
}
コード例 #4
0
ファイル: todo.go プロジェクト: errows/slick
func (p *Plugin) handleTodo(listen *slick.Listener, msg *slick.Message) {

	idFormat := regexp.MustCompile(`^[a-z]{2}$`)
	match := msg.Match
	parts := strings.Split(match[0], " ")
	if len(parts) == 1 {
		p.listTasks(msg, false)
		return
	}
	act := parts[1]
	allCommands := map[string]bool{
		"all":            true,
		"-a":             true,
		"--all":          true,
		":allthethings:": true,
	}

	switch act {
	case "add":
		p.createTask(msg)

	case "close", "fix", "scratch", "done", "strike", "ship", ":boom:", "remove":
		if len(parts) < 3 || !idFormat.MatchString(parts[2]) {
			msg.ReplyMention(fmt.Sprintf("Please %s a task with `!todo %s ID`", act, act))
			return
		}
		if act == "remove" {
			p.deleteTask(msg, parts[2])
		} else {
			p.closeTask(msg, parts[2])
		}

	case "list":
		includeClosed := len(parts) > 2 && allCommands[parts[2]]
		p.listTasks(msg, includeClosed)

	case "help":
		p.replyHelp(msg, "")

	default:
		if idFormat.MatchString(act) {
			p.detailTask(msg, act)
		} else {
			p.replyHelp(msg, "Wooops, not sure what you wanted.\n")
		}
	}
}
コード例 #5
0
ファイル: todo.go プロジェクト: errows/slick
func (p *Plugin) closeTask(msg *slick.Message, id string) {
	todo := p.store.Get(msg.Channel)
	index, err := getTaskIndex(id, todo)
	if err != nil {
		msg.ReplyMention("Task not found...")
		return
	}
	parts := strings.Split(msg.Match[0], " ")
	task := todo[index]
	task.Closed = true
	task.ClosedAt = time.Now()
	if len(parts) > 3 {
		task.ClosingNote = strings.Join(parts[3:], " ")
	}
	p.store.Put(msg.Channel, todo)
	msg.Reply("`" + task.ID + "` ~" + strings.Join(task.Text, " // ") + "~ " + task.ClosingNote)
}
コード例 #6
0
ファイル: todo.go プロジェクト: errows/slick
func (p *Plugin) createTask(msg *slick.Message) {
	var text []string
	text = append(text, strings.TrimPrefix(msg.Match[0], "!todo add "))
	todo := p.store.Get(msg.Channel)

	if len(todo) > 600 {
		msg.ReplyMention("Gosh you have over 600 tasks!!! Clean some up first.")
		return
	}

	id := p.generateRandomID(todo)
	task := &Task{
		ID:        id,
		CreatedAt: time.Now(),
		User:      msg.FromUser.ID,
		Text:      text,
		Closed:    false,
	}
	todo = append(todo, task)
	p.store.Put(msg.Channel, todo)
	msg.Reply("`" + task.ID + "` added to the todo")
}
コード例 #7
0
ファイル: wicked.go プロジェクト: errows/slick
func (wicked *Wicked) ChatHandler(listen *slick.Listener, msg *slick.Message) {
	bot := listen.Bot
	uuidNow := time.Now()

	if strings.HasPrefix(msg.Text, "!wicked ") {
		fromRoom := ""
		if msg.FromChannel != nil {
			fromRoom = msg.FromChannel.ID
		}

		availableRoom := wicked.FindAvailableRoom(fromRoom)

		if availableRoom == nil {
			msg.Reply("No available Wicked Confroom for a meeting! Seems you'll need to create new Wicked Confrooms !")
			goto continueLogging
		}

		id := wicked.NextMeetingID()
		meeting := NewMeeting(id, msg.FromUser, msg.Text[7:], bot, availableRoom, uuidNow)

		wicked.pastMeetings = append(wicked.pastMeetings, meeting)
		wicked.meetings[availableRoom.ID] = meeting

		if availableRoom.ID == fromRoom {
			meeting.sendToRoom(fmt.Sprintf(`*** Starting wicked meeting W%s in here.`, meeting.ID))
		} else {
			msg.Reply(fmt.Sprintf(`*** Starting wicked meeting W%s in room "%s". Join with !join W%s`, meeting.ID, availableRoom.Name, meeting.ID))
			initiatedFrom := ""
			if fromRoom != "" {
				initiatedFrom = fmt.Sprintf(` in "%s"`, msg.FromChannel.Name)
			}
			meeting.sendToRoom(fmt.Sprintf(`*** Wicked meeting initiated by @%s%s. Goal: %s`, msg.FromUser.Name, initiatedFrom, meeting.Goal))
		}

		meeting.sendToRoom(fmt.Sprintf(`*** Access report at %s/wicked/%s.html`, wicked.bot.Config.WebBaseURL, meeting.ID))
		meeting.setTopic(fmt.Sprintf(`[Running] W%s goal: %s`, meeting.ID, meeting.Goal))
	} else if strings.HasPrefix(msg.Text, "!join") {
		match := joinMatcher.FindStringSubmatch(msg.Text)
		if match == nil {
			msg.ReplyMention(`invalid !join syntax. Use something like "!join W123"`)
		} else {
			for _, meeting := range wicked.meetings {
				if match[1] == meeting.ID {
					meeting.sendToRoom(fmt.Sprintf(`*** @%s asked to join`, msg.FromUser.Name))
				}
			}
		}
	}

continueLogging:

	//
	// Public commands and messages
	//
	if msg.FromChannel == nil {
		return
	}
	room := msg.FromChannel.ID
	meeting, meetingExists := wicked.meetings[room]
	if !meetingExists {
		return
	}

	user := meeting.ImportUser(msg.FromUser)

	if strings.HasPrefix(msg.Text, "!proposition ") {
		decision := meeting.AddDecision(user, msg.Text[12:], uuidNow)
		if decision == nil {
			msg.Reply("Whoops, wrong syntax for !proposition")
		} else {
			msg.Reply(fmt.Sprintf("Proposition added, ref: D%s", decision.ID))
		}

	} else if strings.HasPrefix(msg.Text, "!ref ") {

		meeting.AddReference(user, msg.Text[4:], uuidNow)
		msg.Reply("Ref. added")

	} else if strings.HasPrefix(msg.Text, "!conclude") {
		meeting.Conclude()
		// TODO: kill all waiting goroutines dealing with messaging
		delete(wicked.meetings, room)
		meeting.sendToRoom("Concluding Wicked meeting, that's all folks!")
		meeting.setTopic(fmt.Sprintf(`[Concluded] W%s goal: %s`, meeting.ID, meeting.Goal))

	} else if match := decisionMatcher.FindStringSubmatch(msg.Text); match != nil {

		decision := meeting.GetDecisionByID(match[1])
		if decision != nil {
			decision.RecordPlusplus(user)
			msg.ReplyMention("noted")
		}

	}

	// Log message
	newMessage := &Message{
		From:      user,
		Timestamp: uuidNow,
		Text:      msg.Text,
	}
	meeting.Logs = append(meeting.Logs, newMessage)
}
コード例 #8
0
ファイル: funny.go プロジェクト: Skarlso/slick
func (funny *Funny) ChatHandler(listen *slick.Listener, msg *slick.Message) {
	bot := listen.Bot

	if msg.Contains("mama") {
		listen.Bot.Listen(&slick.Listener{
			ListenDuration: time.Duration(10 * time.Second),
			MessageHandlerFunc: func(listen *slick.Listener, msg *slick.Message) {
				if strings.Contains(msg.Text, "papa") {
					msg.Reply("3s", "yo rocker").DeleteAfter("3s")
					msg.AddReaction("wink")
					go func() {
						time.Sleep(3 * time.Second)
						msg.AddReaction("beer")
						time.Sleep(1 * time.Second)
						msg.RemoveReaction("wink")
					}()
				}
			},
		})
	}

	if msg.MentionsMe {
		if msg.Contains("you're funny") {

			if bot.Mood == slick.Happy {
				msg.Reply("/me blushes")
			} else {
				msg.Reply("here's another one")
				msg.Reply(slick.RandomString("robot jokes"))
			}

		} else if msg.ContainsAny([]string{"dumb ass", "dumbass"}) {

			msg.Reply("don't say such things")

		} else if msg.ContainsAny([]string{"thanks", "thank you", "thx", "thnks"}) {
			msg.Reply(bot.WithMood("my pleasure", "any time, just ask, I'm here for you, ffiieeewww!get a life"))

		} else if msg.Contains("how are you") && msg.MentionsMe {
			msg.ReplyMention(bot.WithMood("good, and you ?", "I'm wild today!! wadabout you ?"))
			bot.Listen(&slick.Listener{
				ListenDuration: 60 * time.Second,
				FromUser:       msg.FromUser,
				FromChannel:    msg.FromChannel,
				MentionsMeOnly: true,
				MessageHandlerFunc: func(listen *slick.Listener, msg *slick.Message) {
					msg.ReplyMention(bot.WithMood("glad to hear it!", "zwweeeeeeeeet !"))
					listen.Close()
				},
				TimeoutFunc: func(listen *slick.Listener) {
					msg.ReplyMention("well, we can catch up later")
					listen.Close()
				},
			})
		}
	}

	if msg.ContainsAny([]string{"lot of excitement", "that's exciting", "how exciting", "much excitement"}) {

		msg.Reply("http://static.fjcdn.com/gifs/Japanese+kids+spongebob+toys_0ad21b_3186721.gif")

	} else if msg.ContainsAny([]string{"what is your problem", "what's your problem", "is there a problem", "which problem"}) {

		msg.Reply("http://media4.giphy.com/media/19hU0m3TJe6I/200w.gif")

	} else if msg.Contains("force push") {

		url := slick.RandomString("forcePush")
		msg.Reply(url)

	} else if msg.ContainsAny([]string{"there is a bug", "there's a bug"}) {

		msg.Reply("https://s3.amazonaws.com/pushbullet-uploads/ujy7DF0U8wm-9YYvLZkmSM8pMYcxCXXig8LjJORE9Xzt/The-life-of-a-coder.jpg")

	} else if msg.ContainsAny([]string{"oh yeah", "approved"}) {

		msg.Reply("https://i.chzbgr.com/maxW250/4496881920/h9C58F860.gif")

	} else if msg.Contains("ice cream") {

		msg.Reply("http://i.giphy.com/IGyLuFXIGSJj2.gif")
		msg.Reply("I love ice cream too")

	} else if msg.ContainsAny([]string{"lot of tension", "some tension", " tensed"}) {

		msg.Reply("http://thumbpress.com/wp-content/uploads/2014/01/funny-gif-meeting-strangers-girl-scared1.gif")
		msg.Reply("tensed, like that ?")

	} else if msg.Contains("quick fix") {

		msg.Reply("http://blog.pgi.com/wp-content/uploads/2013/02/jim-carey.gif")
		msg.Reply("make it real quick")

	} else if msg.ContainsAny([]string{"crack an egg", "crack something", "to crack"}) {

		msg.Reply("http://s3-ec.buzzfed.com/static/enhanced/webdr02/2012/11/8/18/anigif_enhanced-buzz-31656-1352415875-9.gif")
		msg.Reply("crack an egg, yeah")

	} else if msg.ContainsAny([]string{"i'm stuck", "I'm stuck", "we're stuck"}) {

		msg.Reply("http://media.giphy.com/media/RVlWx1msxnf7W/giphy.gif")
		msg.Reply("I'm stuck too!")

	} else if msg.ContainsAny([]string{"watching tv", "watch tv"}) {

		msg.Reply("http://i0.kym-cdn.com/photos/images/newsfeed/000/495/040/9ab.gif")
		msg.Reply("like that ?")

	} else if msg.ContainsAny([]string{"spider", "pee on", "inappropriate"}) {

		msg.Reply("https://i.chzbgr.com/maxW500/5626597120/hB2E11E61.gif")

	} else if msg.ContainsAny([]string{"a meeting", "an interview"}) {

		msg.Reply("like this one")
		msg.Reply("https://i.chzbgr.com/maxW500/6696664320/hFC69678C.gif")

	} else if msg.ContainsAny([]string{"it's odd", "it is odd", "that's odd", "that is odd", "it's awkward", "it is awkward", "that's awkward", "that is awkward"}) {

		term := "awkward"
		if msg.Contains("odd") {
			term = "odd"
		}
		msg.Reply(fmt.Sprintf("THAT's %s", term))
		msg.Reply("https://i.chzbgr.com/maxW500/8296294144/h7AC1001C.gif")

	} else if msg.Text == "ls" {

		msg.Reply("/code deploy/      Contributors-Guide/ image_server/     sheep_porn/     streambed/\nstreamhead/  README.md")

	} else if msg.ContainsAny([]string{"that's really cool", "that is really cool", "really happy"}) {

		msg.Reply("http://media.giphy.com/media/BlVnrxJgTGsUw/giphy.gif")

	} else if msg.ContainsAny([]string{"difficult problem", "hard problem"}) {

		msg.Reply("naming things, cache invalidation and off-by-1 errors are the two most difficult computer science problems")

	} else if msg.Contains("in theory") {

		msg.Reply("yeah, theory and practice perfectly match... in theory.")
	} else if msg.Contains("dishes") {

		msg.Reply(slick.RandomString("dishes"))

	} else if msg.Contains(" bean") {

		msg.Reply("http://media3.giphy.com/media/c35RMDO6luMaQ/500w.gif")

	} else if msg.Contains("steak") {

		msg.Reply("http://media.tumblr.com/tumblr_me6r52h1md1r6nno1.gif")

	} else if msg.ContainsAny([]string{"booze", "alcohol", "martini", " dog "}) {

		msg.Reply("http://media2.giphy.com/media/ZmJBjPdd44gXS/200w.gif")

	} else if msg.ContainsAny([]string{"internet", " tube "}) {

		msg.Reply("https://pbs.twimg.com/media/By0J3YHCcAA4UBo.jpg:large")

	}
}
コード例 #9
0
ファイル: totw.go プロジェクト: Skarlso/slick
func (totw *Totw) ChatHandler(conv *slick.Listener, msg *slick.Message) {
	if strings.HasPrefix(msg.Text, "!totw") || strings.HasPrefix(msg.Text, "!techoftheweek") {
		msg.ReplyMention(slick.RandomString("tech adept"))
	}
}
コード例 #10
0
ファイル: vote.go プロジェクト: Skarlso/slick
func (v *Vote) voteHandler(listen *slick.Listener, msg *slick.Message) {
	v.mutex.Lock()
	defer v.mutex.Unlock()

	bot := v.bot
	// TODO:    ok, @kat wants to survey what's for lunch, use "!vote The Food Place http://food-place.url" .. you can vote for the same place with a substring: "!vote food place"
	// TODO: match "!vote Mucha Dogs http://bigdogs.com"
	// TODO: match "!vote mucha dogs"
	// TODO: match "!vote Other place

	if msg.Text == "!what-for-lunch" || msg.Text == "!vote-for-lunch" {
		msg.ReplyMention("you can say `!what-for-lunch 5m` to get a vote that will last 5 minutes. `!vote-for-lunch` is an alias")
		return
	}

	if msg.HasPrefix("!what-for-lunch ") || msg.HasPrefix("!vote-for-lunch ") {
		if v.runningVotes[msg.FromChannel.ID] != nil {
			msg.ReplyMention("vote is already running!").DeleteAfter("3s")
			return
		}

		timing := strings.TrimSpace(strings.SplitN(msg.Text, " ", 2)[1])
		dur, err := time.ParseDuration(timing)
		if err != nil {
			msg.ReplyMention(fmt.Sprintf("couldn't parse duration: %s", err))
			return
		}

		v.runningVotes[msg.FromChannel.ID] = make([]vote, 0)

		go func() {
			time.Sleep(dur)

			v.mutex.Lock()
			defer v.mutex.Unlock()

			res := make(map[string]int)
			for _, oneVote := range v.runningVotes[msg.FromChannel.ID] {
				res[oneVote.vote] = res[oneVote.vote] + 1
			}

			// TODO: print report, clear up
			if len(res) == 0 {
				msg.ReplyMention("polls closed, but no one voted")
			} else {
				out := []string{"polls closed, here are the results:"}
				for theVote, count := range res {
					plural := ""
					if count > 1 {
						plural = "s"
					}
					out = append(out, fmt.Sprintf("* %s: %d vote%s", theVote, count, plural))
				}
				msg.ReplyMention(strings.Join(out, "\n"))
			}

			delete(v.runningVotes, msg.FromChannel.ID)
		}()

		msg.Reply("<!channel> okay, what do we eat ? Votes are open. Use `!vote The Food Place http://food-place.url` .. you can vote for the same place with a substring, ex: `!vote food place`")

	}

	if msg.HasPrefix("!vote ") {
		running := v.runningVotes[msg.FromChannel.ID]
		if running == nil {
			msg.Reply(bot.WithMood("what vote ?!", "oh you're so cute! voting while there's no vote going on !"))
			return
		}

		voteCast := strings.TrimSpace(strings.SplitN(msg.Text, " ", 2)[1])
		if len(voteCast) == 0 {
			return
		}

		// TODO: check for dupe
		for _, prevVote := range running {
			if msg.FromUser.ID == prevVote.user {
				// buzz off if you voted already
				msg.ReplyMention(bot.WithMood("you voted already", "trying to double vote ! how charming :)"))
				return
			}
		}

		for _, prevVote := range running {
			if strings.Contains(strings.ToLower(prevVote.vote), strings.ToLower(voteCast)) {
				running = append(running, vote{msg.FromUser.ID, prevVote.vote})
				v.runningVotes[msg.FromChannel.ID] = running
				msg.ReplyMention(bot.WithMood("okay", "hmmm kaay")).DeleteAfter("2s")
				return
			}
		}
		running = append(running, vote{msg.FromUser.ID, voteCast})
		v.runningVotes[msg.FromChannel.ID] = running
		msg.ReplyMention(bot.WithMood("taking note", "taking note! what a creative mind...")).DeleteAfter("2s")

		// TODO: match "!what-for-lunch 1h|5m|50s"

	}
}