diff --git a/README.md b/README.md index 42966a8..926d255 100644 --- a/README.md +++ b/README.md @@ -54,10 +54,11 @@ platforms. - *Discord* - *Email* -- *Microsoft Teams* +- *Mastodon* - *Mattermost* -- *Pushover* +- *Microsoft Teams* - *Pushbullet* +- *Pushover* - *RocketChat* - *Slack* - *Telegram* @@ -146,11 +147,10 @@ USAGE: main [global options] command [command options] [arguments...] DESCRIPTION: - PingMe is a CLI tool which provides the ability to send messages or alerts - to multiple messaging platforms and also email, everything is configurable - via environment variables and command line switches.Currently supported - platforms include Slack, Telegram, RocketChat, Discord, Pushover, Mattermost, - Microsoft Teams and email address. + PingMe is a CLI tool which provides the ability to send messages or alerts to multiple + messaging platforms and also email, everything is configurable via environment + variables and command line switches.Currently supported platforms include Slack, Telegram, + RocketChat, Discord, Pushover, Mattermost, Pushbullet, Microsoft Teams, Twillio, Mastodon and email address. COMMANDS: telegram Send message to telegram @@ -162,6 +162,8 @@ COMMANDS: email Send an email mattermost Send message to mattermost pushbullet Send message to pushbullet + twillio Send sms via twillio + mastodon Set status message for mastodon help, h Shows a list of commands or help for one command GLOBAL OPTIONS: diff --git a/docs/services.md b/docs/services.md index b47ac56..11a5668 100644 --- a/docs/services.md +++ b/docs/services.md @@ -468,6 +468,49 @@ jobs: | TWILLIO_TITLE | "" | | TWILLIO_MESSAGE | "" | +## Mastodon + +Mastodon uses application token to authorize and set status. + +```bash +mastodon --url "mastodon.social" --msg "some message" --title "PingMe CLI" --token "123" +``` + +- GitHub Action + +```yaml +on: [push] + +jobs: + pingme-job: + runs-on: ubuntu-latest + name: PingMe + steps: + - name: Checkout + uses: actions/checkout@v2 + + - name: Ping me On + uses: kha7iq/pingme-action@v1 + env: + MASTODON_TOKEN: ${{ secrets.MASTODON_TOKEN }} + MASTODON_SERVER: 'mastodon.social' + MASTODON_TITLE: 'Reference: ${{ github.ref }}' + MASTODON_MESSAGE: 'Event is triggered by ${{ github.event_name }}' + + with: + service: mastodon +``` + +- **Variables** + +| Variables | Default Value | +| -------------------------- | :----------------: | +| MASTODON_TOKEN | "" | +| MASTODON_SERVER | "" | +| MASTODON_TITLE | "" | +| MASTODON_MESSAGE | "" | + + ## Email Email uses username & password to authenticate for sending emails. SMTP diff --git a/main.go b/main.go index 3054f4c..8f102b8 100644 --- a/main.go +++ b/main.go @@ -4,9 +4,9 @@ import ( "log" "os" - "github.com/kha7iq/pingme/service/zulip" - + "github.com/kha7iq/pingme/service/mastodon" "github.com/kha7iq/pingme/service/twillio" + "github.com/kha7iq/pingme/service/zulip" "github.com/kha7iq/pingme/service/discord" "github.com/kha7iq/pingme/service/email" @@ -33,7 +33,7 @@ func main() { app.Description = `PingMe is a CLI tool which provides the ability to send messages or alerts to multiple messaging platforms and also email, everything is configurable via environment variables and command line switches.Currently supported platforms include Slack, Telegram, -RocketChat, Discord, Pushover, Mattermost, Pushbullet, Microsoft Teams and email address.` +RocketChat, Discord, Pushover, Mattermost, Pushbullet, Microsoft Teams, Twillio, Mastodon and email address.` // app.Commands contains the subcommands as functions which return []*cli.Command. app.Commands = []*cli.Command{ telegram.Send(), @@ -47,6 +47,7 @@ RocketChat, Discord, Pushover, Mattermost, Pushbullet, Microsoft Teams and email pushbullet.Send(), twillio.Send(), zulip.Send(), + mastodon.Send(), } err := app.Run(os.Args) diff --git a/service/mastodon/mastodon.go b/service/mastodon/mastodon.go new file mode 100644 index 0000000..abdd407 --- /dev/null +++ b/service/mastodon/mastodon.go @@ -0,0 +1,124 @@ +package mastodon + +import ( + "bytes" + "encoding/json" + "fmt" + "log" + "net/http" + "time" + + "github.com/urfave/cli/v2" +) + +// Mastodon struct holds data parsed via flags for the service +type Mastodon struct { + Title string + Token string + ServerURL string + Message string +} + +// Send parse values from *cli.context and return *cli.Command +// and sets a status message for mastodon. +func Send() *cli.Command { + var mastodonOpts Mastodon + return &cli.Command{ + Name: "mastodon", + Usage: "Set status message for mastodon", + UsageText: "pingme mastodon --token '123' --url 'mastodon.social' --title 'PingMe' " + + "--msg 'some message'", + Description: `Mastodon uses application token to authorize and sets a status message`, + Flags: []cli.Flag{ + &cli.StringFlag{ + Destination: &mastodonOpts.Token, + Name: "token", + Aliases: []string{"t"}, + Required: true, + Usage: "Application token for authorization.", + EnvVars: []string{"MASTODON_TOKEN"}, + }, + &cli.StringFlag{ + Destination: &mastodonOpts.Message, + Name: "msg", + Aliases: []string{"m"}, + Usage: "Message content.", + EnvVars: []string{"MASTODON_MESSAGE"}, + }, + &cli.StringFlag{ + Destination: &mastodonOpts.Title, + Name: "title", + Usage: "Title of the message.", + EnvVars: []string{"MASTODON_TITLE"}, + }, + &cli.StringFlag{ + Destination: &mastodonOpts.ServerURL, + Name: "url", + Aliases: []string{"u"}, + Value: "mastodon.social", + Required: true, + Usage: "URL of mastodon server i.e mastodon.social", + EnvVars: []string{"MASTODON_SERVER"}, + }, + }, + Action: func(ctx *cli.Context) error { + endPointURL := "https://" + mastodonOpts.ServerURL + "/api/v1/statuses/" + + // Create a Bearer string by appending string access token + bearer := "Bearer " + mastodonOpts.Token + + fullMessage := mastodonOpts.Title + "\n" + mastodonOpts.Message + + if err := sendMastodon(endPointURL, bearer, fullMessage); err != nil { + return fmt.Errorf("failed to send message\n[ERROR] - %v", err) + } + + return nil + }, + } +} + +// sendMastodon function take the server url , authorization token +// and message string to set the status. +func sendMastodon(url string, token string, msg string) error { + reqBody, err := json.Marshal(map[string]string{ + "status": msg, + }) + if err != nil { + return err + } + + // Create a new request using http + req, err := http.NewRequest("POST", url, bytes.NewBuffer(reqBody)) + if err != nil { + return err + } + + // add authorization header to the request + req.Header.Set("Authorization", token) + req.Header.Set("Content-Type", "application/json; charset=UTF-8") + + // create a new http client and send request to server + c := &http.Client{Timeout: 10 * time.Second} + resp, err := c.Do(req) + if err != nil { + return err + } + defer resp.Body.Close() + + // decode response received from server + var data map[string]interface{} + err = json.NewDecoder(resp.Body).Decode(&data) + if err != nil { + return err + } + + // check if server returned an error + checkErr, ok := data["error"] + if ok { + return fmt.Errorf("%v", checkErr) + } + + log.Printf("Success!!\nVisibility: %v\nURL: %v\n", data["visibility"], data["url"]) + return nil +}