Skip to content

Latest commit

 

History

History
156 lines (118 loc) · 4.06 KB

README.md

File metadata and controls

156 lines (118 loc) · 4.06 KB

Session Sign Up Service

Coverage

When someone signs up for an Info Session on operationspark.org, this service runs a series of tasks:

  • Sends a webhook to Greenlight
  • Sends a Slack message to the #signups channel.
  • Sends the user a confirmation email
  • Registers the user for the Info Session's Zoom meeting

Development

Google provides a framework to run the serverless functions locally. The framework starts an HTTP server that wraps the serverless function(s). You can start the local server with the terminal or VS Code

Shell

$ cd cmd
$ SLACK_WEBHOOK_URL=[webhook endpoint] go run main.go

Serving function:

Then trigger the function with an HTTP request (cURL, Postman, etc)

$ curl --header "Content-Type: application/json" \
  --request POST \
  --data '{"firstName":"Quinta", "lastName": "Brunson"}' \
  http://localhost:8080/

VS Code

Use the "Local Function Server" debug configuration:

image

Project Structure

There is a signupService struct that has a list of tasks to run on a signup form event from the operationspark.org website.

A task is an interface with run and name methods.

type task interface {
	// Run takes a signup form struct and executes some action.
	// Ex.: Send an email, post a Slack message.
	run(context.Context, Signup) error
	// Name Returns the name of the task.
	name() string
}

When someone signs up for an Info Session, the form is parsed, then passed to a series of tasks for processing.

// function.go

// Set up services/tasks to run when someone signs up for an Info Session.
mgSvc := NewMailgunService(mgDomain, mgAPIKey, "")
glSvc := NewGreenlightService(glWebhookURL)
slackSvc := NewSlackService(slackWebhookURL)

// These registration tasks include:
registrationService := newSignupService(
		signupServiceOptions{
			// Registration tasks:
			// (executed concurrently)
			tasks: []task{
				// posting a WebHook to Greenlight,
				glSvc,
				// sending a "Welcome Email",
				mgSvc,
				// sending a Slack message to #signups channel,
				slackSvc,
				// registering the user for the Zoom meeting,
				zoomSvc,
			},
		},
)

server := newSignupServer(registrationService)
// Register executes a series of tasks in order. If one fails, the remaining tasks are cancelled.
func (sc *SignupService) register(su Signup) error {
	for _, task := range sc.tasks {
		err := task.run(su)
		if err != nil {
			return fmt.Errorf("task failed: %q: %v", task.name(), err)
		}
	}
	return nil
}

To register a new task, create a service struct and implement the task interface:

Example

package signup

type skywriteService struct {
}

func NewSkyWriteService() *skywriteService {
  return &skywriteService{}
}

func (d skywriteService) run(su Signup) error {
	return d.skyWrite(su.NameFirst)
}

func (d skywriteService) name() string {
	return "dominos service"
}

// SkyWrite sends a drone out to draw someones name in chemtrails.
func (d skywriteService) skyWrite(name string) error {
	// Do the thing
	return nil
}

Then pass the service to the registration service in function.go.

func NewServer() {
	// ...
  registrationService := newSignupService(
    // ... other tasks,
    // (Order matters!)
    NewSkyWriteService()
	)
  // ...
	server := newSignupServer(registrationService)
	return server
}

Connected Services

Contributing

Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change.

Please make sure to update tests as appropriate.