From 37064849db25cbae687dd22f3f563651dd589760 Mon Sep 17 00:00:00 2001
From: Yoel Susanto <yoelsusantopro@yahoo.com>
Date: Tue, 23 Feb 2021 17:18:27 +0700
Subject: [PATCH 1/4] feat(service): add line service

---
 go.mod               |  6 +++++
 go.sum               | 16 +++++++++++++
 service/line/line.go | 57 ++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 79 insertions(+)
 create mode 100644 service/line/line.go

diff --git a/go.mod b/go.mod
index 561c553..3124d42 100644
--- a/go.mod
+++ b/go.mod
@@ -18,11 +18,14 @@ require (
 	github.com/go-telegram-bot-api/telegram-bot-api v4.6.4+incompatible
 	github.com/golang/protobuf v1.4.3 // indirect
 	github.com/jordan-wright/email v4.0.1-0.20210109023952-943e75fe5223+incompatible
+	github.com/kr/text v0.2.0 // indirect
+	github.com/line/line-bot-sdk-go v7.8.0+incompatible
 	github.com/magefile/mage v1.11.0 // indirect
 	github.com/mailgun/mailgun-go/v4 v4.3.4
 	github.com/mattn/go-colorable v0.1.8 // indirect
 	github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
 	github.com/modern-go/reflect2 v1.0.1 // indirect
+	github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect
 	github.com/pkg/errors v0.9.1
 	github.com/plivo/plivo-go v5.5.1+incompatible
 	github.com/sendgrid/rest v2.6.2+incompatible // indirect
@@ -36,6 +39,9 @@ require (
 	golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83 // indirect
 	golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
 	golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43 // indirect
+	golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
 	google.golang.org/protobuf v1.25.0 // indirect
+	gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect
+	gopkg.in/yaml.v2 v2.4.0 // indirect
 	gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
 )
diff --git a/go.sum b/go.sum
index 58bf17a..92164fb 100644
--- a/go.sum
+++ b/go.sum
@@ -1,6 +1,7 @@
 cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
 github.com/Baozisoftware/qrcode-terminal-go v0.0.0-20170407111555-c0650d8dff0f h1:2dk3eOnYllh+wUOuDhOoC2vUVoJF/5z478ryJ+wzEII=
 github.com/Baozisoftware/qrcode-terminal-go v0.0.0-20170407111555-c0650d8dff0f/go.mod h1:4a58ifQTEe2uwwsaqbh3i2un5/CBPg+At/qHpt18Tmk=
+github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
 github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
 github.com/Rhymen/go-whatsapp v0.0.0/go.mod h1:rdQr95g2C1xcOfM7QGOhza58HeI3I+tZ/bbluv7VazA=
 github.com/Rhymen/go-whatsapp v0.1.1 h1:OK+bCugQcr2YjyYKeDzULqCtM50TPUFM6LvQtszKfcw=
@@ -36,6 +37,7 @@ github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEe
 github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
 github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
 github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
+github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
 github.com/cschomburg/go-pushbullet v0.0.0-20171206132031-67759df45fbb h1:7X9nrm+LNWdxzQOiCjy0G51rNUxbH35IDHCjAMvogyM=
 github.com/cschomburg/go-pushbullet v0.0.0-20171206132031-67759df45fbb/go.mod h1:RfQ9wji3fjcSEsQ+uFCtIh3+BXgcZum8Kt3JxvzYzlk=
 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@@ -97,6 +99,12 @@ github.com/jordan-wright/email v4.0.1-0.20210109023952-943e75fe5223+incompatible
 github.com/jordan-wright/email v4.0.1-0.20210109023952-943e75fe5223+incompatible/go.mod h1:1c7szIrayyPPB/987hsnvNzLushdWf4o/79s3P08L8A=
 github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68=
 github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
+github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
+github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
+github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
+github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
+github.com/line/line-bot-sdk-go v7.8.0+incompatible h1:Uf9/OxV0zCVfqyvwZPH8CrdiHXXmMRa/L91G3btQblQ=
+github.com/line/line-bot-sdk-go v7.8.0+incompatible/go.mod h1:0RjLjJEAU/3GIcHkC3av6O4jInAbt25nnZVmOFUgDBg=
 github.com/magefile/mage v1.10.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A=
 github.com/magefile/mage v1.11.0 h1:C/55Ywp9BpgVVclD3lRnSYCwXTYxmSppIgLeDYlNuls=
 github.com/magefile/mage v1.11.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A=
@@ -114,6 +122,8 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJ
 github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
 github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
 github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
+github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
+github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
 github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
 github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
 github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
@@ -181,6 +191,8 @@ golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3
 golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
 golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
 golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
+golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
 google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
 google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
@@ -202,8 +214,12 @@ google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4
 google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
+gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
 gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
+gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
 gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
 gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
 gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
diff --git a/service/line/line.go b/service/line/line.go
new file mode 100644
index 0000000..e877699
--- /dev/null
+++ b/service/line/line.go
@@ -0,0 +1,57 @@
+package line
+
+import (
+	"context"
+
+	"github.com/line/line-bot-sdk-go/linebot"
+	"github.com/pkg/errors"
+)
+
+// Line struct holds info about client and destination ID for communicating with line API
+type Line struct {
+	client      *linebot.Client
+	receiverIDs []string
+}
+
+// New creates a new instance of Line notifier service
+// For more info about line api credential:
+// -> https://github.com/line/line-bot-sdk-go
+func New(channelSecret, channelAccessToken string) (*Line, error) {
+	bot, err := linebot.New(channelSecret, channelAccessToken)
+	if err != nil {
+		return nil, err
+	}
+
+	l := &Line{
+		client: bot,
+	}
+	return l, nil
+}
+
+// AddReceivers receives user, group or room IDs then add them to internal receivers list
+func (l *Line) AddReceivers(receiverIDs ...string) {
+	l.receiverIDs = append(l.receiverIDs, receiverIDs...)
+}
+
+// Send receives message subject and body then sends it to all receivers set previously
+// Subject will be on the first line followed by message on the next line
+func (l *Line) Send(ctx context.Context, subject, message string) error {
+	lineMessage := &linebot.TextMessage{
+		Text: subject + "\n" + message,
+	}
+
+	for _, destinationID := range l.receiverIDs {
+		select {
+		case <-ctx.Done():
+			return ctx.Err()
+
+		default:
+			_, err := l.client.PushMessage(destinationID, lineMessage).WithContext(ctx).Do()
+			if err != nil {
+				return errors.Wrapf(err, "failed to send message to line. destination id: '%s'", destinationID)
+			}
+		}
+	}
+
+	return nil
+}

From b4922a64e66d9f4693af52056f27df63874d5c6e Mon Sep 17 00:00:00 2001
From: Yoel Susanto <yoelsusantopro@yahoo.com>
Date: Tue, 23 Feb 2021 17:19:07 +0700
Subject: [PATCH 2/4] docs: add line service to readme

---
 README.md | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/README.md b/README.md
index 0e438a7..eba9824 100644
--- a/README.md
+++ b/README.md
@@ -67,6 +67,7 @@ _ = notifier.Send(
 - *Amazon SES*
 - *Discord*
 - *Email*
+- *Line*
 - *Mailgun*
 - *Microsoft Teams*
 - *Plivo*
@@ -82,6 +83,7 @@ _ = notifier.Send(
 - Amazon SES support: [aws/aws-sdk-go](https://github.com/aws/aws-sdk-go)
 - Discord support: [bwmarrin/discordgo](https://github.com/bwmarrin/discordgo)
 - Email support: [jordan-wright/email](https://github.com/jordan-wright/email)
+- Line support: [line/line-bot-sdk-go](https://github.com/line/line-bot-sdk-go)
 - Logo: [MariaLetta/free-gophers-pack](https://github.com/MariaLetta/free-gophers-pack)
 - Mailgun support: [mailgun/mailgun-go](https://github.com/mailgun/mailgun-go)
 - Microsoft Teams support: [atc0005/go-teams-notify](https://github.com/atc0005/go-teams-notify)

From c511ac19ee4d132cd643e54258eeefbf2176f41d Mon Sep 17 00:00:00 2001
From: Yoel Susanto <yoelsusantopro@yahoo.com>
Date: Tue, 23 Feb 2021 17:19:24 +0700
Subject: [PATCH 3/4] docs: add line service example usage

---
 service/line/usage.md | 43 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 43 insertions(+)
 create mode 100644 service/line/usage.md

diff --git a/service/line/usage.md b/service/line/usage.md
new file mode 100644
index 0000000..3c28143
--- /dev/null
+++ b/service/line/usage.md
@@ -0,0 +1,43 @@
+# Line Usage
+
+Install notifier using:
+
+* `go get -u github.com/nikoksr/notify`
+
+
+## Sample Code
+
+```go
+package main
+
+import (
+  "github.com/nikoksr/notify"
+  "github.com/nikoksr/notify/service/line"
+  "golang.org/x/net/context"
+)
+
+func main() {
+  // Assuming you already have a line messaging API credential
+  // Provide your channel secret and access token
+  lineService, _ := line.New("channelSecret", "channelAccessToken")
+
+  // Add id from various receivers
+  // You can try to use your own line id for testing
+  lineService.AddReceivers("userID1", "groupID1")
+
+  notifier := notify.New()
+  // Tell our notifier to use the line service. You can repeat the above process
+  // for as many services as you like and just tell the notifier to use them.
+  notifier.UseServices(lineService)
+
+  // Send a message
+  err := notifier.Send(context.Background(),
+    "Welcome",
+    "I am a bot written in Go!",
+  )
+
+  if err != nil {
+    panic(err)
+  }
+}
+```

From 720b9e73a3a1097d6140985c0307d0a83d78f4a2 Mon Sep 17 00:00:00 2001
From: Yoel Susanto <yoelsusantopro@yahoo.com>
Date: Sat, 6 Mar 2021 21:03:52 +0700
Subject: [PATCH 4/4] fix: adjust code style

---
 service/line/line.go  | 8 ++++----
 service/line/usage.md | 4 +++-
 2 files changed, 7 insertions(+), 5 deletions(-)

diff --git a/service/line/line.go b/service/line/line.go
index e877699..af44792 100644
--- a/service/line/line.go
+++ b/service/line/line.go
@@ -25,6 +25,7 @@ func New(channelSecret, channelAccessToken string) (*Line, error) {
 	l := &Line{
 		client: bot,
 	}
+
 	return l, nil
 }
 
@@ -40,15 +41,14 @@ func (l *Line) Send(ctx context.Context, subject, message string) error {
 		Text: subject + "\n" + message,
 	}
 
-	for _, destinationID := range l.receiverIDs {
+	for _, receiverID := range l.receiverIDs {
 		select {
 		case <-ctx.Done():
 			return ctx.Err()
-
 		default:
-			_, err := l.client.PushMessage(destinationID, lineMessage).WithContext(ctx).Do()
+			_, err := l.client.PushMessage(receiverID, lineMessage).WithContext(ctx).Do()
 			if err != nil {
-				return errors.Wrapf(err, "failed to send message to line. destination id: '%s'", destinationID)
+				return errors.Wrapf(err, "failed to send message to LINE contact '%s'", receiverID)
 			}
 		}
 	}
diff --git a/service/line/usage.md b/service/line/usage.md
index 3c28143..dde2272 100644
--- a/service/line/usage.md
+++ b/service/line/usage.md
@@ -26,12 +26,14 @@ func main() {
   lineService.AddReceivers("userID1", "groupID1")
 
   notifier := notify.New()
+
   // Tell our notifier to use the line service. You can repeat the above process
   // for as many services as you like and just tell the notifier to use them.
   notifier.UseServices(lineService)
 
   // Send a message
-  err := notifier.Send(context.Background(),
+  err := notifier.Send(
+    context.Background(),
     "Welcome",
     "I am a bot written in Go!",
   )