├── .gitignore ├── .travis.yml ├── AUTHCOMPLETE.md ├── LICENSE ├── Lint.png ├── README.md ├── ThreatDragonModels └── Test Threat │ └── Test Threat.json ├── api ├── auth.go ├── auth_test.go ├── modify.go ├── modify_test.go ├── retrieve.go └── retrieve_test.go ├── cmd ├── auth.go ├── modify.go ├── retrieve.go └── root.go ├── lint.go └── pocket ├── client.go ├── constants.go ├── mockclient.go ├── resource-en.go └── types.go /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files, Static and Dynamic libs (Shared Objects) 2 | *.o 3 | *.a 4 | *.so 5 | 6 | # Folders 7 | _obj 8 | _test 9 | 10 | # Architecture specific extensions/prefixes 11 | *.[568vq] 12 | [568vq].out 13 | 14 | *.cgo1.go 15 | *.cgo2.c 16 | _cgo_defun.c 17 | _cgo_gotypes.go 18 | _cgo_export.* 19 | 20 | _testmain.go 21 | 22 | *.exe 23 | *.test 24 | *.prof 25 | lint.yaml 26 | lint 27 | *.idea 28 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | 3 | go: 4 | - 1.6 5 | - tip 6 | 7 | env: 8 | global: 9 | - GOARCH=amd64 10 | - GO15VENDOREXPERIMENT=1 -------------------------------------------------------------------------------- /AUTHCOMPLETE.md: -------------------------------------------------------------------------------- 1 | # Authorisation Finished! 2 | 3 | ![image ](https://raw.githubusercontent.com/daveym/lint/master/Lint.png) 4 | 5 | **Hi there!** 6 | 7 | If your are seeing this, you have hopefully permitted Lint to access your Pocket data. Lint aims to help you visualise what you've saved off to Pocket through the command line, with a view that you can use it's output to bulk update items, or as input to your other programs. 8 | 9 | With Lint, you'll be able to retrieve items, retag them, delete them, archive them and more. Lint is powered by the Pocket API, and is open sourced under the MIT License, so if you fancy adding some new features, come ahead and get involved. 10 | 11 | Thanks for giving lint a try. 12 | 13 | Davey -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Daveym 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Lint.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daveym/lint/3c864863403097efe9c928687d6737bf471071c9/Lint.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Lint [![Build Status](https://travis-ci.org/daveym/lint.svg?branch=master)](https://travis-ci.org/daveym/lint) Report Card 2 | 3 | ## Synopsis 4 | 5 | Lint is a terminal based application that pulls back your Pocket entries and allows you to archive, favourite, unfavourite readd (from archived state) or delete these entries. Lint is currently in development and has not yet reached a releasable milestone, but feel free to have a look. At the moment, I'm using this as a vehicle for learning Go as well, so any advice or guidance is greatly appreciated as well. 6 | 7 | ## Intro 8 | 9 | To use this app, you need to have a [Pocket account](https://getpocket.com) and have access to your 'Consumer Key'. A consumer key is created by Pocket for each application that wants to access Pocket data via the Pocket API. As I'm open sourcing this application, feel free to go and set up your own copy on Pocket to get a consumer key - you'll need one to run this app! 10 | 11 | 12 | ## Installation 13 | 14 | If you want to have a go, download the source and get the latest [Go binary](https://golang.org/dl/). You'll need to compile, using 'go build lint.go' and get setup by executing './lint auth'. 15 | 16 | Pocket requires that you authenticate using your Consumer Token, and then you have to permit Lint to access the pocket data via an authorisation webpage. When you do that, you get an access token returned back from Pocket that can is used in subsequent API requests to add, retrieve or modify your pocket data. You'll only need to authenticate once with Lint, as it persists your access code to a local lint config (yaml) file. The following gives you an idea on how to get lint setup: 17 | 18 | ``` 19 | 1) ./lint auth 20 | Please make sure that lint.yaml exists in the working directory. 21 | 22 | 2) touch lint.yaml 23 | vim lint.yaml 24 | 25 | 3) paste in the following: 26 | consumerKey: your-consumer-key 27 | 28 | 4) re-run ./lint auth - you'll then be presented with an oAuth page for authentication. 29 | 30 | 5) At this point you ca retrieve articles. They'll come back in the form: 31 | ID, Title, URL 32 | 33 | If you want, you can pipe these to a file using ./lint retrieve -s all >> myfile. From there, see what articles you want to keep or archive or favourite and use their ID's as inputs to lint using: 34 | 35 | ./lint modify -a item1 item2 item3 etc. 36 | ``` 37 | 38 | ## Motivation 39 | 40 | I frequently find myself saving stuff to Pocket and never coming back to it again, or forgetting what I've yet to read. I also frequently save things without applying any tags whatsoever. This makes it tricky to find what I'm looking for later. I want an app that can help surface what I've stored in Pocket, but also something that I can use to manage items I've saved. 41 | 42 | I'm also attempting to learn Go, so I figured a good way to learn would be to create a simple app that connects to the [Pocket API](https://getpocket.com/developer/docs/overview) and pulls back my Pocket items. I can then retag, delete etc as appropriate. 43 | 44 | ## API Reference 45 | 46 | The app is constructed with the following components: 47 | 48 | 1. [Cobra](https://github.com/spf13/cobra) - Command line processing 49 | 2. [Viper](https://github.com/spf13/viper) - Configuration file access 50 | 3. Pocket Package - Wrapper aroound the [Pocket API](https://getpocket.com/developer/docs/overview) 51 | 52 | ## Getting Involved 53 | If you want to be involved in this, drop me a note on twitter, at @djmcglade 54 | 55 | 56 | ## License 57 | 58 | Licensed under MIT. 59 | 60 | -------------------------------------------------------------------------------- /ThreatDragonModels/Test Threat/Test Threat.json: -------------------------------------------------------------------------------- 1 | { 2 | "summary": { 3 | "title": "Test Threat", 4 | "owner": "me" 5 | }, 6 | "detail": { 7 | "contributors": [], 8 | "diagrams": [ 9 | { 10 | "title": "test", 11 | "thumbnail": "./public/content/images/thumbnail.jpg", 12 | "id": 0 13 | } 14 | ] 15 | } 16 | } -------------------------------------------------------------------------------- /api/auth.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | import ( 4 | "bufio" 5 | "fmt" 6 | "io/ioutil" 7 | "os" 8 | 9 | "github.com/daveym/lint/pocket" 10 | ) 11 | 12 | // Authenticate against Pocket API. Interface used to allow mock to be passed in. 13 | func Authenticate(pc pocket.API) string { 14 | 15 | msg := "" 16 | 17 | if len(pc.GetConsumerKey()) == 0 { 18 | msg = pocket.CONSUMERKEYNOTFOUNDEn 19 | return msg 20 | } 21 | 22 | AuthNResp := &pocket.AuthenticationResponse{} 23 | err := pc.Authenticate(pc.GetConsumerKey(), AuthNResp) 24 | 25 | if err != nil { 26 | msg = pocket.CONSUMERKEYNOTVALIDEn 27 | return msg 28 | } 29 | 30 | err = pc.UserAuthorise(pocket.UserAuthorisationURL, AuthNResp.Code, pocket.RedirectURI) 31 | if err != nil { 32 | msg = pocket.ERRORAPPROVINGLINTEn 33 | return msg 34 | } 35 | 36 | fmt.Print(pocket.ACKNOWLEDGEAUTHen) 37 | bufio.NewReader(os.Stdin).ReadBytes('\n') 38 | 39 | AuthRResp := &pocket.AuthorisationResponse{} 40 | err = pc.RetrieveAccessToken(pc.GetConsumerKey(), AuthNResp.Code, AuthRResp) 41 | 42 | if err != nil { 43 | msg = pocket.ERRORAUTHen 44 | return msg 45 | } 46 | 47 | cfgval := fmt.Sprintf("ConsumerKey: %v\nAccessToken: %v\nUsername: %v", 48 | pc.GetConsumerKey(), AuthRResp.AccessToken, AuthRResp.Username) 49 | 50 | err = ioutil.WriteFile(pocket.CfgFile, []byte(cfgval), 0644) 51 | 52 | if err != nil { 53 | msg = pocket.ERRORSAVINGCONSUMERKEYen 54 | return msg 55 | } 56 | 57 | msg = pocket.AUTHSUCCESSen 58 | 59 | return msg 60 | } 61 | -------------------------------------------------------------------------------- /api/auth_test.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/daveym/lint/pocket" 7 | ) 8 | 9 | var err error 10 | 11 | func TestAuthNoConsumerKey(t *testing.T) { 12 | 13 | t.Log("Executing: TestAuthNoConsumerKey") 14 | 15 | mc := &pocket.MockClient{} 16 | mc.SetConsumerKey("") 17 | 18 | expectedmsg := pocket.CONSUMERKEYNOTFOUNDEn 19 | actualmsg := Authenticate(mc) 20 | 21 | if actualmsg != expectedmsg { 22 | t.Log("Expected: " + expectedmsg) 23 | t.Log("Actual: " + actualmsg) 24 | t.Fatal("TestValidConsumerKey failed") 25 | } 26 | } 27 | 28 | func TestAuthInvalidConsumerKey(t *testing.T) { 29 | 30 | t.Log("Executing: TestAuthInvalidConsumerKey") 31 | 32 | mc := &pocket.MockClient{} 33 | mc.SetConsumerKey("INVALIDKEY") 34 | 35 | expectedmsg := pocket.CONSUMERKEYNOTVALIDEn 36 | actualmsg := Authenticate(mc) 37 | 38 | if actualmsg != expectedmsg { 39 | t.Log("Expected: " + expectedmsg) 40 | t.Log("Actual: " + actualmsg) 41 | t.Fatal("TestAuthInvalidConsumerKey failed") 42 | } 43 | } 44 | 45 | func TestBrowserAuthFail(t *testing.T) { 46 | 47 | t.Log("Executing: TestBrowserAuthFail") 48 | 49 | mc := &pocket.MockClient{} 50 | mc.SetConsumerKey("INVALIDBROWSER") 51 | 52 | expectedmsg := pocket.ERRORAPPROVINGLINTEn 53 | actualmsg := Authenticate(mc) 54 | 55 | if actualmsg != expectedmsg { 56 | t.Log("Expected: " + expectedmsg) 57 | t.Log("Actual: " + actualmsg) 58 | t.Fatal("TestBrowserAuthFail failed") 59 | } 60 | } 61 | 62 | func TestAuthGetAccessTokenFail(t *testing.T) { 63 | 64 | t.Log("Executing: TestAuthGetAccessTokenFail") 65 | 66 | mc := &pocket.MockClient{} 67 | mc.SetConsumerKey("FAIL") 68 | mc.SetAccessToken("FAIL") 69 | 70 | expectedmsg := pocket.ERRORAUTHen 71 | actualmsg := Authenticate(mc) 72 | 73 | if actualmsg != expectedmsg { 74 | t.Log("Expected: " + expectedmsg) 75 | t.Log("Actual: " + actualmsg) 76 | t.Fatal("TestAuthGetAccessTokenFail failed") 77 | } 78 | } 79 | 80 | func TestAuthGetAccessTokenSuccess(t *testing.T) { 81 | 82 | t.Log("Executing: TestAuthGetAccessTokenSuccess") 83 | 84 | mc := &pocket.MockClient{} 85 | mc.SetConsumerKey("45678") 86 | mc.SetAccessToken("SUCCESS") 87 | 88 | expectedmsg := pocket.AUTHSUCCESSen 89 | actualmsg := Authenticate(mc) 90 | 91 | if actualmsg != expectedmsg { 92 | t.Log("Expected: " + expectedmsg) 93 | t.Log("Actual: " + actualmsg) 94 | t.Fatal("TestAuthGetAccessTokenSuccess failed") 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /api/modify.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | import ( 4 | "strconv" 5 | 6 | "github.com/daveym/lint/pocket" 7 | ) 8 | 9 | // Modify against Pocket API. Interface used to allow mock to be passed in. 10 | func Modify(pc pocket.API, action string, itemVal int, args []string) string { 11 | 12 | msg := "" 13 | 14 | if len(pc.GetConsumerKey()) == 0 { 15 | msg = pocket.CONSUMERKEYNOTVALIDEn 16 | return msg 17 | } 18 | 19 | switch action { 20 | case "archive", "delete", "favourite", "unfavorite", "readd": 21 | msg = applyAction(pc, action, itemVal, args) 22 | case "add": 23 | msg = "Add not yet implemented." 24 | } 25 | 26 | return msg 27 | } 28 | 29 | func applyAction(pc pocket.API, action string, itemVal int, args []string) string { 30 | 31 | msg := "" 32 | modreq := pocket.ModifyRequest{} 33 | modreq.ConsumerKey = pc.GetConsumerKey() 34 | modreq.AccessToken = pc.GetAccessToken() 35 | 36 | modact := &pocket.Action{} 37 | modact.Action = action 38 | modact.ItemID = itemVal 39 | modreq.Actions = append(modreq.Actions, modact) 40 | 41 | // Bulk update, with itemIds in Args parameter 42 | if len(args) > 0 { 43 | for i := 0; i < len(args); i++ { 44 | modact := &pocket.Action{} 45 | modact.Action = action 46 | modact.ItemID, _ = strconv.Atoi(args[i]) 47 | modreq.Actions = append(modreq.Actions, modact) 48 | } 49 | } 50 | 51 | modresp := &pocket.ModifyResponse{} 52 | err := pc.Modify(modreq, modresp) 53 | 54 | if err != nil { 55 | msg = pocket.ERRORRETRIEVINGen + err.Error() 56 | return msg 57 | } 58 | 59 | if modresp.Status == 0 { 60 | msg = pocket.ERROREXECUTINGen + action 61 | return msg 62 | } 63 | 64 | return pocket.UPDATEAPPLIEDen 65 | } 66 | -------------------------------------------------------------------------------- /api/modify_test.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/daveym/lint/pocket" 7 | ) 8 | 9 | func TestModifyNoConsumerKey(t *testing.T) { 10 | 11 | t.Log("Executing: TestModifyNoConsumerKey") 12 | 13 | var action string 14 | var itemVal int 15 | var args []string 16 | 17 | mc := &pocket.MockClient{} 18 | mc.SetConsumerKey("") 19 | 20 | action = "" 21 | 22 | expectedmsg := pocket.CONSUMERKEYNOTVALIDEn 23 | actualmsg := Modify(mc, action, itemVal, args) 24 | 25 | if actualmsg != expectedmsg { 26 | t.Log("Expected: " + expectedmsg) 27 | t.Log("Actual: " + actualmsg) 28 | t.Fatal("TestModifyNoConsumerKey failed") 29 | } 30 | } 31 | 32 | func TestModifySuccessfulUpdate(t *testing.T) { 33 | 34 | t.Log("Executing: TestModifySuccessfulUpdate") 35 | 36 | var action string 37 | var itemVal int 38 | var args []string 39 | 40 | mc := &pocket.MockClient{} 41 | mc.SetConsumerKey("SUCCESS") 42 | 43 | action = "archive" 44 | itemVal = 12345 45 | 46 | expectedmsg := pocket.UPDATEAPPLIEDen 47 | actualmsg := Modify(mc, action, itemVal, args) 48 | 49 | if actualmsg != expectedmsg { 50 | t.Log("Expected: " + expectedmsg) 51 | t.Log("Actual: " + actualmsg) 52 | t.Fatal("TestModifySuccessfulUpdate failed") 53 | } 54 | } 55 | 56 | func TestModifyFailedUpdate(t *testing.T) { 57 | 58 | t.Log("Executing: TestModifyFailedUpdate") 59 | 60 | var action string 61 | var itemVal int 62 | var args []string 63 | 64 | mc := &pocket.MockClient{} 65 | mc.SetConsumerKey("SUCCESS") 66 | 67 | action = "archive" 68 | itemVal = 45678 69 | 70 | expectedmsg := pocket.ERROREXECUTINGen + action 71 | actualmsg := Modify(mc, action, itemVal, args) 72 | 73 | if actualmsg != expectedmsg { 74 | t.Log("Expected: " + expectedmsg) 75 | t.Log("Actual: " + actualmsg) 76 | t.Fatal("TestModifyFailedUpdate failed") 77 | } 78 | } 79 | 80 | func TestModifySuccessfulUpdateMultipleArgs(t *testing.T) { 81 | 82 | t.Log("Executing: TestModifySuccessfulUpdate") 83 | 84 | var action string 85 | var itemVal int 86 | var args []string 87 | 88 | mc := &pocket.MockClient{} 89 | mc.SetConsumerKey("SUCCESS") 90 | 91 | action = "archive" 92 | itemVal = 12345 93 | args = append(args, "45678") 94 | args = append(args, "91011") 95 | 96 | expectedmsg := pocket.UPDATEAPPLIEDen 97 | actualmsg := Modify(mc, action, itemVal, args) 98 | 99 | if actualmsg != expectedmsg { 100 | t.Log("Expected: " + expectedmsg) 101 | t.Log("Actual: " + actualmsg) 102 | t.Fatal("TestModifySuccessfulUpdate failed") 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /api/retrieve.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/daveym/lint/pocket" 7 | ) 8 | 9 | // Retrieve against Pocket API. Interface used to allow mock to be passed in. 10 | func Retrieve(pc pocket.API, searchVal string, domainVal string, tagVal string, countVal int) string { 11 | 12 | msg := "" 13 | 14 | if len(pc.GetConsumerKey()) == 0 { 15 | msg = pocket.CONSUMERKEYNOTVALIDEn 16 | return msg 17 | } 18 | 19 | if countVal == 0 { 20 | msg = pocket.COUNTGREATERTHANZEROen 21 | return msg 22 | } 23 | 24 | if len(searchVal) == 0 && len(domainVal) == 0 && len(tagVal) == 0 { 25 | msg = pocket.SPECIFYSEARCHen 26 | return msg 27 | } 28 | 29 | itemreq := pocket.RetrieveRequest{} 30 | itemreq.ConsumerKey = pc.GetConsumerKey() 31 | itemreq.AccessToken = pc.GetAccessToken() 32 | 33 | if searchVal != "all" { 34 | itemreq.Search = searchVal 35 | } 36 | 37 | itemreq.Domain = domainVal 38 | itemreq.Tag = tagVal 39 | itemreq.Count = countVal 40 | itemreq.Sort = pocket.SortNewest 41 | 42 | itemresp := &pocket.RetrieveResponse{} 43 | 44 | err := pc.Retrieve(itemreq, itemresp) 45 | 46 | if err != nil { 47 | msg = pocket.ERRORRETRIEVINGen + err.Error() 48 | return msg 49 | } 50 | 51 | items := itemresp.List 52 | 53 | if len(items) == 0 { 54 | msg = pocket.NOMATCHINGVALUESen 55 | return msg 56 | } 57 | 58 | for _, item := range items { 59 | msg = msg + fmt.Sprintf("%v,%v,%v\n", item.ItemID, item.GivenTitle, item.GivenURL) 60 | } 61 | 62 | return msg 63 | } 64 | -------------------------------------------------------------------------------- /api/retrieve_test.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | 7 | "github.com/daveym/lint/pocket" 8 | ) 9 | 10 | func TestRetrieveNoConsumerKey(t *testing.T) { 11 | 12 | t.Log("Executing: TestRetrieveNoConsumerKey") 13 | 14 | var searchVal string 15 | var domainVal string 16 | var tagVal string 17 | var countVal = 1 18 | 19 | mc := &pocket.MockClient{} 20 | mc.SetConsumerKey("") 21 | 22 | expectedmsg := pocket.CONSUMERKEYNOTVALIDEn 23 | actualmsg := Retrieve(mc, searchVal, domainVal, tagVal, countVal) 24 | 25 | if actualmsg != expectedmsg { 26 | t.Log("Expected: " + expectedmsg) 27 | t.Log("Actual: " + actualmsg) 28 | t.Fatal("TestValidConsumerKey failed") 29 | } 30 | } 31 | 32 | func TestRetrieveNoCountCriteria(t *testing.T) { 33 | 34 | t.Log("Executing: TestRetrieveNoCountCriteria") 35 | 36 | var searchVal, domainVal, tagVal string 37 | var countVal int 38 | 39 | mc := &pocket.MockClient{} 40 | mc.SetConsumerKey("45678") 41 | mc.SetAccessToken("SUCCESS") 42 | 43 | searchVal = "" 44 | domainVal = "" 45 | tagVal = "" 46 | countVal = 0 47 | 48 | expectedmsg := pocket.COUNTGREATERTHANZEROen 49 | actualmsg := Retrieve(mc, searchVal, domainVal, tagVal, countVal) 50 | 51 | if actualmsg != expectedmsg { 52 | t.Log("Expected: " + expectedmsg) 53 | t.Log("Actual: " + actualmsg) 54 | t.Fatal("TestRetrieveNoSearchCriteria failed") 55 | } 56 | } 57 | 58 | func TestRetrieveNoCriteria(t *testing.T) { 59 | 60 | t.Log("Executing: TestRetrieveNoCriteria") 61 | 62 | var searchVal, domainVal, tagVal string 63 | var countVal int 64 | 65 | mc := &pocket.MockClient{} 66 | mc.SetConsumerKey("45678") 67 | mc.SetAccessToken("SUCCESS") 68 | 69 | searchVal = "" 70 | domainVal = "" 71 | tagVal = "" 72 | countVal = 1 73 | 74 | expectedmsg := pocket.SPECIFYSEARCHen 75 | actualmsg := Retrieve(mc, searchVal, domainVal, tagVal, countVal) 76 | 77 | if actualmsg != expectedmsg { 78 | t.Log("Expected: " + expectedmsg) 79 | t.Log("Actual: " + actualmsg) 80 | t.Fatal("TestRetrieveNoCriteria failed") 81 | } 82 | } 83 | 84 | func TestRetrieveWithNoItemsFound(t *testing.T) { 85 | 86 | t.Log("Executing: TestRetrieveWithSearchCriteria") 87 | 88 | var searchVal, domainVal, tagVal string 89 | var countVal int 90 | 91 | mc := &pocket.MockClient{} 92 | mc.SetConsumerKey("45678") 93 | mc.SetAccessToken("SUCCESS") 94 | 95 | searchVal = "nothing" 96 | domainVal = "" 97 | tagVal = "" 98 | countVal = 1 99 | 100 | expectedmsg := pocket.NOMATCHINGVALUESen 101 | actualmsg := Retrieve(mc, searchVal, domainVal, tagVal, countVal) 102 | 103 | if actualmsg != expectedmsg { 104 | t.Log("Expected: " + expectedmsg) 105 | t.Log("Actual: " + actualmsg) 106 | t.Fatal("TestRetrieveWithSearchCriteria failed") 107 | } 108 | } 109 | 110 | func TestRetrieveWithSearchCriteria(t *testing.T) { 111 | 112 | t.Log("Executing: TestRetrieveWithSearchCriteria") 113 | 114 | var searchVal, domainVal, tagVal string 115 | var countVal int 116 | 117 | mc := &pocket.MockClient{} 118 | mc.SetConsumerKey("45678") 119 | mc.SetAccessToken("SUCCESS") 120 | 121 | searchVal = "docker" 122 | domainVal = "" 123 | tagVal = "" 124 | countVal = 1 125 | 126 | expectedmsg := fmt.Sprintf("%v,%v,%v\n", 11111, "Docker", "http://docker.com") 127 | actualmsg := Retrieve(mc, searchVal, domainVal, tagVal, countVal) 128 | 129 | if actualmsg != expectedmsg { 130 | t.Log("Expected: " + expectedmsg) 131 | t.Log("Actual: " + actualmsg) 132 | t.Fatal("TestRetrieveWithSearchCriteria failed") 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /cmd/auth.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/daveym/lint/api" 7 | "github.com/daveym/lint/pocket" 8 | "github.com/spf13/cobra" 9 | "github.com/spf13/viper" 10 | ) 11 | 12 | var authCmd = &cobra.Command{ 13 | Use: "auth", 14 | Short: "Authenticate against Pocket to get an Access Token. One off activity.", 15 | Long: `To access the Pocket API, you need to authenticate with your consumer key. Your consumer key 16 | can be found under the development area within the pocket website`, 17 | Run: func(cmd *cobra.Command, args []string) { 18 | 19 | pc := &pocket.Client{} 20 | 21 | pc.SetConsumerKey(viper.GetString("ConsumerKey")) 22 | pc.SetAccessToken(viper.GetString("AccessToken")) 23 | 24 | msg := api.Authenticate(pc) 25 | 26 | viper.Set("ConsumerKey", pc.GetConsumerKey()) 27 | viper.Set("AccessToken", pc.GetAccessToken()) 28 | 29 | fmt.Println(msg) 30 | 31 | }} 32 | 33 | func init() { 34 | RootCmd.AddCommand(authCmd) 35 | } 36 | -------------------------------------------------------------------------------- /cmd/modify.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "fmt" 5 | "strconv" 6 | 7 | "github.com/daveym/lint/api" 8 | "github.com/daveym/lint/pocket" 9 | "github.com/spf13/cobra" 10 | "github.com/spf13/viper" 11 | ) 12 | 13 | var itemArg string 14 | 15 | var modifyCmd = &cobra.Command{ 16 | Use: "modify", 17 | Short: "Modify items stored witin your Pocket data store (archive, favourite, unfavourite, delete)", 18 | Long: `Modify your pocket items. 19 | Archive - Move an item to pockets archive 20 | Favorite - Mark an item as a favorite 21 | Unfavorite - Remove an item from your favorites 22 | Delete - Permanently remove an item from your pocket account 23 | `, 24 | } 25 | 26 | func init() { 27 | 28 | modifyCmd.Run = modify 29 | 30 | // itemID is the first parameter to each of the commands. 31 | modifyCmd.Flags().StringVarP(&itemArg, "add", "n", "", "Add a new item to pocket.") 32 | modifyCmd.Flags().StringVarP(&itemArg, "arc", "a", "", "Archive an item in pocket using ./lint modify -a itemID [itemID2 itemID3 itemID3 etc.]") 33 | modifyCmd.Flags().StringVarP(&itemArg, "del", "d", "", "Delete an item from pocket using ./lint modify -d itemID [itemID2 itemID3 itemID3 etc.]") 34 | modifyCmd.Flags().StringVarP(&itemArg, "fav", "f", "", "Favourite an item in pocket using ./lint modify -f itemID [itemID2 itemID3 itemID3 etc.]") 35 | modifyCmd.Flags().StringVarP(&itemArg, "unfav", "u", "", "(Un)Favourite an item in pocket using ./lint modify -u itemID [itemID2 itemID3 itemID3 etc.]") 36 | modifyCmd.Flags().StringVarP(&itemArg, "readd", "r", "", "Readd an item that was archived pocket using ./lint modify -r itemID [itemID2 itemID3 itemID3 etc.]") 37 | 38 | RootCmd.AddCommand(modifyCmd) 39 | } 40 | 41 | func modify(cmd *cobra.Command, args []string) { 42 | 43 | msg := "" 44 | 45 | pc := &pocket.Client{} 46 | pc.SetConsumerKey(viper.GetString("ConsumerKey")) 47 | pc.SetAccessToken(viper.GetString("AccessToken")) 48 | 49 | itemVal, err := strconv.Atoi(itemArg) 50 | 51 | if err != nil { 52 | fmt.Println("ItemID paramemter must be numeric") 53 | return 54 | } 55 | 56 | switch { 57 | case cmd.Flag("arc").Changed: 58 | msg = api.Modify(pc, "archive", itemVal, args) 59 | case cmd.Flag("del").Changed: 60 | msg = api.Modify(pc, "delete", itemVal, args) 61 | case cmd.Flag("fav").Changed: 62 | msg = api.Modify(pc, "favourite", itemVal, args) 63 | case cmd.Flag("unfav").Changed: 64 | msg = api.Modify(pc, "unfavourite", itemVal, args) 65 | case cmd.Flag("readd").Changed: 66 | msg = api.Modify(pc, "readd", itemVal, args) 67 | case cmd.Flag("add").Changed: 68 | msg = api.Modify(pc, "add", itemVal, args) 69 | } 70 | 71 | fmt.Println(msg) 72 | } 73 | -------------------------------------------------------------------------------- /cmd/retrieve.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/daveym/lint/api" 7 | "github.com/daveym/lint/pocket" 8 | "github.com/spf13/cobra" 9 | "github.com/spf13/viper" 10 | ) 11 | 12 | var searchVal string 13 | var domainVal string 14 | var tagVal string 15 | var countVal int 16 | 17 | var retrieveCmd = &cobra.Command{ 18 | Use: "retrieve", 19 | Short: "Retrieve items stored witin your Pocket data store. Use flags -s, -d and -t to specific a search term, domain or tag", 20 | Long: `Retrieve provides you with the means to query Pocket, pull back items by specific order 21 | and then use the results to perform follow up actions such as deleting or tagging`, 22 | } 23 | 24 | func init() { 25 | 26 | retrieveCmd.Run = retrieve 27 | retrieveCmd.Flags().StringVarP(&searchVal, "search", "s", "", "Only return items whose title or url contain the search string or use -s all to retrieve everything") 28 | retrieveCmd.Flags().StringVarP(&domainVal, "domain", "d", "", "Only return items from a particular domain") 29 | retrieveCmd.Flags().StringVarP(&tagVal, "tag", "t", "", "only return items tagged with tag name") 30 | retrieveCmd.Flags().IntVarP(&countVal, "count", "c", 10, "total number of items to return") 31 | 32 | RootCmd.AddCommand(retrieveCmd) 33 | } 34 | 35 | func retrieve(cmd *cobra.Command, args []string) { 36 | 37 | pc := &pocket.Client{} 38 | pc.SetConsumerKey(viper.GetString("ConsumerKey")) 39 | pc.SetAccessToken(viper.GetString("AccessToken")) 40 | 41 | msg := api.Retrieve(pc, searchVal, domainVal, tagVal, countVal) 42 | fmt.Println(msg) 43 | } 44 | -------------------------------------------------------------------------------- /cmd/root.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | 7 | "github.com/spf13/cobra" 8 | "github.com/spf13/viper" 9 | ) 10 | 11 | // RootCmd - The base command for the application. 12 | var RootCmd = &cobra.Command{ 13 | Use: "lint", 14 | Short: "Lint - pull back articles from your Pocket datastore and get rid of the fluff.", 15 | Long: `Lint provides you with a way of seeing what you've saved to read later. Often we forget what we've stored, 16 | and lint aims to help you remember whats stored, but also provide a quick way to purge items you wont read, or retag 17 | items for easier retrieval later. 18 | 19 | Run 'lint COMMAND --help' for more information on a command.`, 20 | } 21 | 22 | // Execute - Adds all defined commands 23 | func Execute() { 24 | if err := RootCmd.Execute(); err != nil { 25 | fmt.Println(err) 26 | os.Exit(-1) 27 | } 28 | 29 | viper.Get("consumerkey") 30 | } 31 | 32 | func init() { 33 | cobra.OnInitialize(initConfig) 34 | } 35 | 36 | func initConfig() { 37 | 38 | viper.SetConfigName("lint") 39 | viper.SetConfigType("yaml") 40 | viper.AddConfigPath(".") 41 | 42 | err := viper.ReadInConfig() 43 | 44 | if err != nil { 45 | fmt.Println("Please make sure that lint.yaml exists in the working directory.") 46 | os.Exit(-1) 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /lint.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "github.com/daveym/lint/cmd" 4 | 5 | // All commands are under the cmd directory 6 | // Command Logic is instigated from these files. 7 | func main() { 8 | cmd.Execute() 9 | } 10 | -------------------------------------------------------------------------------- /pocket/client.go: -------------------------------------------------------------------------------- 1 | package pocket 2 | 3 | import ( 4 | "bytes" 5 | "encoding/json" 6 | "fmt" 7 | "net/http" 8 | "os/exec" 9 | ) 10 | 11 | // API - Base interface type for Pocket API. Allows us to mock/test. 12 | type API interface { 13 | SetConsumerKey(string) 14 | GetConsumerKey() string 15 | SetAccessToken(string) 16 | GetAccessToken() string 17 | Authenticate(string, *AuthenticationResponse) error 18 | UserAuthorise(string, string, string) error 19 | RetrieveAccessToken(string, string, *AuthorisationResponse) error 20 | Retrieve(RetrieveRequest, *RetrieveResponse) error 21 | Modify(ModifyRequest, *ModifyResponse) error 22 | } 23 | 24 | // Client - Provide access the Pocket API 25 | type Client struct { 26 | _consumerKey string 27 | _accessToken string 28 | } 29 | 30 | // SetConsumerKey - Set the new consumer Key 31 | func (p *Client) SetConsumerKey(newKey string) { 32 | p._consumerKey = newKey 33 | } 34 | 35 | // GetConsumerKey - Set the new consumer Key 36 | func (p *Client) GetConsumerKey() string { 37 | return p._consumerKey 38 | } 39 | 40 | // SetAccessToken - Set the new consumer Key 41 | func (p *Client) SetAccessToken(newToken string) { 42 | p._accessToken = newToken 43 | } 44 | 45 | // GetAccessToken - Set the new consumer Key 46 | func (p *Client) GetAccessToken() string { 47 | return p._accessToken 48 | } 49 | 50 | // Authenticate takes the the users consumer key and performs a one time authentication with 51 | // the Pocket API to request access. A Request Token is returned that should be used for all 52 | // subsequent requests to Pocket. 53 | func (p *Client) Authenticate(consumerKey string, resp *AuthenticationResponse) error { 54 | 55 | request := map[string]string{"consumer_key": consumerKey, "redirect_uri": RedirectURI} 56 | jsonStr, _ := json.Marshal(request) 57 | err := postJSON("POST", AuthenticationURL, jsonStr, resp) 58 | 59 | return err 60 | } 61 | 62 | // UserAuthorise - Redirect the user to the Pocket Authorise screen 63 | func (p *Client) UserAuthorise(url string, reqtoken string, uri string) error { 64 | 65 | browser := exec.Command("open", url+ 66 | "request_token="+reqtoken+ 67 | "&redirect_uri="+uri) 68 | 69 | _, err := browser.Output() 70 | 71 | return err 72 | } 73 | 74 | // RetrieveAccessToken - Using the consumerKey and request code, obtain an Access token and Pocket Username 75 | func (p *Client) RetrieveAccessToken(consumerKey string, code string, resp *AuthorisationResponse) error { 76 | 77 | request := map[string]string{"consumer_key": consumerKey, "code": code} 78 | jsonStr, _ := json.Marshal(request) 79 | err := postJSON("POST", AuthorisationURL, jsonStr, resp) 80 | 81 | return err 82 | } 83 | 84 | // Retrieve - Pull back items from Pocket 85 | func (p *Client) Retrieve(itemreq RetrieveRequest, resp *RetrieveResponse) error { 86 | 87 | jsonStr, err := json.Marshal(itemreq) 88 | 89 | err = postJSON("GET", RetrieveURL, jsonStr, resp) 90 | 91 | return err 92 | } 93 | 94 | // Modify - Modify items in Pocket 95 | func (p *Client) Modify(req ModifyRequest, resp *ModifyResponse) error { 96 | 97 | jsonStr, err := json.Marshal(req) 98 | 99 | if err != nil { 100 | return err 101 | } 102 | 103 | err = postJSON("POST", ModifyURL, jsonStr, resp) 104 | 105 | return err 106 | } 107 | 108 | // Generic post method, url and data are incoming. Response is a base interface 109 | // that we can use to return many response types. 110 | func postJSON(action string, url string, data []byte, resp interface{}) (err error) { 111 | 112 | req, err := http.NewRequest(action, url, bytes.NewBuffer(data)) 113 | req.Header.Set("Content-Type", "application/json") 114 | req.Header.Set("charset", "UTF8") 115 | req.Header.Set("X-Accept", "application/json") 116 | 117 | client := &http.Client{} 118 | jsonResp, err := client.Do(req) 119 | 120 | if err != nil { 121 | fmt.Println(err.Error()) 122 | } 123 | 124 | err = json.NewDecoder(jsonResp.Body).Decode(resp) 125 | 126 | return err 127 | } 128 | -------------------------------------------------------------------------------- /pocket/constants.go: -------------------------------------------------------------------------------- 1 | package pocket 2 | 3 | // PocketHome - Pocket base url 4 | const PocketHome string = "https://getpocket.com" 5 | 6 | // CfgFile - Name of viper config file. Lint will store its values in the working directory. 7 | const CfgFile string = "lint.yaml" 8 | 9 | // URLS 10 | const ( 11 | // AuthenticationURL - API address to Authenticate Pocket Consumer Key 12 | AuthenticationURL string = "https://getpocket.com/v3/oauth/request" 13 | // AuthorisationURL - API address to Authorise and recience a Request Key 14 | AuthorisationURL string = "https://getpocket.com/v3/oauth/authorize" 15 | //UserAuthorisationURL - Address that a user must enter into their browser to Authorise Lint to access Pocket 16 | UserAuthorisationURL string = "https://getpocket.com/auth/authorize?" 17 | //RedirectURI - Link back location after Authorisation has been granted 18 | RedirectURI string = "https://github.com/daveym/lint/blob/master/AUTHCOMPLETE.md" 19 | // RetrieveURL - API Address to query Pocket Items 20 | RetrieveURL = "https://getpocket.com/v3/get" 21 | // ModifyURL - API Address to modify Pocket Items 22 | ModifyURL = "https://getpocket.com/v3/send" 23 | ) 24 | 25 | // ITEM STATUS 26 | const ( 27 | // ItemStatusUnread - Pocket Item has not been read 28 | ItemStatusUnread ItemStatus = 0 29 | // ItemStatusArchived - Pocket Item has been archived 30 | ItemStatusArchived = 1 31 | // ItemStatusDeleted - Pocket Item has been deleted 32 | ItemStatusDeleted = 2 33 | ) 34 | 35 | // ITEM STATE 36 | const ( 37 | // ItemStateUnread - only return unread items (default) 38 | ItemStateUnread string = "unread" 39 | // ItemStateArchive - only return archived items 40 | ItemStateArchive string = "archive" 41 | // ItemStateAll - return both unread and archived items 42 | ItemStateAll string = "all" 43 | ) 44 | 45 | // MEDIA ATTACHMENTS 46 | const ( 47 | // ItemMediaAttachmentNoMedia - No media attached to the Pocket Item 48 | ItemMediaAttachmentNoMedia ItemMediaAttachment = 0 49 | // ItemMediaAttachmentHasMedia - Media is attached to the Pocket Item 50 | ItemMediaAttachmentHasMedia ItemMediaAttachment = 1 51 | // ItemMediaAttachmentIsMedia - The Pocket Item is media only 52 | ItemMediaAttachmentIsMedia ItemMediaAttachment = 2 53 | ) 54 | 55 | // ARTICLE TYPE 56 | const ( 57 | // ContentTypeArticle - article item 58 | ContentTypeArticle ContentType = "article" 59 | // ContentTypeVideo - Video item 60 | ContentTypeVideo ContentType = "video" 61 | // ContentTypeImage - Image item 62 | ContentTypeImage ContentType = "image" 63 | ) 64 | 65 | // DETAIL TYPE 66 | const ( 67 | // DetailTypeSimple - only return the titles and urls of each item 68 | DetailTypeSimple DetailType = "simple" 69 | // DetailTypeComplete - return all data about each item, including tags, images, authors, videos and more 70 | DetailTypeComplete DetailType = "complete" 71 | ) 72 | 73 | // FAVOURITE FILTER 74 | const ( 75 | FavoriteFilterUnspecified FavoriteFilter = "" 76 | FavoriteFilterUnfavorited FavoriteFilter = "0" 77 | FavoriteFilterFavorited FavoriteFilter = "1" 78 | ) 79 | 80 | // SORT FILTER 81 | const ( 82 | SortNewest Sort = "newest" 83 | SortOldest Sort = "oldest" 84 | SortTitle Sort = "title" 85 | SortSite Sort = "site" 86 | ) 87 | -------------------------------------------------------------------------------- /pocket/mockclient.go: -------------------------------------------------------------------------------- 1 | package pocket 2 | 3 | import "errors" 4 | 5 | // MockClient - Used for mocking 6 | type MockClient struct { 7 | _consumerKey string 8 | _accessToken string 9 | } 10 | 11 | // SetConsumerKey - Set the new consumer Key 12 | func (p *MockClient) SetConsumerKey(newKey string) { 13 | p._consumerKey = newKey 14 | } 15 | 16 | // GetConsumerKey - Set the new consumer Key 17 | func (p *MockClient) GetConsumerKey() string { 18 | return p._consumerKey 19 | } 20 | 21 | // SetAccessToken - Set the new access token 22 | func (p *MockClient) SetAccessToken(newToken string) { 23 | p._accessToken = newToken 24 | } 25 | 26 | // GetAccessToken - Set the new access token 27 | func (p *MockClient) GetAccessToken() string { 28 | return p._accessToken 29 | } 30 | 31 | // Authenticate - Mock instance 32 | func (p *MockClient) Authenticate(consumerKey string, resp *AuthenticationResponse) error { 33 | 34 | var err error 35 | 36 | if consumerKey == "INVALIDKEY" { 37 | err = errors.New("Invalid Key") 38 | } 39 | return err 40 | } 41 | 42 | // UserAuthorise - Mock instance 43 | func (p *MockClient) UserAuthorise(url string, code string, uri string) error { 44 | 45 | var err error 46 | 47 | if p.GetConsumerKey() == "INVALIDBROWSER" { 48 | err = errors.New("Invalid Key") 49 | } 50 | return err 51 | } 52 | 53 | // RetrieveAccessToken - Mock instance 54 | func (p *MockClient) RetrieveAccessToken(consumerKey string, code string, resp *AuthorisationResponse) error { 55 | 56 | var err error 57 | if consumerKey == "FAIL" { 58 | err = errors.New("Invalid Key") 59 | return err 60 | } 61 | 62 | return nil 63 | } 64 | 65 | // Retrieve - Mock instance 66 | func (p *MockClient) Retrieve(req RetrieveRequest, resp *RetrieveResponse) error { 67 | 68 | var err error 69 | 70 | resp.Status = 123 71 | resp.Complete = 123 72 | resp.List = make(map[string]Item) 73 | resp.Since = 789 74 | 75 | fakeItem := Item{ 76 | Excerpt: "Excerpt", 77 | Favorite: 1, 78 | GivenTitle: "Docker", 79 | GivenURL: "http://docker.com", 80 | HasImage: ItemMediaAttachmentNoMedia, 81 | HasVideo: ItemMediaAttachmentNoMedia, 82 | IsArticle: 1, 83 | ItemID: 11111, 84 | ResolvedID: 11111, 85 | ResolvedTitle: "Docker", 86 | ResolvedURL: "http://docker.com", 87 | SortID: 11111, 88 | Status: ItemStatusUnread, 89 | WordCount: 150} 90 | 91 | if req.Search == "docker" { 92 | resp.List["11111"] = fakeItem 93 | } 94 | 95 | if req.Search == "nothing" { 96 | resp.Status = 0 97 | resp.Complete = 0 98 | resp.List = make(map[string]Item) 99 | resp.Since = 0 100 | } 101 | 102 | return err 103 | } 104 | 105 | // Modify - Modify items in Pocket 106 | func (p *MockClient) Modify(req ModifyRequest, resp *ModifyResponse) error { 107 | 108 | actions := req.Actions 109 | itemVal := actions[0].ItemID 110 | 111 | if itemVal == 12345 { 112 | resp.Status = 1 113 | } 114 | 115 | if itemVal == 45678 { 116 | resp.Status = 0 117 | } 118 | 119 | var err error 120 | return err 121 | } 122 | -------------------------------------------------------------------------------- /pocket/resource-en.go: -------------------------------------------------------------------------------- 1 | package pocket 2 | 3 | // CONSUMERKEYNOTFOUNDEn - English message for a consumer key not being present in lint.yaml 4 | const CONSUMERKEYNOTFOUNDEn string = "Consumer Key is not present in lint.yaml. Please add, using the format 'ConsumerKey: value', without quotes." 5 | 6 | // CONSUMERKEYNOTVALIDEn - English message for invalid consumer key 7 | const CONSUMERKEYNOTVALIDEn string = "Please check your consumer key, it does not appear to be valid." 8 | 9 | // ERRORAPPROVINGLINTEn - English message for error whilst approving Lint access 10 | const ERRORAPPROVINGLINTEn string = "Error whilst approving Lint access to Pocket data. Please check your connectivity/default browser." 11 | 12 | // ACKNOWLEDGEAUTHen - English Acknowledge message for authorising Lint 13 | const ACKNOWLEDGEAUTHen string = "Press ENTER when you have authorised Lint to access to Pocket." 14 | 15 | // ERRORAUTHen - English message foe error authorising Consumer Key 16 | const ERRORAUTHen string = "Error authorising your consumer key and request token. Have you granted permission to Lint?" 17 | 18 | // ERRORSAVINGCONSUMERKEYen - English message for error whilst persisting consumer key 19 | const ERRORSAVINGCONSUMERKEYen string = "Error persisting consumer key, access token and username to lint.yaml" 20 | 21 | // AUTHSUCCESSen - English message for successful authentication 22 | const AUTHSUCCESSen string = "Authentication Successful - Pocket Access Token is persisted to lint.yaml" 23 | 24 | // SPECIFYSEARCHen - English message to specify search parameters 25 | const SPECIFYSEARCHen string = "Please specify a search, domain or tag parameter or use the --help parameter." 26 | 27 | // NOMATCHINGVALUESen - English message when no matching values are found in pocket 28 | const NOMATCHINGVALUESen string = "No matching values found in your pocket store." 29 | 30 | // COUNTGREATERTHANZEROen - English message to specify a count greater than zero 31 | const COUNTGREATERTHANZEROen string = "Please specify a count parameter greater than 0." 32 | 33 | // ERRORRETRIEVINGen - English message to specify an error retrieving from pocket 34 | const ERRORRETRIEVINGen string = "Error retrieving from Pocket: " 35 | 36 | // UPDATEAPPLIEDen - English confirmation of successful update 37 | const UPDATEAPPLIEDen string = "Update applied successfully." 38 | 39 | // ERROREXECUTINGen - English message for error excuting an action against Pocket API 40 | const ERROREXECUTINGen string = "Error executing against the pocket API: " 41 | -------------------------------------------------------------------------------- /pocket/types.go: -------------------------------------------------------------------------------- 1 | package pocket 2 | 3 | // State of returned items 4 | type State string 5 | 6 | // Sort - Sort options for returned items 7 | type Sort string 8 | 9 | // ItemStatus - Status of retrieved item 10 | type ItemStatus int 11 | 12 | // ContentType - Article video or image 13 | type ContentType string 14 | 15 | // DetailType - Simple or complete detail 16 | type DetailType string 17 | 18 | // FavoriteFilter - Filter by favourite 19 | type FavoriteFilter string 20 | 21 | // ItemMediaAttachment - Is Media attached to the Pocket Item. 22 | type ItemMediaAttachment int 23 | 24 | // RequestToken - Obtain a code from Pocket 25 | type RequestToken struct { 26 | Code string `json:"code"` 27 | } 28 | 29 | // AuthenticationResponse response from Pocket 30 | type AuthenticationResponse struct { 31 | Code string // Code is request Token 32 | State string 33 | } 34 | 35 | // AuthorisationResponse response from Pocket 36 | type AuthorisationResponse struct { 37 | AccessToken string `json:"access_token"` 38 | Username string `json:"username"` 39 | } 40 | 41 | // RetrieveRequest - response from Pocket 42 | type RetrieveRequest struct { 43 | ConsumerKey string `json:"consumer_key"` 44 | AccessToken string `json:"access_token"` 45 | State State `json:"state,omitempty"` 46 | Favorite FavoriteFilter `json:"favorite,omitempty"` 47 | Tag string `json:"tag,omitempty"` 48 | ContentType ContentType `json:"contentType,omitempty"` 49 | Sort Sort `json:"sort,omitempty"` 50 | DetailType DetailType `json:"detailType,omitempty"` 51 | Search string `json:"search,omitempty"` 52 | Domain string `json:"domain,omitempty"` 53 | Since int `json:"since,omitempty"` 54 | Count int `json:"count,omitempty"` 55 | Offset int `json:"offset,omitempty"` 56 | } 57 | 58 | // RetrieveResponse - List of items retrieved from Pocket 59 | type RetrieveResponse struct { 60 | Status int 61 | Complete int 62 | List map[string]Item 63 | Since int 64 | } 65 | 66 | // Item - Individual Pocket Item 67 | type Item struct { 68 | ItemID int `json:"item_id,string"` 69 | ResolvedID int `json:"resolved_id,string"` 70 | GivenURL string `json:"given_url"` 71 | GivenTitle string `json:"given_title"` 72 | Favorite int `json:",string"` 73 | Status ItemStatus `json:",string"` 74 | SortID int `json:"sort_id"` 75 | ResolvedTitle string `json:"resolved_title"` 76 | ResolvedURL string `json:"resolved_url"` 77 | Excerpt string 78 | IsArticle int `json:"is_article,string"` 79 | HasImage ItemMediaAttachment `json:"has_image,string"` 80 | HasVideo ItemMediaAttachment `json:"has_video,string"` 81 | WordCount int `json:"word_count,string"` 82 | } 83 | 84 | // ModifyRequest - Send actions to pocket, i.e. add, archive, readd, favourite, unfavourite, delete 85 | type ModifyRequest struct { 86 | ConsumerKey string `json:"consumer_key"` 87 | AccessToken string `json:"access_token"` 88 | Actions []*Action `json:"actions"` 89 | } 90 | 91 | // ModifyResponse - Result of modifications against pocket. 92 | type ModifyResponse struct { 93 | Status int 94 | ActionResults []bool `json:"action_results"` 95 | } 96 | 97 | // Action represents one action in a bulk modify requests. 98 | type Action struct { 99 | Action string `json:"action"` 100 | ItemID int `json:"item_id,string"` 101 | } 102 | --------------------------------------------------------------------------------