talknote_rb 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,107 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ # Example script demonstrating group functionality
5
+ # Usage: ruby examples/group_example.rb
6
+
7
+ require_relative '../lib/talknote'
8
+
9
+ def main
10
+ puts "šŸš€ Talknote Group API Example"
11
+ puts "=" * 50
12
+
13
+ begin
14
+ client = Talknote::Client.new
15
+ puts "āœ… Successfully initialized Talknote client"
16
+ rescue StandardError => e
17
+ puts "āŒ Failed to initialize client: #{e.message}"
18
+ puts "\nMake sure you've run: talknote init -i CLIENT_ID -s CLIENT_SECRET"
19
+ exit 1
20
+ end
21
+
22
+ # Example 1: List all groups
23
+ puts "\nšŸ“‹ Listing all groups..."
24
+ begin
25
+ groups_response = client.group
26
+ groups = groups_response.dig('data', 'groups') || []
27
+
28
+ if groups.empty?
29
+ puts " No groups found"
30
+ else
31
+ puts " Found #{groups.length} groups:"
32
+ groups.first(3).each do |group|
33
+ puts " - #{group['name']} (ID: #{group['id']})"
34
+ end
35
+ puts " ... (showing first 3 groups)" if groups.length > 3
36
+ end
37
+ rescue Talknote::Error => e
38
+ puts " āŒ Error: #{e.message}"
39
+ end
40
+
41
+ # Example 2: Get group details and unread count
42
+ puts "\nšŸ“Š Checking unread messages in groups..."
43
+ begin
44
+ groups_response = client.group
45
+ groups = groups_response.dig('data', 'groups') || []
46
+
47
+ groups.first(2).each do |group|
48
+ puts " Group: #{group['name']}"
49
+
50
+ # Get unread count
51
+ begin
52
+ unread_response = client.group_unread(group['id'])
53
+ unread_count = unread_response.dig('data', 'unread_count') || 0
54
+ puts " šŸ“¬ Unread messages: #{unread_count}"
55
+ rescue Talknote::Error => e
56
+ puts " āŒ Could not get unread count: #{e.message}"
57
+ end
58
+
59
+ # Get messages from the group
60
+ begin
61
+ messages_response = client.group_list(group['id'])
62
+ puts " ļæ½ Messages: Available"
63
+ rescue Talknote::Error => e
64
+ puts " ļæ½ Messages: Could not retrieve (#{e.message})"
65
+ end
66
+
67
+ puts ""
68
+ end
69
+ rescue Talknote::Error => e
70
+ puts " āŒ Error: #{e.message}"
71
+ end
72
+
73
+ # Example 3: Send a test message (commented out for safety)
74
+ puts "\nšŸ’¬ Example: Sending a message to a group"
75
+ puts " (This example is commented out for safety)"
76
+ puts " To send a message, uncomment the code below and specify a group ID:"
77
+ puts ""
78
+ puts " # group_id = 'your_group_id_here'"
79
+ puts " # message = 'Hello from TalknoteRb! šŸš€'"
80
+ puts " # result = client.group_post(group_id, message)"
81
+ puts " # puts \"Message sent successfully!\""
82
+
83
+ # Uncomment and modify the following lines to actually send a message:
84
+ # group_id = 'YOUR_GROUP_ID_HERE'
85
+ # message = 'Test message from TalknoteRb example script! šŸš€'
86
+ # begin
87
+ # result = client.group_post(group_id, message)
88
+ # puts " āœ… Message sent successfully!"
89
+ # puts " Response: #{result}"
90
+ # rescue Talknote::Error => e
91
+ # puts " āŒ Failed to send message: #{e.message}"
92
+ # end
93
+
94
+ puts "\nšŸŽ‰ Group API example completed!"
95
+ puts "\nNext steps:"
96
+ puts "- Try running: bundle exec talknote group"
97
+ puts "- Send a message: bundle exec talknote group-post GROUP_ID 'Your message'"
98
+
99
+ rescue StandardError => e
100
+ puts "\nšŸ’„ Unexpected error: #{e.message}"
101
+ puts e.backtrace.first(5).join("\n")
102
+ exit 1
103
+ end
104
+
105
+ if __FILE__ == $0
106
+ main
107
+ end
data/lib/talknote/cli.rb CHANGED
@@ -2,6 +2,11 @@
2
2
 
3
3
  require 'talknote'
4
4
  require 'thor'
5
+ require 'webrick'
6
+ require 'pp'
7
+ require 'oauth2'
8
+ require 'fileutils'
9
+ require 'json'
5
10
 
