pinup 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,25 @@
1
+ require 'launchy'
2
+
3
+ module Pinup
4
+ class Open
5
+ def self.open_pins(options = {})
6
+ unread = options[:unread] unless options[:unread].nil?
7
+ untagged = options[:untagged] unless options[:untagged].nil?
8
+ count = options[:number].to_i unless options[:number].nil?
9
+ delete = options[:delete] unless options[:delete].nil?
10
+
11
+ items = Pinup::Queries.list_items
12
+ filtered = Pinup::Queries.filter_items(items, unread, untagged, count)
13
+ items_string = Pinup::Queries.item_string(filtered)
14
+ urls = items_string.split(/\n/)
15
+
16
+ urls.each do |url|
17
+ Launchy.open(url)
18
+ end
19
+
20
+ if delete
21
+ Pinup::Queries.delete_items(urls)
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,116 @@
1
+ require 'net/https'
2
+ require 'uri'
3
+ require 'json'
4
+
5
+ module Pinup
6
+ class Queries
7
+ def self.list_items
8
+ token = Pinup::Settings.get_token
9
+ if token.nil?
10
+ return nil
11
+ end
12
+
13
+ parameters = JSON_PARAMS.dup
14
+ parameters[:auth_token] = token
15
+
16
+ response = list_query(parameters)
17
+ if response.code != '200'
18
+ puts "Error getting bookmarks: #{ response.body }"
19
+ return nil
20
+ else
21
+ return response.body
22
+ end
23
+ end
24
+
25
+ def self.filter_items(response, unread, untagged, count)
26
+ begin
27
+ json = JSON.parse(response)
28
+ rescue JSON::ParserError => e
29
+ puts "Failed to parse JSON: #{ e }"
30
+ exit
31
+ end
32
+
33
+ count = 20 if count < 1
34
+ new_items = []
35
+
36
+ json.each do |item|
37
+ bookmark = Bookmark.new(item)
38
+
39
+ if unread && untagged
40
+ if bookmark.unread || bookmark.untagged
41
+ new_items << bookmark
42
+ end
43
+ elsif unread
44
+ if bookmark.unread && !bookmark.untagged
45
+ new_items << bookmark
46
+ end
47
+ elsif untagged
48
+ if bookmark.untagged && !bookmark.unread
49
+ new_items << bookmark
50
+ end
51
+ else
52
+ if !bookmark.unread && !bookmark.untagged
53
+ new_items << bookmark
54
+ end
55
+ end
56
+
57
+ if new_items.count >= count
58
+ break
59
+ end
60
+ end
61
+
62
+ return new_items
63
+ end
64
+
65
+ def self.delete_items(urls)
66
+ token = Pinup::Settings.get_token
67
+ if token.nil?
68
+ return nil
69
+ end
70
+
71
+ parameters = JSON_PARAMS.dup
72
+ parameters[:auth_token] = token
73
+
74
+ urls.each do |url|
75
+ url_params = parameters.dup
76
+ url_params[:url] = url
77
+ delete_query(url_params)
78
+ end
79
+ end
80
+
81
+ def self.item_string(items)
82
+ item_output = ""
83
+ items.each do |item|
84
+ item_output << "#{ item.href }\n"
85
+ end
86
+
87
+ return item_output
88
+ end
89
+
90
+ private
91
+
92
+ def self.list_query(parameters)
93
+ uri = URI.parse("#{ API_URL }/posts/all")
94
+ uri.query = URI.encode_www_form(parameters)
95
+
96
+ http = Net::HTTP.new(uri.host, uri.port)
97
+ http.use_ssl = true
98
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
99
+
100
+ request = Net::HTTP::Get.new(uri.request_uri)
101
+ http.request(request)
102
+ end
103
+
104
+ def self.delete_query(parameters)
105
+ uri = URI.parse("#{ API_URL }/posts/delete")
106
+ uri.query = URI.encode_www_form(parameters)
107
+
108
+ http = Net::HTTP.new(uri.host, uri.port)
109
+ http.use_ssl = true
110
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
111
+
112
+ request = Net::HTTP::Get.new(uri.request_uri)
113
+ http.request(request)
114
+ end
115
+ end
116
+ end
@@ -0,0 +1,89 @@
1
+ require 'yaml'
2
+ require 'netrc'
3
+ require 'colored'
4
+
5
+ module Pinup
6
+ class Settings
7
+ def self.write_settings(settings)
8
+ File.open(SETTINGS, 'w') do |f|
9
+ f.write(settings.to_yaml)
10
+ end
11
+ end
12
+
13
+ def self.read_settings
14
+ if !File.exists? SETTINGS
15
+ return nil
16
+ end
17
+
18
+ settings = YAML::load_file(SETTINGS)
19
+ if !settings || settings.empty?
20
+ return nil
21
+ end
22
+
23
+ return settings
24
+ end
25
+
26
+ def self.save_token(options = {})
27
+ path = DEFAULT_NETRC
28
+ token = options[:token]
29
+
30
+ if token.nil?
31
+ puts 'Attempted to save empty token'.red
32
+ return nil
33
+ end
34
+
35
+ if options[:path]
36
+ path = options[:path]
37
+ end
38
+
39
+ token_split = token.split(/:/)
40
+ if token_split.count != 2
41
+ puts "Invalid token #{ token_split.join(':') }".red
42
+ return nil
43
+ end
44
+
45
+ username = token_split.first
46
+ password = token_split.last
47
+
48
+ netrc = Netrc.read(path)
49
+ netrc.new_item_prefix = "\n# This Entry was added automatically\n"
50
+ netrc[PINBOARD_URL] = username, password
51
+ netrc.save
52
+
53
+ return true
54
+ end
55
+
56
+ def self.get_token
57
+ path = DEFAULT_NETRC
58
+
59
+ settings = read_settings
60
+ if settings
61
+ path = settings[:path]
62
+ end
63
+
64
+ netrc = Netrc.read(path)
65
+ username, password = netrc[PINBOARD_URL]
66
+ token = token(username, password)
67
+ if token.nil?
68
+ puts "There are no credentials in #{ path }".red
69
+ return nil
70
+ end
71
+
72
+ return token
73
+ end
74
+
75
+ def self.clear_settings
76
+ if File.exists? SETTINGS
77
+ File.delete(SETTINGS)
78
+ end
79
+ end
80
+
81
+ def self.token(username, password)
82
+ if username.nil? || password.nil? || username.empty? || password.empty?
83
+ return nil
84
+ end
85
+
86
+ "#{ username }:#{ password }"
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,8 @@
1
+ module Pinup
2
+ VERSION = '0.1.0'
3
+ SETTINGS = File.expand_path('~/.pinup')
4
+ PINBOARD_URL = 'pinboard.in'
5
+ API_URL = 'https://api.pinboard.in/v1'
6
+ JSON_PARAMS = { format: 'json' }
7
+ DEFAULT_NETRC = File.expand_path('~/.netrc')
8
+ end
data/pinup.gemspec ADDED
@@ -0,0 +1,24 @@
1
+ require File.join([File.dirname(__FILE__),'lib','pinup','version.rb'])
2
+ spec = Gem::Specification.new do |s|
3
+ s.name = 'pinup'
4
+ s.version = Pinup::VERSION
5
+ s.author = 'Keith Smiley'
6
+ s.email = 'keithbsmiley@gmail.com'
7
+ s.homepage = 'http://keith.so/'
8
+ s.required_ruby_version = '>= 1.9.3'
9
+ s.summary = 'Digest your Pinboard bookmarks in bulk'
10
+ s.description = 'Allows you to open and delete your Pinboard bookmarks in bulk'
11
+ s.license = 'MIT'
12
+
13
+ s.files = `git ls-files`.split($/)
14
+ s.executables = s.files.grep(%r{^bin/}) { |f| File.basename(f) }
15
+ s.test_files = s.files.grep(%r{^(test|spec|features)/})
16
+ s.require_paths = ['lib']
17
+
18
+ s.add_dependency('colored', '~> 1.2')
19
+ s.add_dependency('netrc', '~> 0.7.7')
20
+ s.add_dependency('launchy', '~> 2.3.0')
21
+ s.add_development_dependency('rake')
22
+ s.add_development_dependency('rspec', '~> 2.13.0')
23
+ s.add_runtime_dependency('gli','2.5.6')
24
+ end
@@ -0,0 +1,42 @@
1
+ require_relative '../spec_helper'
2
+
3
+ describe Pinup::Authorize do
4
+ before do
5
+ @netrc_path = File.expand_path('~/foobar')
6
+ end
7
+
8
+ describe 'authorize_netrc' do
9
+ describe 'an empty netrc' do
10
+ it 'should return nil' do
11
+ expect(Pinup::Authorize.authorize_netrc({ path: @netrc_path })).to be_nil
12
+ end
13
+ end
14
+
15
+ describe 'a valid netrc' do
16
+ it 'should return true' do
17
+ # This will only pass if your default netrc has a valid username and password (token)
18
+ expect(Pinup::Authorize.authorize_netrc).to be_true
19
+ end
20
+ end
21
+ end
22
+
23
+ describe 'authorize_credentials' do
24
+ describe 'invalid credentials' do
25
+ it 'should return nil' do
26
+ expect(Pinup::Authorize.authorize_credentials({ username: 'foo', password: 'bar' })).to be_nil
27
+ end
28
+ end
29
+
30
+ describe 'valid credentials' do
31
+ # Note: this will only work if you set up netrc's for this testing
32
+ it 'should return true' do
33
+ netrc = Netrc.read
34
+ username, password = netrc['test.pinboard.in']
35
+ expect(username).not_to be_nil
36
+ expect(password).not_to be_nil
37
+ result = Pinup::Authorize.authorize_credentials({ username: username, password: password })
38
+ expect(result).to be_true
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,97 @@
1
+ require_relative '../spec_helper'
2
+
3
+ describe Bookmark do
4
+ describe 'attributes' do
5
+ before do
6
+ options = { 'href' => 'http://github.com', 'toread' => 'yes', 'tags' => '' }
7
+ @bookmark = Bookmark.new(options)
8
+ end
9
+
10
+ it 'should respond to the correct attributes' do
11
+ expect(@bookmark).to respond_to(:href)
12
+ expect(@bookmark).to respond_to(:unread)
13
+ expect(@bookmark).to respond_to(:untagged)
14
+ expect(@bookmark).not_to respond_to(:foobar)
15
+ end
16
+ end
17
+
18
+ describe 'initialize' do
19
+ describe 'unread without tags' do
20
+ before do
21
+ options = { 'href' => 'http://github.com', 'toread' => 'yes', 'tags' => '' }
22
+ @bookmark = Bookmark.new(options)
23
+ end
24
+
25
+ it 'have the correct attributes' do
26
+ expect(@bookmark).not_to be_nil
27
+ result = @bookmark.href == 'http://github.com'
28
+ expect(result).to be_true
29
+ expect(@bookmark.unread).to be_true
30
+ expect(@bookmark.untagged).to be_true
31
+ end
32
+ end
33
+
34
+ describe 'read with tags' do
35
+ before do
36
+ options = { 'href' => 'http://google.com', 'toread' => 'no', 'tags' => 'foo' }
37
+ @bookmark = Bookmark.new(options)
38
+ end
39
+
40
+ it 'have the correct attributes' do
41
+ expect(@bookmark).not_to be_nil
42
+ result = @bookmark.href == 'http://google.com'
43
+ expect(result).to be_true
44
+ expect(@bookmark.unread).to be_false
45
+ expect(@bookmark.untagged).to be_false
46
+ end
47
+ end
48
+ end
49
+
50
+ describe 'is_unread' do
51
+ it 'should return true only when toread is "yes"' do
52
+ expect(Bookmark.is_unread('yes')).to be_true
53
+ end
54
+
55
+ it 'should return false otherwise' do
56
+ expect(Bookmark.is_unread('false')).to be_false
57
+ expect(Bookmark.is_unread('no')).to be_false
58
+ expect(Bookmark.is_unread('foo')).to be_false
59
+ end
60
+ end
61
+
62
+
63
+ describe 'is_untagged' do
64
+ it 'should return true if there is nothing in the tag field' do
65
+ expect(Bookmark.is_untagged(' ')).to be_true
66
+ expect(Bookmark.is_untagged("\n \t \r")).to be_true
67
+ end
68
+
69
+ it 'should return false if there is something in the tag field' do
70
+ expect(Bookmark.is_untagged('foo')).to be_false
71
+ expect(Bookmark.is_untagged('foo bar')).to be_false
72
+ end
73
+ end
74
+
75
+ describe 'to_s' do
76
+ before do
77
+ options = { 'href' => 'http://google.com', 'toread' => 'no', 'tags' => 'foo' }
78
+ @bookmark = Bookmark.new(options)
79
+ @response = @bookmark.to_s
80
+ end
81
+
82
+ it 'should contain the URL' do
83
+ result = @response.include? 'google.com'
84
+ expect(result).to be_true
85
+ end
86
+
87
+ it 'should contain unread settings' do
88
+ result = @response.include? 'Unread: false'
89
+ expect(result).to be_true
90
+ end
91
+
92
+ it 'should contain the URL' do
93
+ result = @response.include? 'Untagged: false'
94
+ expect(result).to be_true
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,132 @@
1
+ require_relative '../spec_helper'
2
+
3
+ describe Pinup::Queries do
4
+ describe 'list_items' do
5
+ before do
6
+ items = Pinup::Queries.list_items
7
+ @posts = JSON.parse(items)
8
+ end
9
+
10
+ it 'shoud return some number of items' do
11
+ result = @posts.count > 0
12
+ expect(result).to be_true
13
+ end
14
+ end
15
+
16
+ describe 'filter_items' do
17
+ describe 'read/unread items' do
18
+ describe 'unread items' do
19
+ before do
20
+ items = Pinup::Queries.list_items
21
+ @filtered = Pinup::Queries.filter_items(items, true, false, 20)
22
+ end
23
+
24
+ it 'should return only unread items' do
25
+ @filtered.each do |item|
26
+ expect(item.unread).to be_true
27
+ expect(item.untagged).to be_false
28
+ end
29
+ end
30
+ end
31
+
32
+ describe 'read items' do
33
+ before do
34
+ items = Pinup::Queries.list_items
35
+ @filtered = Pinup::Queries.filter_items(items, false, false, 20)
36
+ end
37
+
38
+ it 'should return only read items' do
39
+ @filtered.each do |item|
40
+ expect(item.unread).to be_false
41
+ expect(item.untagged).to be_false
42
+ end
43
+ end
44
+ end
45
+ end
46
+
47
+ describe 'untagged/tagged items' do
48
+ describe 'untagged items' do
49
+ before do
50
+ items = Pinup::Queries.list_items
51
+ @filtered = Pinup::Queries.filter_items(items, false, true, 20)
52
+ end
53
+
54
+ it 'should return only untagged items' do
55
+ @filtered.each do |item|
56
+ expect(item.unread).to be_false
57
+ expect(item.untagged).to be_true
58
+ end
59
+ end
60
+ end
61
+
62
+ describe 'tagged items' do
63
+ before do
64
+ items = Pinup::Queries.list_items
65
+ @filtered = Pinup::Queries.filter_items(items, false, false, 20)
66
+ end
67
+
68
+ it 'should return only untagged items' do
69
+ result = @filtered.count > 0
70
+ expect(result).to be_true
71
+ @filtered.each do |item|
72
+ expect(item.unread).to be_false
73
+ expect(item.untagged).to be_false
74
+ end
75
+ end
76
+ end
77
+ end
78
+
79
+ # Note these will only work if the default pinboard account unread & untagged items
80
+ describe 'number of items' do
81
+ describe 'an invalid number' do
82
+ describe 'zero items' do
83
+ before do
84
+ items = Pinup::Queries.list_items
85
+ @filtered = Pinup::Queries.filter_items(items, false, false, 0)
86
+ end
87
+
88
+ it 'should return the default number of items' do
89
+ expect(@filtered.count).to equal(20)
90
+ end
91
+ end
92
+
93
+ describe 'negative items' do
94
+ before do
95
+ items = Pinup::Queries.list_items
96
+ @filtered = Pinup::Queries.filter_items(items, false, false, -9)
97
+ end
98
+
99
+ it 'should return the default number of items' do
100
+ expect(@filtered.count).to equal(20)
101
+ end
102
+ end
103
+ end
104
+
105
+ describe 'some number of unread items' do
106
+ before do
107
+ items = Pinup::Queries.list_items
108
+ @filtered = Pinup::Queries.filter_items(items, false, false, 14)
109
+ end
110
+
111
+ it 'should return the correct number of items' do
112
+ expect(@filtered.count).to equal(14)
113
+ end
114
+ end
115
+ end
116
+ end
117
+
118
+ describe 'item_string' do
119
+ before do
120
+ @item = Bookmark.new({ "href" => "http://google.com" })
121
+ @item2 = Bookmark.new({ "href" => "http://github.com" })
122
+ @urls = [ @item, @item2 ]
123
+ @response = Pinup::Queries.item_string(@urls)
124
+ @string = "http://google.com\nhttp://github.com\n"
125
+ end
126
+
127
+ it 'should return a correctly formatted string' do
128
+ result = @response == @string
129
+ expect(result).to be_true
130
+ end
131
+ end
132
+ end