chefu_academy 0.1.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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 56cf1309b2b9aec7c93d650ea719bd128fdfee851bfb765ba2ccef9956819f3f
4
+ data.tar.gz: 05053aba56bc1c0ff0bf957d3df4c559622306efbda75429acf7a1c874391881
5
+ SHA512:
6
+ metadata.gz: 6794e73aa2e4217d8a77d66d0c8a2388c1d62bbc0e747b80f95380e66bf6550ac3becc6a8903cba632a1a78c1eea5adf8312b6b6b631f8ab660b6f1186d98551
7
+ data.tar.gz: ea113d018beb72e2ff917feb90ed4223ea8fce0b039e1ad06cc9e635066b49889aa330ad31bd3665942398bd4216820b0510c350b231b3cd2c7aa1ee0d0a0d3f
data/README.md ADDED
@@ -0,0 +1,16 @@
1
+ # CheFu Academy Ruby Client
2
+
3
+ Official Ruby gem source for the CheFu Academy API.
4
+
5
+ ## Usage
6
+
7
+ ```ruby
8
+ client = CheFuAcademy::Client.new(api_key: 'chf_publicId_secret')
9
+ courses = client.list_courses(limit: 5)
10
+ ```
11
+
12
+ ## Local Install
13
+
14
+ ```bash
15
+ bundle install
16
+ ```
@@ -0,0 +1,169 @@
1
+ require 'json'
2
+ require 'net/http'
3
+ require 'uri'
4
+
5
+ module CheFuAcademy
6
+ DEFAULT_BASE_URL = 'https://api.chefuinc.com/api'
7
+
8
+ class Error < StandardError
9
+ attr_reader :status_code, :details
10
+
11
+ def initialize(message, status_code: nil, details: nil)
12
+ super(message)
13
+ @status_code = status_code
14
+ @details = details
15
+ end
16
+ end
17
+
18
+ class Client
19
+ attr_accessor :api_key, :auth_token
20
+
21
+ def initialize(api_key: nil, auth_token: nil, base_url: DEFAULT_BASE_URL, timeout: 10)
22
+ @api_key = api_key
23
+ @auth_token = auth_token
24
+ @base_url = base_url.delete_suffix('/')
25
+ @timeout = timeout
26
+ end
27
+
28
+ def login(email:, password:)
29
+ session = request('POST', '/auth/login', body: { email: email, password: password }, api_key_auth: false)
30
+ self.auth_token = session['idToken'] || session['token']
31
+ session
32
+ end
33
+
34
+ def register(email:, password:, fullname:)
35
+ request('POST', '/auth/register', body: { email: email, password: password, fullname: fullname }, api_key_auth: false)
36
+ end
37
+
38
+ def refresh(refresh_token:)
39
+ session = request('POST', '/auth/refresh', body: { refreshToken: refresh_token }, api_key_auth: false)
40
+ self.auth_token = session['idToken'] || session['token']
41
+ session
42
+ end
43
+
44
+ def list_courses(**query)
45
+ request('GET', '/courses', query: query)
46
+ end
47
+
48
+ def search_courses(**query)
49
+ request('GET', '/courses/search', query: query)
50
+ end
51
+
52
+ def featured_courses(**query)
53
+ request('GET', '/courses/featured', query: query)
54
+ end
55
+
56
+ def course_categories
57
+ request('GET', '/courses/categories')
58
+ end
59
+
60
+ def course(course_id)
61
+ request('GET', "/courses/#{escape(course_id)}")
62
+ end
63
+
64
+ def course_chapters(course_id)
65
+ request('GET', "/courses/#{escape(course_id)}/chapters")
66
+ end
67
+
68
+ def course_chapter(course_id, chapter_index)
69
+ request('GET', "/courses/#{escape(course_id)}/chapters/#{chapter_index}")
70
+ end
71
+
72
+ def course_lessons(course_id, chapter_index)
73
+ request('GET', "/courses/#{escape(course_id)}/chapters/#{chapter_index}/lessons")
74
+ end
75
+
76
+ def course_quiz(course_id)
77
+ request('GET', "/courses/#{escape(course_id)}/quiz")
78
+ end
79
+
80
+ def course_flashcards(course_id)
81
+ request('GET', "/courses/#{escape(course_id)}/flashcards")
82
+ end
83
+
84
+ def course_qa(course_id)
85
+ request('GET', "/courses/#{escape(course_id)}/qa")
86
+ end
87
+
88
+ def list_videos(**query)
89
+ request('GET', '/videos', query: query)
90
+ end
91
+
92
+ def search_videos(**query)
93
+ request('GET', '/videos/search', query: query)
94
+ end
95
+
96
+ def videos_by_category(category)
97
+ request('GET', "/videos/category/#{escape(category)}")
98
+ end
99
+
100
+ def video(video_id)
101
+ request('GET', "/videos/#{escape(video_id)}")
102
+ end
103
+
104
+ def create_key(name: nil)
105
+ request('POST', '/keys/create', body: { name: name }, user_auth: true, api_key_auth: false)
106
+ end
107
+
108
+ def list_keys
109
+ request('GET', '/keys/list', user_auth: true, api_key_auth: false)
110
+ end
111
+
112
+ def revoke_key(key_id)
113
+ request('POST', '/keys/revoke', body: { keyId: key_id }, user_auth: true, api_key_auth: false)
114
+ end
115
+
116
+ private
117
+
118
+ def request(method, path, query: {}, body: nil, user_auth: false, api_key_auth: true)
119
+ token = user_auth ? auth_token : api_key
120
+ raise Error.new('User authentication is required.', status_code: 401) if user_auth && blank?(token)
121
+ raise Error.new('API key is required.', status_code: 401) if api_key_auth && !user_auth && blank?(token)
122
+
123
+ uri = URI("#{@base_url}#{path}")
124
+ clean_query = query.reject { |_key, value| value.nil? || value.to_s.empty? }
125
+ uri.query = URI.encode_www_form(clean_query) unless clean_query.empty?
126
+
127
+ request = Net::HTTP.const_get(method.capitalize).new(uri)
128
+ request['Accept'] = 'application/json'
129
+ request['Authorization'] = "Bearer #{token}" unless blank?(token)
130
+ if body
131
+ request['Content-Type'] = 'application/json'
132
+ request.body = JSON.generate(body)
133
+ end
134
+
135
+ response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == 'https', read_timeout: @timeout) do |http|
136
+ http.request(request)
137
+ end
138
+
139
+ decoded = response.body.nil? || response.body.empty? ? nil : JSON.parse(response.body)
140
+ unless response.is_a?(Net::HTTPSuccess)
141
+ raise Error.new(error_message(decoded, response.body), status_code: response.code.to_i, details: decoded)
142
+ end
143
+
144
+ decoded
145
+ rescue JSON::ParserError => error
146
+ raise Error.new("JSON parse error: #{error.message}")
147
+ end
148
+
149
+ def escape(value)
150
+ URI.encode_www_form_component(value.to_s).gsub('+', '%20')
151
+ end
152
+
153
+ def blank?(value)
154
+ value.nil? || value.to_s.empty?
155
+ end
156
+
157
+ def error_message(decoded, raw)
158
+ if decoded.is_a?(Hash)
159
+ message = decoded['message']
160
+ return message.join(' ') if message.is_a?(Array)
161
+ return message if message.is_a?(String) && !message.empty?
162
+ error = decoded['error']
163
+ return error if error.is_a?(String) && !error.empty?
164
+ end
165
+
166
+ raw.nil? || raw.empty? ? 'CheFu Academy request failed.' : raw
167
+ end
168
+ end
169
+ end
@@ -0,0 +1,4 @@
1
+ require_relative 'chefu_academy/client'
2
+
3
+ module CheFuAcademy
4
+ end
metadata ADDED
@@ -0,0 +1,47 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: chefu_academy
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - CheFu Inc
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2026-06-03 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description:
14
+ email:
15
+ executables: []
16
+ extensions: []
17
+ extra_rdoc_files: []
18
+ files:
19
+ - README.md
20
+ - lib/chefu_academy.rb
21
+ - lib/chefu_academy/client.rb
22
+ homepage: https://github.com/CheFu-code/CheFu-Academy-SDK
23
+ licenses:
24
+ - MIT
25
+ metadata:
26
+ homepage_uri: https://github.com/CheFu-code/CheFu-Academy-SDK
27
+ source_code_uri: https://github.com/CheFu-code/CheFu-Academy-SDK/tree/main/clients/ruby
28
+ post_install_message:
29
+ rdoc_options: []
30
+ require_paths:
31
+ - lib
32
+ required_ruby_version: !ruby/object:Gem::Requirement
33
+ requirements:
34
+ - - ">="
35
+ - !ruby/object:Gem::Version
36
+ version: '3.0'
37
+ required_rubygems_version: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - ">="
40
+ - !ruby/object:Gem::Version
41
+ version: '0'
42
+ requirements: []
43
+ rubygems_version: 3.5.22
44
+ signing_key:
45
+ specification_version: 4
46
+ summary: Official Ruby client for the CheFu Academy API
47
+ test_files: []