6
11
  module Talknote
7
12
  class CLI < Thor
@@ -11,7 +16,7 @@ module Talknote
11
16
  option 'id', aliases: 'i', type: :string, required: true, banner: 'Client ID'
12
17
  option 'secret', aliases: 's', type: :string, required: true, banner: 'Client Secret'
13
18
  option 'host', aliases: 'h', type: :string, default: '127.0.0.1', banner: 'Callback host'
14
- option 'port', aliases: 'p', type: :string, default: '3000', banner: 'Callback port'
19
+ option 'port', aliases: 'p', type: :string, default: '8080', banner: 'Callback port'
15
20
  def init
16
21
  state = ('a'..'z').to_a.sample(32).join
17
22
  path = '/oauth/callback'
@@ -25,26 +30,29 @@ module Talknote
25
30
  )
26
31
 
27
32
  redirect_uri = "http://#{options['host']}:#{options['port']}#{path}"
28
- scope = %w[talknote.timeline.read
29
- talknote.timeline.write
30
- talknote.timeline.message.read
31
- talknote.timeline.message.write
32
- talknote.timeline.unread
33
- talknote.group
34
- talknote.group.read
35
- talknote.group.write
36
- talknote.group.unread
37
- talknote.group.message.read
38
- talknote.group.message.write
39
- talknote.direct_message
40
- talknote.direct_message.read
41
- talknote.direct_message.write
42
- talknote.direct_message.unread
43
- talknote.direct_message.message.read
44
- talknote.direct_message.message.write
45
- talknote.user.read talknote.user.write
46
- talknote.allfeed.read
47
- talknote.allfeed.unread].join(' ')
33
+ scope = [
34
+ 'talknote.timeline.read',
35
+ 'talknote.timeline.write',
36
+ 'talknote.timeline.message.read',
37
+ 'talknote.timeline.message.write',
38
+ 'talknote.timeline.unread',
39
+ 'talknote.group',
40
+ 'talknote.group.read',
41
+ 'talknote.group.write',
42
+ 'talknote.group.unread',
43
+ 'talknote.group.message.read',
44
+ 'talknote.group.message.write',
45
+ 'talknote.direct_message',
46
+ 'talknote.direct_message.read',
47
+ 'talknote.direct_message.write',
48
+ 'talknote.direct_message.unread',
49
+ 'talknote.direct_message.message.read',
50
+ 'talknote.direct_message.message.write',
51
+ 'talknote.user.read',
52
+ 'talknote.user.write',
53
+ 'talknote.allfeed.read',
54
+ 'talknote.allfeed.unread'
55
+ ].join(' ')
48
56
 
