Added support for creating slack channels with reference to a weekday, added support for specifying users to always add to a channel, maybe more?
This commit is contained in:
		
							parent
							
								
									e6ef66194e
								
							
						
					
					
						commit
						2354e60b3d
					
				
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@ -1,3 +1,4 @@
 | 
				
			|||||||
config.yaml
 | 
					config.yaml
 | 
				
			||||||
service-notifications
 | 
					service-notifications
 | 
				
			||||||
service-notifications.db
 | 
					service-notifications.db
 | 
				
			||||||
 | 
					sync.sh
 | 
				
			||||||
@ -110,6 +110,7 @@ Get Slack API token by creating an app at https://api.slack.com/apps then go to
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
Get Planning Center API secrets at https://api.planningcenteronline.com/oauth/applications by creating a personal access token.
 | 
					Get Planning Center API secrets at https://api.planningcenteronline.com/oauth/applications by creating a personal access token.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					You can get a slack user ID by viewing the profile and under the 3 dot menu choose Copy member ID.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```yaml
 | 
					```yaml
 | 
				
			||||||
---
 | 
					---
 | 
				
			||||||
@ -122,6 +123,9 @@ planning_center:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
slack:
 | 
					slack:
 | 
				
			||||||
    api_token: SLACK_API_TOKEN
 | 
					    api_token: SLACK_API_TOKEN
 | 
				
			||||||
    admin_id: SLACK_UID
 | 
					    create_from_weekday: 3
 | 
				
			||||||
 | 
					    default_conversation: SLACK_UID
 | 
				
			||||||
 | 
						sticky_users:
 | 
				
			||||||
 | 
					        - SLACK_UID
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
							
								
								
									
										2
									
								
								api.go
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								api.go
									
									
									
									
									
								
							@ -96,7 +96,7 @@ func (s *HTTPServer) RegisterAPIRoutes(r *mux.Router) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		// Get current time and default conversation.
 | 
							// Get current time and default conversation.
 | 
				
			||||||
		now := time.Now().UTC()
 | 
							now := time.Now().UTC()
 | 
				
			||||||
		conversation := app.config.Slack.AdminID
 | 
							conversation := app.config.Slack.DefaultConversation
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Find plan times that are occuring right now.
 | 
							// Find plan times that are occuring right now.
 | 
				
			||||||
		var planTime PlanTimes
 | 
							var planTime PlanTimes
 | 
				
			||||||
 | 
				
			|||||||
@ -35,9 +35,11 @@ type PlanningCenterConfig struct {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// Configurations relating to Slack API/channel creation.
 | 
					// Configurations relating to Slack API/channel creation.
 | 
				
			||||||
type SlackConfig struct {
 | 
					type SlackConfig struct {
 | 
				
			||||||
 | 
						CreateFromWeekday   int           `fig:"create_from_weekday"`   // Create ahead from this weekday. -1 value is default and will instead create from the current time of operation.
 | 
				
			||||||
	CreateChannelsAhead time.Duration `fig:"create_channels_ahead"` // Amount of time of future services to create channels head for. Defaults to 8 days head.
 | 
						CreateChannelsAhead time.Duration `fig:"create_channels_ahead"` // Amount of time of future services to create channels head for. Defaults to 8 days head.
 | 
				
			||||||
	APIToken            string        `fig:"api_token"`
 | 
						APIToken            string        `fig:"api_token"`
 | 
				
			||||||
	AdminID             string        `fig:"admin_id"` // Slack user that administers this app.
 | 
						StickyUsers         []string      `fig:"sticky_users"`         // Users to add to every channel.
 | 
				
			||||||
 | 
						DefaultConversation string        `fig:"default_conversation"` // Slack user that administers this app.
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Configuration Structure.
 | 
					// Configuration Structure.
 | 
				
			||||||
@ -86,6 +88,7 @@ func (a *App) ReadConfig() {
 | 
				
			|||||||
			Connection: "service-notifications.db",
 | 
								Connection: "service-notifications.db",
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		Slack: SlackConfig{
 | 
							Slack: SlackConfig{
 | 
				
			||||||
 | 
								CreateFromWeekday:   -1,
 | 
				
			||||||
			CreateChannelsAhead: time.Hour * 24 * 8,
 | 
								CreateChannelsAhead: time.Hour * 24 * 8,
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										2
									
								
								main.go
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								main.go
									
									
									
									
									
								
							@ -13,7 +13,7 @@ import (
 | 
				
			|||||||
const (
 | 
					const (
 | 
				
			||||||
	serviceName        = "service-notifications"
 | 
						serviceName        = "service-notifications"
 | 
				
			||||||
	serviceDescription = "Notifications for church services"
 | 
						serviceDescription = "Notifications for church services"
 | 
				
			||||||
	serviceVersion     = "0.1"
 | 
						serviceVersion     = "0.2"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// App is the global application structure for communicating between servers and storing information.
 | 
					// App is the global application structure for communicating between servers and storing information.
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										85
									
								
								update.go
									
									
									
									
									
								
							
							
						
						
									
										85
									
								
								update.go
									
									
									
									
									
								
							@ -13,6 +13,19 @@ import (
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// Update planning center database tables with data from PC API.
 | 
					// Update planning center database tables with data from PC API.
 | 
				
			||||||
func UpdatePCData() {
 | 
					func UpdatePCData() {
 | 
				
			||||||
 | 
						// We don't need to update the archive if we already have data from the past,
 | 
				
			||||||
 | 
						// as such we get the current time and see if we already have an entry in the future.
 | 
				
			||||||
 | 
						// Its possible that some people only schedule services once a week, so we check with
 | 
				
			||||||
 | 
						// the current date subtracted by 14 days.
 | 
				
			||||||
 | 
						var updateFrom time.Time
 | 
				
			||||||
 | 
						now := time.Now().UTC()
 | 
				
			||||||
 | 
						var futurePlan Plans
 | 
				
			||||||
 | 
						app.db.Where("first_time_at >= ?", now.Add(time.Hour*24*14*-1)).Order("first_time_at ASC").First(&futurePlan)
 | 
				
			||||||
 | 
						if futurePlan.ID != 0 {
 | 
				
			||||||
 | 
							// If a future plan exists, we update from past 30 days.
 | 
				
			||||||
 | 
							updateFrom = now.Add(time.Hour * 24 * 30 * -1)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Get all people.
 | 
						// Get all people.
 | 
				
			||||||
	allPeople, err := PCGetAll("/services/v2/people")
 | 
						allPeople, err := PCGetAll("/services/v2/people")
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
@ -118,6 +131,13 @@ func UpdatePCData() {
 | 
				
			|||||||
			p.MultiDay = attributes.GetBool("multi_day")
 | 
								p.MultiDay = attributes.GetBool("multi_day")
 | 
				
			||||||
			p.Dates = attributes.GetString("dates")
 | 
								p.Dates = attributes.GetString("dates")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// If either updated at or first time at for the plan is before the update from date,
 | 
				
			||||||
 | 
								// we can process the update of data. Otherwise, we ignore this service as we do not care
 | 
				
			||||||
 | 
								// about updating historic data. Updating historic data causes more API traffic than needed.
 | 
				
			||||||
 | 
								if p.UpdatedAt.Before(updateFrom) && p.FirstTimeAt.Before(updateFrom) {
 | 
				
			||||||
 | 
									continue
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			// If plan wasn't already created, create it.
 | 
								// If plan wasn't already created, create it.
 | 
				
			||||||
			if p.ID == 0 {
 | 
								if p.ID == 0 {
 | 
				
			||||||
				p.ID = planID
 | 
									p.ID = planID
 | 
				
			||||||
@ -291,13 +311,41 @@ func UpdateSlackData() {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Delay on channel descript/topic may not be long enough.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Create slack channels for upcoming services.
 | 
					// Create slack channels for upcoming services.
 | 
				
			||||||
func CreateSlackChannels() {
 | 
					func CreateSlackChannels() {
 | 
				
			||||||
	// For now, we're using the start time of now. I want to update this later to allow
 | 
						// Start at now.
 | 
				
			||||||
	// setting a day of the week for slack channels to be created on.
 | 
						now := time.Now().UTC()
 | 
				
			||||||
	// Doing a day of the week will allow for channels to be created ahead of time, then
 | 
						startDate := now
 | 
				
			||||||
	// if people are added to the plan later on, they can be added at the next cron run.
 | 
						// If create from weekday is a valid weekday, attempt to turn back the clock to the
 | 
				
			||||||
	startDate := time.Now().UTC()
 | 
						// most recently past weekday. Use that day as the stating point so we do not
 | 
				
			||||||
 | 
						// create channels in the future past the date we expect to have channels.
 | 
				
			||||||
 | 
						// This is useful if you want to run the cron every day to keep channel title
 | 
				
			||||||
 | 
						// and members up to date, but only want so many channels ahead of a certain weekday.
 | 
				
			||||||
 | 
						if app.config.Slack.CreateFromWeekday != -1 && app.config.Slack.CreateFromWeekday <= 6 {
 | 
				
			||||||
 | 
							// Get the current weekday and set the days to subtract to 0.
 | 
				
			||||||
 | 
							thisWeekday := int(now.Weekday())
 | 
				
			||||||
 | 
							var daysSub int = 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// If this weekday is the day we intend to create from, or if the weekday is
 | 
				
			||||||
 | 
							// after. We want to just subtract this weekday from create form weekday which
 | 
				
			||||||
 | 
							// should get us back to the most recent weekday.
 | 
				
			||||||
 | 
							if thisWeekday >= app.config.Slack.CreateFromWeekday {
 | 
				
			||||||
 | 
								daysSub = app.config.Slack.CreateFromWeekday - thisWeekday
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								// Otherwise, we have started a new week from that weekday and we need to
 | 
				
			||||||
 | 
								// add 7 days to the current weekday in our subtraction. This will bring us
 | 
				
			||||||
 | 
								// not to the next weekday, but the past weekday.
 | 
				
			||||||
 | 
								daysSub = app.config.Slack.CreateFromWeekday - (thisWeekday + 7)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							// Subtract the number of days calculated to bring us to the weekday to create form.
 | 
				
			||||||
 | 
							startDate = now.Add(time.Hour * 24 * time.Duration(daysSub))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	// Last date is start date plus duration of create channels ahead.
 | 
						// Last date is start date plus duration of create channels ahead.
 | 
				
			||||||
	lastDate := startDate.Add(app.config.Slack.CreateChannelsAhead)
 | 
						lastDate := startDate.Add(app.config.Slack.CreateChannelsAhead)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -391,7 +439,7 @@ func CreateSlackChannels() {
 | 
				
			|||||||
			if topic != "" {
 | 
								if topic != "" {
 | 
				
			||||||
				// Sleep before, as it takes time for Slack APIs
 | 
									// Sleep before, as it takes time for Slack APIs
 | 
				
			||||||
				// to recongize the channel was created.
 | 
									// to recongize the channel was created.
 | 
				
			||||||
				time.Sleep(10 * time.Second)
 | 
									time.Sleep(120 * time.Second)
 | 
				
			||||||
				_, err = app.slack.SetTopicOfConversation(channel.ID, topic)
 | 
									_, err = app.slack.SetTopicOfConversation(channel.ID, topic)
 | 
				
			||||||
				if err != nil {
 | 
									if err != nil {
 | 
				
			||||||
					log.Println("Failed to set topic:", err)
 | 
										log.Println("Failed to set topic:", err)
 | 
				
			||||||
@ -421,6 +469,31 @@ func CreateSlackChannels() {
 | 
				
			|||||||
		// Keep a list of users we need to invite as they are new.
 | 
							// Keep a list of users we need to invite as they are new.
 | 
				
			||||||
		var usersToInvite []string
 | 
							var usersToInvite []string
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// For each sticky user, invite them.
 | 
				
			||||||
 | 
							for _, stickyUser := range app.config.Slack.StickyUsers {
 | 
				
			||||||
 | 
								// Check if they were already invited.
 | 
				
			||||||
 | 
								alreadyInvited := false
 | 
				
			||||||
 | 
								for _, uid := range invited {
 | 
				
			||||||
 | 
									if uid == stickyUser {
 | 
				
			||||||
 | 
										alreadyInvited = true
 | 
				
			||||||
 | 
										break
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// Make sure they were not already added to the list of users.
 | 
				
			||||||
 | 
								for _, uid := range usersToInvite {
 | 
				
			||||||
 | 
									if uid == stickyUser {
 | 
				
			||||||
 | 
										alreadyInvited = true
 | 
				
			||||||
 | 
										break
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// If not already invited, add to the list of users to invite.
 | 
				
			||||||
 | 
								if !alreadyInvited {
 | 
				
			||||||
 | 
									usersToInvite = append(usersToInvite, stickyUser)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// For each person on the plan, see if we need to invite them.
 | 
							// For each person on the plan, see if we need to invite them.
 | 
				
			||||||
		for _, personOnPlan := range peopleOnPlan {
 | 
							for _, personOnPlan := range peopleOnPlan {
 | 
				
			||||||
			// Find the slack user for the planning center person.
 | 
								// Find the slack user for the planning center person.
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user