notehub 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: ca0bd1cf2aef21ee30951b866b124f3765f83214
4
+ data.tar.gz: 4db1cef1632b394107c25b86ab6c2085bc798da2
5
+ SHA512:
6
+ metadata.gz: 7ef53c5044ff99a73850affc1b4c5dabd2cf2ec0e882e7c36d7dbf029d499b7e19f43241f9f19f48707b5d4f384fe9fab4264f2f3886b60d0e68e32e1c45f6db
7
+ data.tar.gz: 92ff3fd23395148e9fd780796382d62271a3a3da1ae6ed4e5a0e4ec5dff2828984317d108ac654bd11e61e4ed5a5e69ce89b4561432dcfa5025134fc1769d4de
@@ -0,0 +1,6 @@
1
+ = notehub
2
+
3
+ Describe your project here
4
+
5
+ :include:notehub.rdoc
6
+
@@ -0,0 +1,267 @@
1
+ #!/usr/bin/env ruby
2
+ require 'gli'
3
+ require 'notehub'
4
+
5
+ nh = NotehubAPI.new
6
+
7
+ if RUBY_VERSION.to_f > 1.9
8
+ Encoding.default_external = Encoding::UTF_8
9
+ Encoding.default_internal = Encoding::UTF_8
10
+ end
11
+
12
+ include GLI::App
13
+
14
+ program_desc 'A command line interface for Notehub <notehub.org>'
15
+
16
+ version Notehub::VERSION
17
+
18
+ desc 'Create a new note'
19
+ arg_name '[text for new note]'
20
+ command :create do |c|
21
+ c.desc 'Alternate theme to use for note (dark, solarized-light, solarized-dark)'
22
+ c.flag [:theme]
23
+
24
+ c.desc 'Alternate font to use for note (Google Web Fonts)'
25
+ c.flag [:font]
26
+
27
+ c.desc 'Alternate font to use for headers (Google Web Fonts)'
28
+ c.flag [:header]
29
+
30
+ c.desc 'Copy resulting url to clipboard'
31
+ c.switch [:c,:copy], :negatable => false
32
+
33
+ c.desc 'Open created note in browser'
34
+ c.switch [:o,:open], :negatable => false
35
+
36
+ c.desc 'Shorten URL'
37
+ c.switch [:s,:short], :negatable => false
38
+
39
+ c.desc 'Password for future edits'
40
+ c.default_value nh.default_password
41
+ c.flag [:p,:password]
42
+
43
+ c.desc 'Read input from file'
44
+ default_value false
45
+ c.flag [:f,:file]
46
+
47
+ c.desc 'Create note from pasteboard (OS X only)'
48
+ c.switch [:P,:paste], :negatable => false
49
+
50
+ c.action do |global_options,options,args|
51
+ if options[:f]
52
+ if File.exists?(File.expand_path(options[:f]))
53
+ input = IO.read(File.expand_path(options[:f]))
54
+ else
55
+ raise "File not found: #{options[:f]}"
56
+ end
57
+ elsif options[:P]
58
+ input = %x{pbpaste}
59
+ elsif args.length > 0 && args[0] != "-"
60
+ input = args.join(" ")
61
+ # elsif STDIN.stat.size > 0
62
+ else
63
+ # puts "Input note text, ^d to submit"
64
+ if RUBY_VERSION.to_f > 1.9
65
+ input = STDIN.read.force_encoding('utf-8')
66
+ else
67
+ input = STDIN.read
68
+ end
69
+ # else
70
+ # raise "No input or text specified for note"
71
+ end
72
+
73
+ additional_options = {}
74
+ additional_options[:theme] = options[:theme] ? options[:theme] : nh.default_theme
75
+ additional_options[:font] = options[:font] ? options[:font] : nh.default_font
76
+ additional_options[:header_font] = options[:header] ? options[:header] : nh.default_header_font
77
+
78
+ res = nh.new_note(input, options[:p], additional_options)
79
+
80
+ raise "Error creating note" unless res
81
+ note_url = options[:s] ? res['short'] : res['url']
82
+ puts "Note created: #{note_url}"
83
+
84
+ %x{echo "#{note_url}"|pbcopy} if options[:c]
85
+
86
+ %x{open "#{res['url']}"} if options[:o]
87
+ end
88
+ end
89
+
90
+ # desc ''
91
+
92
+ # desc 'List stored note ids'
93
+ # arg_name 'search_term'
94
+ # command :list do |c|
95
+ # c.action do |global_options,options,args|
96
+ # nh.list_notes(args.join(" "))
97
+ # end
98
+ # end
99
+
100
+ desc 'Update a note'
101
+ arg_name 'noteID'
102
+ command :update do |c|
103
+ # TODO: Check note db for password if choosing from list
104
+ c.desc 'ID for note (default: choose from list)'
105
+ c.default_value false
106
+ c.flag [:id]
107
+
108
+ c.desc 'Create note from pasteboard (OS X only)'
109
+ c.switch [:P,:paste]
110
+
111
+ c.desc 'Password for note'
112
+ c.flag [:p,:password]
113
+
114
+ c.desc 'Read input from file'
115
+ default_value false
116
+ c.flag [:f,:file]
117
+
118
+ c.desc 'Copy resulting url to clipboard'
119
+ c.switch [:c,:copy]
120
+
121
+ c.desc 'Open created note in browser'
122
+ c.switch [:o,:open]
123
+
124
+ c.desc 'Shorten URL'
125
+ c.switch [:s,:short]
126
+
127
+ c.action do |global_options,options,args|
128
+ if options[:f]
129
+ if File.exists?(File.expand_path(options[:f]))
130
+ input = IO.read(File.expand_path(options[:f]))
131
+ else
132
+ raise "File not found: #{options[:f]}"
133
+ end
134
+ elsif options[:P]
135
+ input = %x{pbpaste}
136
+ elsif args.length > 0 && args[0] != "-"
137
+ input = args.join(" ")
138
+ # elsif STDIN.stat.size > 0
139
+ else
140
+ # puts "Input note text, ^d to submit" unless STDIN.stat.size > 0
141
+ if RUBY_VERSION.to_f > 1.9
142
+ input = STDIN.read.force_encoding('utf-8')
143
+ else
144
+ input = STDIN.read
145
+ end
146
+ # else
147
+ # raise "No input or text specified for note"
148
+ end
149
+ if options[:id]
150
+ id = options[:id]
151
+ else
152
+ note = nh.choose_note
153
+ raise "Error reading selected note" unless note
154
+ id = note['id'].strip
155
+ end
156
+ res = nh.update_note(id, input, options[:p])
157
+ raise "Error updating note" unless res
158
+
159
+ note_url = options[:s] ? res['shortUrl'] : res['longUrl']
160
+ puts "Note updated: #{note_url}"
161
+
162
+ %x{echo "#{note_url}"|pbcopy} if options[:c]
163
+
164
+ %x{open #{res['url']}} if options[:o]
165
+ end
166
+ end
167
+
168
+ desc 'Retrieve info for a selected note'
169
+ arg_name 'search_term'
170
+ command :info do |c|
171
+ c.desc 'Specific key to retrieve (id, url, short, etc.)'
172
+ c.flag [:k,:key]
173
+
174
+ c.desc 'Copy result to clipboard (OS X)'
175
+ c.switch [:c,:copy], :negatable => false
176
+
177
+ c.action do |global_options, options, args|
178
+ args = args.join(" ").strip
179
+ note = false
180
+ notes = nh.notes['notes']
181
+ if args =~ /\S\/\S/ && args =~ /^[a-z0-9\/\-]+$/
182
+
183
+ if notes.has_key? (args)
184
+ note = notes[args]
185
+ end
186
+ end
187
+
188
+ unless note
189
+ puts "Choose a note:"
190
+ note = nh.choose_note(args)
191
+ end
192
+
193
+ if note
194
+ extra = nh.read_note(note['id'])
195
+ note['stats'] = extra['statistics']
196
+ nh.store_note(note)
197
+ if options[:k]
198
+ if note.has_key?(options[:k])
199
+ out = note[options[:k]].strip
200
+ else
201
+ raise "Key #{options[:k]} not found"
202
+ end
203
+ else
204
+ out = "\n"
205
+ out += note['title'].strip + "\n"
206
+ out += "-".hr(note['title'].strip.length) + "\n"
207
+ out += " URL: #{note['short']} (#{note['url']})" + "\n"
208
+ out += "Created: #{note['stats']['published']}" + "\n"
209
+ out += " Edited: #{note['stats']['edited']}" + "\n" if note['stats'].has_key?('edited')
210
+ out += " Views: #{note['stats']['views']}" + "\n"
211
+ out += " ID: #{note['id']}"
212
+ end
213
+ puts out
214
+
215
+ if options[:c]
216
+ %x{echo #{Shellwords.escape(out.strip)}|tr -d "\n"|pbcopy}
217
+ end
218
+ else
219
+ raise "Cancelled"
220
+ end
221
+ end
222
+
223
+ end
224
+
225
+ desc 'Open the selected note in the default browser'
226
+ arg_name 'search_term'
227
+ command :view do |c|
228
+ c.action do |global_options,options,args|
229
+ puts "Choose a note:"
230
+ note = nh.choose_note(args.join(" "))
231
+ if note
232
+ %x{open "#{note['url']}"}
233
+ else
234
+ raise "Cancelled"
235
+ end
236
+ # list = nh.find_notes(args.join(" "))
237
+ # list.each_with_index { |note, i| puts "% 3d: %s" % [i+1, note['title']] }
238
+ # print "> "
239
+ # num = gets
240
+ # unless num =~ /^[a-z ]*$/i
241
+ # %x{open #{list[num.to_i - 1]['url']}}
242
+ # end
243
+ end
244
+ end
245
+
246
+ pre do |global,command,options,args|
247
+ # Pre logic here
248
+ # Return true to proceed; false to abort and not call the
249
+ # chosen command
250
+ # Use skips_pre before a command to skip this block
251
+ # on that command only
252
+ true
253
+ end
254
+
255
+ post do |global,command,options,args|
256
+ # Post logic here
257
+ # Use skips_post before a command to skip this
258
+ # block on that command only
259
+ end
260
+
261
+ on_error do |exception|
262
+ # Error logic here
263
+ # return false to skip default error handling
264
+ true
265
+ end
266
+
267
+ exit run(ARGV)
@@ -0,0 +1,13 @@
1
+ require 'notehub/version.rb'
2
+ require 'notehub/notehub.rb'
3
+ require 'json'
4
+ require 'yaml'
5
+ require 'fileutils'
6
+ require 'net/http'
7
+ require 'digest/md5'
8
+ require 'cgi'
9
+ require 'highline/import'
10
+ require 'shellwords'
11
+
12
+ # Add requires for other files you add to your project here, so
13
+ # you just need to require this one file in your bin file
@@ -0,0 +1,253 @@
1
+ #!/usr/bin/ruby
2
+
3
+ class Hash
4
+ def to_query
5
+ prefix = "?"
6
+ query_string = ""
7
+ self.each {|p, v|
8
+ query_string += "#{prefix}#{p}=#{CGI.escape(v)}"
9
+ prefix = "&"
10
+ }
11
+ query_string
12
+ end
13
+ end
14
+
15
+ class String
16
+ def hr(length=0)
17
+ length = `tput cols`.strip.to_i if length == 0
18
+ out = ""
19
+ length.times do
20
+ out += self
21
+ end
22
+ out
23
+ end
24
+ end
25
+
26
+
27
+ class NotehubAPI
28
+ API_VERSION = "1.4"
29
+ attr_reader :notes, :default_password, :default_theme, :default_font, :default_header_font
30
+
31
+ def initialize(opts={})
32
+
33
+ opts['config_location'] ||= "#{ENV['HOME']}/.notehub"
34
+ opts['config_file'] ||= "#{opts['config_location']}/config.yml"
35
+ opts['notes_db'] ||= "#{opts['config_location']}/notes.db"
36
+
37
+ config_file = opts['config_file']
38
+ @notes_db = opts['notes_db']
39
+
40
+ # Set up config
41
+ FileUtils.mkdir_p(opts['config_location'],:mode => 0755) unless File.directory? opts['config_location']
42
+ unless File.exists?(config_file)
43
+ new_config = {
44
+ 'publisher_id' => "your_publisher_id",
45
+ 'secret_key' => "your_secret_key",
46
+ 'default_password' => "default password for editing notes",
47
+ 'default_theme' => "light",
48
+ 'default_font' => 'Georgia'
49
+ }.to_yaml
50
+
51
+ File.open(config_file, 'w') { |yf| YAML::dump(new_config, yf) }
52
+ end
53
+
54
+ config = YAML.load_file(config_file)
55
+ @pid = config['publisher_id']
56
+ @psk = config['secret_key']
57
+ if config['default_password'] && config['default_password'].length > 0
58
+ @default_password = config['default_password']
59
+ else
60
+ @default_password = false
61
+ end
62
+ @default_theme = config['default_theme'] || 'light'
63
+ @default_font = config['default_font'] || 'Georgia'
64
+ @default_header_font = config['default_header_font'] || 'Georgia'
65
+
66
+ # verify config
67
+ if @pid == "your_publisher_id" || @psk == "your_secret_key"
68
+ puts "Please edit #{config_file} and run again"
69
+ Process.exit 1
70
+ end
71
+
72
+ # set up notes database
73
+ unless File.exists?(@notes_db)
74
+ new_db = {'notes' => {}}
75
+ File.open(@notes_db, 'w') { |yf| YAML::dump(new_db, yf) }
76
+ end
77
+
78
+ # load existing notes
79
+ @notes = YAML.load_file(@notes_db)
80
+ end
81
+
82
+ def store_note(note)
83
+ @notes['notes'][note['id']] = note
84
+ File.open(@notes_db, 'w') { |yf| YAML::dump(@notes, yf) }
85
+ end
86
+
87
+ def post_api(params, action="post")
88
+ uri = URI("http://www.notehub.org/api/note")
89
+
90
+ if action == "put"
91
+ req = Net::HTTP::Put.new(uri)
92
+ else
93
+ req = Net::HTTP::Post.new(uri)
94
+ end
95
+ req.set_form_data(params)
96
+
97
+ res = Net::HTTP.start(uri.hostname, uri.port) do |http|
98
+ http.request(req)
99
+ end
100
+
101
+ case res
102
+ when Net::HTTPSuccess, Net::HTTPRedirection
103
+ json = JSON.parse(res.body)
104
+ if json['status']['success']
105
+ return json
106
+ else
107
+ raise "POST request returned error: #{json['status']['message']}"
108
+ end
109
+ else
110
+ # res.value
111
+ p res.body if res
112
+ raise "Error retrieving POST request to API"
113
+ end
114
+ # res = Net::HTTP.post_form(uri, params)
115
+ end
116
+
117
+ def get_api(params)
118
+ params['version'] = API_VERSION
119
+
120
+ uri = URI("http://www.notehub.org/api/note#{params.to_query}")
121
+
122
+ Net::HTTP.start(uri.host, uri.port) do |http|
123
+ req = Net::HTTP::Get.new uri
124
+ res = http.request req
125
+ if res && res.code == "200"
126
+ json = JSON.parse(res.body)
127
+ if json['status']['success']
128
+ return json
129
+ else
130
+ raise "GET request returned error: #{json['status']['message']}"
131
+ end
132
+ else
133
+ p res.body if res
134
+ raise "Error retrieving GET request to API"
135
+ end
136
+ end
137
+ end
138
+
139
+ def new_note(text, pass=false, options={})
140
+ options[:theme] ||= nil
141
+ options[:font] ||= nil
142
+
143
+ params = {}
144
+ params['note'] = text.strip
145
+ params['pid'] = @pid
146
+ params['signature'] = Digest::MD5.hexdigest(@pid + @psk + text.strip)
147
+ params['password'] = Digest::MD5.hexdigest(pass) if pass
148
+ params['version'] = API_VERSION
149
+
150
+ params['theme'] = options[:theme] unless options[:theme].nil?
151
+ params['text-font'] = options[:font] unless options[:font].nil?
152
+ params['header-font'] = options[:header_font] unless options[:header_font].nil?
153
+
154
+ res = post_api(params)
155
+
156
+ if res && res['status']['success']
157
+ note_data = read_note(res['noteID'])
158
+ note = {
159
+ 'title' => note_data['title'][0..80],
160
+ 'id' => res['noteID'],
161
+ 'url' => res['longURL'],
162
+ 'short' => res['shortURL'],
163
+ 'stats' => note_data['statistics'],
164
+ 'pass' => pass || ""
165
+ }
166
+ store_note(note)
167
+ return note
168
+ else
169
+ if res
170
+ raise "Failed: #{res['status']['comment']} "
171
+ else
172
+ raise "Failed to create note"
173
+ end
174
+ end
175
+ end
176
+
177
+ def update_note(id, text, pass=false)
178
+ # TODO: Signature invalid
179
+ params = {}
180
+ pass ||= @default_password
181
+ # raise "Password required for update" unless pass
182
+
183
+ md5_pass = Digest::MD5.hexdigest(pass)
184
+
185
+ params['password'] = md5_pass
186
+ params['noteID'] = id
187
+ params['note'] = text.strip
188
+ params['pid'] = @pid
189
+ sig = @pid + @psk + id + text.strip + md5_pass
190
+ params['signature'] = Digest::MD5.hexdigest(sig)
191
+ params['version'] = API_VERSION
192
+ res = post_api(params,"put")
193
+
194
+ if res && res['status']['success']
195
+ note_data = read_note(id)
196
+ note = {
197
+ 'title' => note_data['title'][0..80].strip,
198
+ 'id' => id,
199
+ 'url' => res['longURL'],
200
+ 'short' => res['shortURL'],
201
+ 'stats' => note_data['statistics'],
202
+ 'pass' => pass || ""
203
+ }
204
+ store_note(note)
205
+ return note
206
+ else
207
+ if res
208
+ raise "Failed: #{res['status']['comment']} "
209
+ else
210
+ raise "Failed to update note"
211
+ end
212
+ end
213
+ end
214
+
215
+ def read_note(id)
216
+ params = {'noteID' => id}
217
+ get_api(params)
218
+ end
219
+
220
+ def list_notes(term=".*")
221
+ notes = find_notes(term)
222
+ notes.each {|note|
223
+ puts "> #{note['title']} [ #{note['id']} ]"
224
+ }
225
+ end
226
+
227
+ def find_notes(term=".*")
228
+ term.gsub!(/\s+/,".*?")
229
+ found_notes = []
230
+ @notes['notes'].each {|k, v|
231
+ v['id'] = k
232
+ found_notes.push(v) if v['title'] =~ /#{term}/i
233
+ }
234
+ found_notes
235
+ end
236
+
237
+ def choose_note(term=".*")
238
+ # TODO: If there's input on STDIN, gets fails. Use highline?
239
+ puts "Choose a note:"
240
+
241
+ list = find_notes(term)
242
+ list.each_with_index { |note, i| puts "% 3d: %s" % [i+1, note['title']] }
243
+ # list.each_with_index { |f,i| puts "% 3d: %s" % [i+1, f] }
244
+ num = ask("Which note? ", Integer) { |q| q.in = 1..list.length }
245
+
246
+ return false if num =~ /^[a-z ]*$/i
247
+
248
+ list[num.to_i - 1]
249
+ end
250
+ end
251
+
252
+ # nh = NotehubAPI.new
253
+ # nh.chooose_note
@@ -0,0 +1,3 @@
1
+ module Notehub
2
+ VERSION = '0.0.1'
3
+ end
@@ -0,0 +1,5 @@
1
+ = notehub
2
+
3
+ Generate this with
4
+ notehub rdoc
5
+ After you have described your command line interface
metadata ADDED
@@ -0,0 +1,141 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: notehub
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Your Name Here
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-03-14 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rake
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '>='
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '>='
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rdoc
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: aruba
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: gli
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '='
60
+ - !ruby/object:Gem::Version
61
+ version: 2.7.0
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '='
67
+ - !ruby/object:Gem::Version
68
+ version: 2.7.0
69
+ - !ruby/object:Gem::Dependency
70
+ name: json
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - '='
74
+ - !ruby/object:Gem::Version
75
+ version: 1.5.5
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - '='
81
+ - !ruby/object:Gem::Version
82
+ version: 1.5.5
83
+ - !ruby/object:Gem::Dependency
84
+ name: highline
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - '='
88
+ - !ruby/object:Gem::Version
89
+ version: 1.6.21
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - '='
95
+ - !ruby/object:Gem::Version
96
+ version: 1.6.21
97
+ description:
98
+ email: your@email.address.com
99
+ executables:
100
+ - notehub
101
+ extensions: []
102
+ extra_rdoc_files:
103
+ - README.rdoc
104
+ - notehub.rdoc
105
+ files:
106
+ - bin/notehub
107
+ - lib/notehub/version.rb
108
+ - lib/notehub/notehub.rb
109
+ - lib/notehub.rb
110
+ - README.rdoc
111
+ - notehub.rdoc
112
+ homepage: http://your.website.com
113
+ licenses: []
114
+ metadata: {}
115
+ post_install_message:
116
+ rdoc_options:
117
+ - --title
118
+ - notehub
119
+ - --main
120
+ - README.rdoc
121
+ - -ri
122
+ require_paths:
123
+ - lib
124
+ - lib
125
+ required_ruby_version: !ruby/object:Gem::Requirement
126
+ requirements:
127
+ - - '>='
128
+ - !ruby/object:Gem::Version
129
+ version: '0'
130
+ required_rubygems_version: !ruby/object:Gem::Requirement
131
+ requirements:
132
+ - - '>='
133
+ - !ruby/object:Gem::Version
134
+ version: '0'
135
+ requirements: []
136
+ rubyforge_project:
137
+ rubygems_version: 2.1.11
138
+ signing_key:
139
+ specification_version: 4
140
+ summary: A description of your project
141
+ test_files: []