49
57
  code_args = {
50
58
  redirect_uri: redirect_uri,
@@ -55,9 +63,28 @@ module Talknote
55
63
  url = client.auth_code.authorize_url(code_args)
56
64
 
57
65
  puts ''
58
- puts "Go to URL: #{url}"
66
+ puts "Authorization URL: #{url}"
59
67
  puts ''
60
68
 
69
+ # Automatically open the URL in the default browser
70
+ begin
71
+ if RUBY_PLATFORM =~ /darwin/ # macOS
72
+ system("open '#{url}'")
73
+ puts "Opening browser automatically..."
74
+ elsif RUBY_PLATFORM =~ /linux/
75
+ system("xdg-open '#{url}'")
76
+ puts "Opening browser automatically..."
77
+ elsif RUBY_PLATFORM =~ /win32|win64|\.NET|windows|cygwin|mingw32/i
78
+ system("start '#{url}'")
79
+ puts "Opening browser automatically..."
80
+ else
81
+ puts "Please manually open the URL above in your browser."
82
+ end
83
+ rescue => e
84
+ puts "Could not open browser automatically: #{e.message}"
85
+ puts "Please manually open the URL above in your browser."
86
+ end
87
+
61
88
  puts 'Starting server - use Ctrl+C to stop'
62
89
  puts ''
63
90
 
@@ -80,25 +107,36 @@ module Talknote
80
107
  next
81
108
  end
82
109
 
83
- token = client.auth_code.get_token(
84
- req.query['code'],
85
- grant_type: 'authorization_code',
86
- redirect_uri: redirect_uri
87
- )
110
+ begin
111
+ token = client.auth_code.get_token(
112
+ req.query['code'],
113
+ grant_type: 'authorization_code',
114
+ redirect_uri: redirect_uri
115
+ )
88
116
 
89
- pp token.to_hash
90
- puts ''
117
+ pp token.to_hash
118
+ puts ''
91
119
 
92
- config_path = "#{Dir.home}/.config/talknote"
93
- unless Dir.exists?(config_path)
94
- Dir.mkdir(config_path)
95
- end
120
+ config_path = "#{Dir.home}/.config/talknote"
121
+ FileUtils.mkdir_p(config_path) unless Dir.exist?(config_path)
96
122
 
97
- File.write("#{config_path}/token.json", token.to_hash.to_json)
98
- res.status = 200
99
- res.body = 'You may now close this tab'
123
+ File.write("#{config_path}/token.json", token.to_hash.to_json)
124
+ res.status = 200
125
+ res.body = 'You may now close this tab'
100
126
 
101
- server.shutdown
127
+ server.shutdown
128
+ rescue OAuth2::Error => e
129
+ puts "OAuth2 Error: #{e.message}"
130
+ puts "Error Code: #{e.code}" if e.respond_to?(:code)
131
+ puts "Error Description: #{e.description}" if e.respond_to?(:description)
132
+ res.status = 400
133
+ res.body = "OAuth Error: #{e.message}"
134
+ rescue => e
135
+ puts "General Error: #{e.message}"
136
+ puts e.backtrace.join("\n")
137
+ res.status = 500
138
+ res.body = "Server Error: #{e.message}"
139
+ end
102
140
  end
103
141
 
104
142
  trap('INT') do
@@ -111,8 +149,75 @@ module Talknote
111
149
  desc 'dm', 'Show dm list'
112
150
  def dm
113
151
  pp Talknote::Client.new.dm
152
+ rescue Talknote::Error => e
153
+ puts "Error: #{e.message}"
154
+ exit 1
155
+ end
156
+
157
+ desc 'dm-list ID', 'Show messages from a DM conversation'
158
+ def dm_list(id)
159
+ pp Talknote::Client.new.dm_list(id)
160
+ rescue Talknote::Error => e
161
+ puts "Error: #{e.message}"
162
+ exit 1
163
+ end
164
+
165
+ desc 'dm-unread ID', 'Show unread count for a DM conversation'
166
+ def dm_unread(id)
167
+ pp Talknote::Client.new.dm_unread(id)
168
+ rescue Talknote::Error => e
169
+ puts "Error: #{e.message}"
170
+ exit 1
171
+ end
172
+
173
+ desc 'dm-post ID MESSAGE', 'Send a message to a DM conversation'
174
+ def dm_post(id, message)
175
+ result = Talknote::Client.new.dm_post(id, message)
176
+ puts "Message sent successfully!"
177
+ pp result
178
+ rescue Talknote::Error => e
179
+ puts "Error: #{e.message}"
180
+ exit 1
114
181
  end
115
182
 
183
+
184
+
185
+ desc 'group', 'Show group list'
186
+ def group
187
+ pp Talknote::Client.new.group
188
+ rescue Talknote::Error => e
189
+ puts "Error: #{e.message}"
190
+ exit 1
191
+ end
192
+
193
+ desc 'group-list ID', 'Show messages from a group'
194
+ def group_list(id)
195
+ pp Talknote::Client.new.group_list(id)
196
+ rescue Talknote::Error => e
197
+ puts "Error: #{e.message}"
198
+ exit 1
199
+ end
200
+
201
+ desc 'group-unread ID', 'Show unread count for a group'
202
+ def group_unread(id)
203
+ pp Talknote::Client.new.group_unread(id)
204
+ rescue Talknote::Error => e
205
+ puts "Error: #{e.message}"
206
+ exit 1
207
+ end
208
+
209
+ desc 'group-post ID MESSAGE', 'Send a message to a group'
210
+ def group_post(id, message)
211
+ result = Talknote::Client.new.group_post(id, message)
212
+ puts "Message sent successfully!"
213
+ pp result
214
+ rescue Talknote::Error => e
215
+ puts "Error: #{e.message}"
216
+ exit 1
217
+ end
218
+
219
+
220
+
116
221
  class << self
117
222
  def exit_on_failure?
118
223
  true
@@ -1,38 +1,60 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'json'
4
+ require 'uri'
4
5
 
5
6
  module Talknote
6
7
  class Client
7
8
 
8
9
  def dm
9
- response = conn.get('api/v1/dm')
10
- JSON.parse(response.body)
10
+ handle_response(conn.get('api/v1/dm'))
11
11
  end
12
12
 
13
13
  def dm_list(id)
14
- response = conn.get("api/v1/dm/list/#{id}")
15
- JSON.parse(response.body)
14
+ handle_response(conn.get("api/v1/dm/list/#{id}"))
16
15
  end
17
16
 
18
17
  def dm_unread(id)
19
- response = conn.get("api/v1/dm/unread/#{id}")
20
- JSON.parse(response.body)
18
+ handle_response(conn.get("api/v1/dm/unread/#{id}"))
21
19
  end
22
20
 
23
- # def dm_post; end
21
+ def dm_post(id, message, options = {})
22
+ # Let's try form-encoded data instead of JSON
23
+ data = { message: message }
24
+ data.merge!(options) if options.any?
25
+
26
+ response = conn.post("api/v1/dm/post/#{id}") do |req|
27
+ req.headers['Content-Type'] = 'application/x-www-form-urlencoded'
28
+ req.body = URI.encode_www_form(data)
29
+ end
30
+ handle_response(response)
31
+ end
32
+
33
+ # Group-related methods
34
+ def group
35
+ handle_response(conn.get('api/v1/group'))
36
+ end
24
37
 
25
38
  def group_list(id)
26
- response = conn.get("api/v1/group/list/#{id}")
27
- JSON.parse(response.body)
39
+ handle_response(conn.get("api/v1/group/list/#{id}"))
40
+ end
41
+
42
+ def group_unread(id)
43
+ handle_response(conn.get("api/v1/group/unread/#{id}"))
28
44
  end
29
45
 
30
- def dm_unread(did)
31
- response = conn.get("api/v1/group/unread/#{id}")
32
- JSON.parse(response.body)
46
+ def group_post(id, message, options = {})
47
+ data = { message: message }
48
+ data.merge!(options) if options.any?
49
+
50
+ response = conn.post("api/v1/group/post/#{id}") do |req|
51
+ req.headers['Content-Type'] = 'application/x-www-form-urlencoded'
52
+ req.body = URI.encode_www_form(data)
53
+ end
54
+ handle_response(response)
33
55
  end
34
56
 
35
- # def group_post; end
57
+
36
58
 
37
59
  private
38
60
 
@@ -48,5 +70,26 @@ module Talknote
48
70
  )
