diff --git a/.gitignore b/.gitignore index 6130df3..9d58f1d 100644 --- a/.gitignore +++ b/.gitignore @@ -30,5 +30,3 @@ bin/* tmp *.tmp vendor/*/ - -*.csv diff --git a/README.md b/README.md index 8b823cd..e3a21a0 100644 --- a/README.md +++ b/README.md @@ -3,15 +3,33 @@ [![Go Releaser](https://img.shields.io/github/release/andefined/twreport.svg)](https://goreportcard.com/report/github.com/andefined/twreport/releases/latest) [![Code Coverage](https://img.shields.io/codecov/c/github/andefined/twreport/master.svg)](https://codecov.io/gh/andefined/twreport/releases/latest) +[![twreport](screenshot.png)](https://github.com/andefined/twreport) + # twreport +A simple CLI for batch reporting / blocking abusive accounts on Twitter. + +## Installation +You can download the binaries from the [releases](/releases) section, or you can install it with Go. + +```bash +go get -u github.com/andefined/twreport +go install github.com/andefined/twreport +``` + +## How to use +1. Prepare you *csv* file without a header. Just point the correct column of the *screen_name* with `--column` flag. Default column is *0*. + + e.g. CSV `874276197357596672,realDonaldTrump` +2. Create an [application](https://apps.twitter.com) and generate *Access Token and Token Secret* under *Keys and Access Tokens* tab. + ```bash twreport report \ - --consumer-key key \ - --consumer-secret secret \ - --access-token token \ - --access-token-secret token-secret \ - --csv /path/to/block.csv \ + --consumer-key $CONSUMER-KEY \ + --consumer-secret $CONSUMER-SECRET \ + --access-token $ACCESS-TOKEN \ + --access-token-secret $ACCESS-TOKEN-SECRET \ + --csv ./templates/block.csv \ --column 1 \ --prompt \ --block diff --git a/VERSION b/VERSION index 8acdd82..4e379d2 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.0.1 +0.0.2 diff --git a/dist/twreport_0.0.1_checksums.txt b/dist/twreport_0.0.1_checksums.txt new file mode 100644 index 0000000..2c6eae1 --- /dev/null +++ b/dist/twreport_0.0.1_checksums.txt @@ -0,0 +1,3 @@ +f6dddcf31021e23f698e317328dd89def77ee59179b6c672cedb1ef93faeb03c twreport_0.0.1_windows_amd64.tar.gz +5270227188306fba3ec4bf175b190dacd694c7ef21fc5ebe12c51dafab13e117 twreport_0.0.1_linux_amd64.tar.gz +9b0b682325ed3e59d5e70dedb271da98b69b3a7df587ca4678a7b4ad9485d61c twreport_0.0.1_darwin_amd64.tar.gz diff --git a/dist/twreport_0.0.1_darwin_amd64.tar.gz b/dist/twreport_0.0.1_darwin_amd64.tar.gz new file mode 100644 index 0000000..561ff5e Binary files /dev/null and b/dist/twreport_0.0.1_darwin_amd64.tar.gz differ diff --git a/dist/twreport_0.0.1_darwin_amd64/twreport b/dist/twreport_0.0.1_darwin_amd64/twreport new file mode 100755 index 0000000..c99be47 Binary files /dev/null and b/dist/twreport_0.0.1_darwin_amd64/twreport differ diff --git a/dist/twreport_0.0.1_linux_amd64.tar.gz b/dist/twreport_0.0.1_linux_amd64.tar.gz new file mode 100644 index 0000000..d519786 Binary files /dev/null and b/dist/twreport_0.0.1_linux_amd64.tar.gz differ diff --git a/dist/twreport_0.0.1_linux_amd64/twreport b/dist/twreport_0.0.1_linux_amd64/twreport new file mode 100755 index 0000000..23d0474 Binary files /dev/null and b/dist/twreport_0.0.1_linux_amd64/twreport differ diff --git a/dist/twreport_0.0.1_windows_amd64.tar.gz b/dist/twreport_0.0.1_windows_amd64.tar.gz new file mode 100644 index 0000000..f337e66 Binary files /dev/null and b/dist/twreport_0.0.1_windows_amd64.tar.gz differ diff --git a/screenshot.png b/screenshot.png new file mode 100644 index 0000000..9b4250e Binary files /dev/null and b/screenshot.png differ diff --git a/templates/block.csv b/templates/block.csv new file mode 100644 index 0000000..037822b --- /dev/null +++ b/templates/block.csv @@ -0,0 +1 @@ +874276197357596672,realDonaldTrump diff --git a/twreport.go b/twreport.go index 8a0084b..39c26f2 100644 --- a/twreport.go +++ b/twreport.go @@ -18,13 +18,13 @@ import ( func main() { app := cli.NewApp() app.Name = "twreport" - app.Version = "0.0.1" - app.Usage = "Twitter: Report / Block Users" + app.Version = "0.0.2" + app.Usage = "Batch Report / Block Abusive Accounts on Twitter" app.Commands = []cli.Command{ { Name: "report", - Usage: "Report / Block Users from File", + Usage: "Batch Report / Block Abusive Accounts from a csv file", Action: Report, Flags: []cli.Flag{ cli.StringFlag{ @@ -69,32 +69,30 @@ func main() { // Report : Report Command func Report(c *cli.Context) error { now := time.Now() + // Read the flags project := &Project{} - project.CSV = c.String("csv") project.Column = c.Int("column") project.Block = c.BoolT("block") project.Prompt = c.BoolT("prompt") - project.ConsumerKey = c.String("consumer-key") project.ConsumerSecret = c.String("consumer-secret") project.AccessToken = c.String("access-token") project.AccessTokenSecret = c.String("access-token-secret") - if project.ConsumerKey == "" || project.ConsumerSecret == "" || project.AccessToken == "" || project.AccessTokenSecret == "" { - log.Fatal("Consumer key/secret and Access token/secret required") - } - + // Twitter API anaconda.SetConsumerKey(project.ConsumerKey) anaconda.SetConsumerSecret(project.ConsumerSecret) api := anaconda.NewTwitterApi(project.AccessToken, project.AccessTokenSecret) - verify, err := api.VerifyCredentials() - if err != nil || !verify { + // Verify Twitter Credentials + _, err := api.VerifyCredentials() + if err != nil { fmt.Printf("%s. Please refer to %s for your Access Tokens.\n", "Bad Authorization Tokens", "https://apps.twitter.com/") return nil } + // Open the Input File file, err := os.Open(project.CSV) if err != nil { fmt.Println("Error:", err) @@ -102,21 +100,26 @@ func Report(c *cli.Context) error { } defer file.Close() + // Read the Input File reader := csv.NewReader(file) reader.Comma = ',' + // Create an Output File + // This is usefull for keeping a log of users that you allready reported/blocked output, err := os.OpenFile("./twreport-"+strconv.FormatInt(now.Unix(), 6)+".csv", os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644) if err != nil { fmt.Println("Error:", err) return nil } - defer output.Close() + // Output File Header writer := csv.NewWriter(output) writer.Write([]string{"screen_name", "report", "block"}) writer.Flush() + for { + // Read Line By Line record, err := reader.Read() if err == io.EOF { break @@ -134,7 +137,7 @@ func Report(c *cli.Context) error { _, err := api.PostUsersReportSpam(field, v) if err != nil { fmt.Printf("You are over the limit for spam reports. Sleeping for 15'.\n") - sleep() + Sleep() } fmt.Printf("User %s Reported (Blocked: %v).\n", field, project.Block) writer.Write([]string{field, "true", strconv.FormatBool(project.Block)}) @@ -144,7 +147,7 @@ func Report(c *cli.Context) error { _, err := api.PostUsersReportSpam(field, v) if err != nil { fmt.Printf("You are over the limit for spam reports. Sleeping for 15'.\n") - sleep() + Sleep() } fmt.Printf("User %s Reported (Blocked: %v).\n", field, project.Block) writer.Write([]string{field, "true", strconv.FormatBool(project.Block)}) @@ -169,7 +172,7 @@ type Project struct { Prompt bool `yaml:"prompt"` } -// PromptConfirm : ... +// PromptConfirm : Prompt for Confirmation func PromptConfirm() bool { var response string _, err := fmt.Scanln(&response) @@ -182,10 +185,11 @@ func PromptConfirm() bool { if strings.ToLower(string(rune(response[0]))) == "n" { return false } - fmt.Printf("Please type yes or no and then press enter: ") + fmt.Printf("Please type y (for yes) or n (for no) and then press enter: ") return PromptConfirm() } -func sleep() { +// Sleep : Go to Sleep for 15 Minutes (API Limits) +func Sleep() { time.Sleep(15 * time.Minute) } diff --git a/vendor/vendor.json b/vendor/vendor.json index 68a80f2..d7758c1 100644 --- a/vendor/vendor.json +++ b/vendor/vendor.json @@ -2,12 +2,6 @@ "comment": "", "ignore": "test", "package": [ - { - "checksumSHA1": "3X1Cr6GoDoaOKoVw8gN9JNIpwOs=", - "path": "github.com/ChimeraCoder/anaconda", - "revision": "0530dae79525a856cc778e15c4c2b03c3f6934b9", - "revisionTime": "2017-06-18T16:47:02Z" - }, { "checksumSHA1": "xE9Zo5ubzdEVBeRf+yD/ZjLALHk=", "path": "github.com/ChimeraCoder/tokenbucket", @@ -15,10 +9,10 @@ "revisionTime": "2013-12-01T22:36:12Z" }, { - "checksumSHA1": "ZhsKgadONibW7XZJZLOqARyWXks=", - "path": "github.com/abiosoft/ishell", - "revision": "1fe4da16846908f352ed09310705a9c84f4b9f97", - "revisionTime": "2017-08-19T12:29:31Z" + "checksumSHA1": "b1uDyqkd+bg50xgC06G8imGO+04=", + "path": "github.com/andefined/anaconda", + "revision": "917c2195eaeea9baf8d218ac0197453719ff89c2", + "revisionTime": "2017-08-28T12:52:32Z" }, { "checksumSHA1": "3RgReu+42CU1EQ6afDsVSvBuPyk=", @@ -26,12 +20,6 @@ "revision": "53511d3c733003985b0b76f733df1f4d0095ee6a", "revisionTime": "2016-01-15T11:51:03Z" }, - { - "checksumSHA1": "aTYPm16eYDQhbVLgreCGwvV2klw=", - "path": "github.com/chzyer/readline", - "revision": "41eea22f717c616615e1e59aa06cf831f9901f35", - "revisionTime": "2017-03-13T23:49:21Z" - }, { "checksumSHA1": "ycg56E+pTPAHToKMIj8C5SZ+WYQ=", "path": "github.com/dustin/go-jsonpointer", @@ -44,47 +32,17 @@ "revision": "2e71ec9dd5adce3b168cd0dbde03b5cc04951c30", "revisionTime": "2016-03-07T16:12:27Z" }, - { - "checksumSHA1": "aEU9IPbfuS1PWY2T26gn41y+feA=", - "path": "github.com/fatih/color", - "revision": "67c513e5729f918f5e69786686770c27141a4490", - "revisionTime": "2017-08-04T15:04:06Z" - }, - { - "checksumSHA1": "yLQg8NdQKYqqytcvKA/0EBkOIkw=", - "path": "github.com/flynn-archive/go-shlex", - "revision": "3f9db97f856818214da2e1057f8ad84803971cff", - "revisionTime": "2015-05-15T14:53:56Z" - }, { "checksumSHA1": "3f+0/jzvM73c4omzvKWwGnswf3k=", "path": "github.com/garyburd/go-oauth/oauth", "revision": "166ce8d672783fbb5a72247c3cf459267717e1ec", "revisionTime": "2017-07-20T17:39:06Z" }, - { - "checksumSHA1": "cTDA66oZUy18cIzJsU1diKq+9CE=", - "path": "github.com/mattn/go-colorable", - "revision": "ad5389df28cdac544c99bd7b9161a0b5b6ca9d1b", - "revisionTime": "2017-08-16T03:18:13Z" - }, - { - "checksumSHA1": "U6lX43KDDlNOn+Z0Yyww+ZzHfFo=", - "path": "github.com/mattn/go-isatty", - "revision": "fc9e8d8ef48496124e79ae0df75490096eccf6fe", - "revisionTime": "2017-03-22T23:44:13Z" - }, { "checksumSHA1": "8YLoOB7KeQqUSPvlBynceGY4xOc=", "path": "github.com/urfave/cli", "revision": "f017f86fccc5a039a98f23311f34fdf78b014f78", "revisionTime": "2017-08-13T14:59:49Z" - }, - { - "checksumSHA1": "7NuioK0dEzBI+OOdVzTARrHsXgI=", - "path": "golang.org/x/sys/unix", - "revision": "2d6f6f883a06fc0d5f4b14a81e4c28705ea64c15", - "revisionTime": "2017-08-25T18:47:02Z" } ], "rootPath": "github.com/andefined/twreport"