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:
James Coleman 2023-10-01 07:58:52 -05:00
parent e6ef66194e
commit 2354e60b3d
6 changed files with 92 additions and 11 deletions

1
.gitignore vendored
View File

@ -1,3 +1,4 @@
config.yaml config.yaml
service-notifications service-notifications
service-notifications.db service-notifications.db
sync.sh

View File

@ -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
View File

@ -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

View File

@ -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,
}, },
} }

View File

@ -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.

View File

@ -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.