49
71
  end
50
72
 
73
+ def handle_response(response)
74
+ case response.status
75
+ when 200..299
76
+ JSON.parse(response.body)
77
+ when 401
78
+ raise Talknote::Error, "Unauthorized: Please check your access token"
79
+ when 403
80
+ raise Talknote::Error, "Forbidden: Insufficient permissions"
81
+ when 404
82
+ raise Talknote::Error, "Not Found: Resource does not exist"
83
+ when 429
84
+ raise Talknote::Error, "Rate Limited: Too many requests"
85
+ when 500..599
86
+ raise Talknote::Error, "Server Error: #{response.status} - #{response.body}"
87
+ else
88
+ raise Talknote::Error, "HTTP Error: #{response.status} - #{response.body}"
89
+ end
90
+ rescue JSON::ParserError => e
91
+ raise Talknote::Error, "Invalid JSON response: #{e.message}"
92
+ end
93
+
51
94
  end
52
95
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Talknote
4
- VERSION = '0.1.0'
4
+ VERSION = '0.2.0'
5
5
  end
data/lib/talknote.rb CHANGED
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'base64'
4
+ require 'json'
3
5
  require 'oauth2'
4
6
  require 'faraday'
5
7
 
data/talknote_rb.gemspec CHANGED
@@ -21,11 +21,16 @@ Gem::Specification.new do |spec|
21
21
  spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
22
22
  `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
23
23
  end
24
- spec.bindir = "exe"
25
- spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
24
+ spec.bindir = "bin"
25
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
26
26
  spec.require_paths = ["lib"]
27
27
 
28
- spec.add_dependency 'oauth2'
28
+ spec.add_dependency 'base64'
29
+ spec.add_dependency 'bigdecimal'
30
+ spec.add_dependency 'csv', '~> 3.0'
31
+ spec.add_dependency 'json'
32
+ spec.add_dependency 'oauth2', '~> 2.0'
29
33
  spec.add_dependency 'thor'
30
- spec.add_dependency 'faraday'
34
+ spec.add_dependency 'faraday', '~> 2.0'
35
+ spec.add_dependency 'webrick'
31
36
  end
metadata CHANGED
@@ -1,17 +1,30 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: talknote_rb
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Masumi Kawasaki
8
- autorequire:
9
- bindir: exe
8
+ bindir: bin
10
9
  cert_chain: []
11
- date: 2020-11-08 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
- name: oauth2
13
+ name: base64
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - ">="
17
+ - !ruby/object:Gem::Version
18
+ version: '0'
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - ">="
24
+ - !ruby/object:Gem::Version
25
+ version: '0'
26
+ - !ruby/object:Gem::Dependency
27
+ name: bigdecimal
15
28
  requirement: !ruby/object:Gem::Requirement
16
29
  requirements:
17
30
  - - ">="
@@ -24,6 +37,48 @@ dependencies:
24
37
  - - ">="
25
38
  - !ruby/object:Gem::Version
26
39
  version: '0'
40
+ - !ruby/object:Gem::Dependency
41
+ name: csv
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: '3.0'
47
+ type: :runtime
48
+ prerelease: false
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: '3.0'
54
+ - !ruby/object:Gem::Dependency
55
+ name: json
56
+ requirement: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: '0'
61
+ type: :runtime
62
+ prerelease: false
63
+ version_requirements: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ version: '0'
68
+ - !ruby/object:Gem::Dependency
69
+ name: oauth2
70
+ requirement: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - "~>"
73
+ - !ruby/object:Gem::Version
74
+ version: '2.0'
75
+ type: :runtime
76
+ prerelease: false
77
+ version_requirements: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - "~>"
80
+ - !ruby/object:Gem::Version
81
+ version: '2.0'
27
82
  - !ruby/object:Gem::Dependency
28
83
  name: thor
29
84
  requirement: !ruby/object:Gem::Requirement
@@ -40,6 +95,20 @@ dependencies:
40
95
  version: '0'
41
96
  - !ruby/object:Gem::Dependency
42
97
  name: faraday
98
+ requirement: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - "~>"
101
+ - !ruby/object:Gem::Version
102
+ version: '2.0'
103
+ type: :runtime
104
+ prerelease: false
105
+ version_requirements: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - "~>"
108
+ - !ruby/object:Gem::Version
109
+ version: '2.0'
110
+ - !ruby/object:Gem::Dependency
111
+ name: webrick
43
112
  requirement: !ruby/object:Gem::Requirement
44
113
  requirements:
45
114
  - - ">="
@@ -55,13 +124,17 @@ dependencies:
55
124
  description: Talknote API Wrapper written in ruby.
56
125
  email:
57
126
  - mkawasaki@sbihg.co.jp
58
- executables: []
127
+ executables:
128
+ - console
129
+ - setup
130
+ - talknote
59
131
  extensions: []
60
132
  extra_rdoc_files: []
61
133
  files:
134
+ - ".github/dependabot.yml"
135
+ - ".github/workflows/main.yml"
62
136
  - ".gitignore"
63
137
  - ".rspec"
64
- - ".travis.yml"
65
138
  - CODE_OF_CONDUCT.md
66
139
  - Gemfile
67
140
  - Gemfile.lock
@@ -71,6 +144,11 @@ files:
71
144
  - bin/console
72
145
  - bin/setup
73
146
  - bin/talknote
147
+ - examples/complete_csv_export_example.rb
148
+ - examples/dm_csv_export_example.rb
149
+ - examples/dm_example.rb
150
+ - examples/group_csv_export_example.rb
151
+ - examples/group_example.rb
74
152
  - lib/talknote.rb
75
153
  - lib/talknote/cli.rb
76
154
  - lib/talknote/client.rb
@@ -83,7 +161,6 @@ metadata:
83
161
  homepage_uri: https://github.com/geeknees/talknote_rb
84
162
  source_code_uri: https://github.com/geeknees/talknote_rb
85
163
  changelog_uri: https://github.com/geeknees/talknote_rb
86
- post_install_message:
87
164
  rdoc_options: []
88
165
  require_paths:
89
166
  - lib
@@ -98,8 +175,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
98
175
  - !ruby/object:Gem::Version
99
176
  version: '0'
100
177
  requirements: []
101
- rubygems_version: 3.1.4
102
- signing_key:
178
+ rubygems_version: 3.6.7
103
179
  specification_version: 4
104
180
  summary: Talknote API Client.
105
181
  test_files: []
data/.travis.yml DELETED
@@ -1,6 +0,0 @@
1
- ---
2
- language: ruby
3
- cache: bundler
4
- rvm:
5
- - 2.7.1
6
- before_install: gem install bundler -v 2.1.4