Repository navigation
Add TeamAPI and resource classes for team-level management #10
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
335b718
6fc67b8
21b53bd
ad2e937
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| { | ||
| "codeReview": { | ||
| "enabled": true, | ||
| "autoReview": true, | ||
| "reviewStyle": "concise" | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,72 +1,7 @@ | ||
| # frozen_string_literal: true | ||
|
|
||
| module Lettermint | ||
| class Client | ||
| attr_reader :configuration | ||
|
|
||
| def initialize(api_token:, base_url: nil, timeout: nil) | ||
| validate_api_token!(api_token) | ||
|
|
||
| @configuration = Configuration.new | ||
| @configuration.base_url = base_url || Lettermint.configuration.base_url | ||
| @configuration.timeout = timeout || Lettermint.configuration.timeout | ||
|
|
||
| yield @configuration if block_given? | ||
|
|
||
| @http_client = HttpClient.new( | ||
| api_token: api_token, | ||
| base_url: @configuration.base_url, | ||
| timeout: @configuration.timeout | ||
| ) | ||
| end | ||
|
|
||
| def email | ||
| EmailMessage.new(http_client: @http_client) | ||
| end | ||
|
|
||
| # Makes a GET request to an arbitrary API endpoint. | ||
| # | ||
| # @param path [String] The API endpoint path (e.g., '/domains') | ||
| # @param params [Hash, nil] Query parameters to include in the request | ||
| # @param headers [Hash, nil] Additional HTTP headers | ||
| # @return [Hash] The parsed JSON response body | ||
| def get(path, params: nil, headers: nil) | ||
| @http_client.get(path: path, params: params, headers: headers) | ||
| end | ||
|
|
||
| # Makes a POST request to an arbitrary API endpoint. | ||
| # | ||
| # @param path [String] The API endpoint path | ||
| # @param data [Hash, nil] The request body (will be JSON-encoded) | ||
| # @param headers [Hash, nil] Additional HTTP headers | ||
| # @return [Hash] The parsed JSON response body | ||
| def post(path, data: nil, headers: nil) | ||
| @http_client.post(path: path, data: data, headers: headers) | ||
| end | ||
|
|
||
| # Makes a PUT request to an arbitrary API endpoint. | ||
| # | ||
| # @param path [String] The API endpoint path | ||
| # @param data [Hash, nil] The request body (will be JSON-encoded) | ||
| # @param headers [Hash, nil] Additional HTTP headers | ||
| # @return [Hash] The parsed JSON response body | ||
| def put(path, data: nil, headers: nil) | ||
| @http_client.put(path: path, data: data, headers: headers) | ||
| end | ||
|
|
||
| # Makes a DELETE request to an arbitrary API endpoint. | ||
| # | ||
| # @param path [String] The API endpoint path | ||
| # @param headers [Hash, nil] Additional HTTP headers | ||
| # @return [Hash] The parsed JSON response body | ||
| def delete(path, headers: nil) | ||
| @http_client.delete(path: path, headers: headers) | ||
| end | ||
|
|
||
| private | ||
|
|
||
| def validate_api_token!(token) | ||
| raise ArgumentError, 'API token cannot be empty' if token.nil? || token.to_s.strip.empty? | ||
| end | ||
| end | ||
| # Backward compatibility: Client is an alias for SendingAPI. | ||
| # Use Lettermint::SendingAPI explicitly for clarity. | ||
| Client = SendingAPI | ||
| end |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,33 @@ | ||
| # frozen_string_literal: true | ||
|
|
||
| module Lettermint | ||
| module Resources | ||
| # Base class for Team API resources providing shared functionality. | ||
| class Base | ||
| def initialize(http_client:) | ||
| @http_client = http_client | ||
| end | ||
|
|
||
| private | ||
|
|
||
| # Builds query parameters for list endpoints. | ||
| # @param page_size [Integer, nil] Number of items per page | ||
| # @param page_cursor [String, nil] Cursor for pagination | ||
| # @param sort [String, nil] Sort field (prefix with - for descending) | ||
| # @param include [String, nil] Related resources to include | ||
| # @param filters [Hash] Filter parameters (converted to filter[key]=value) | ||
| # @return [Hash, nil] Query parameters hash or nil if empty | ||
| def build_params(page_size: nil, page_cursor: nil, sort: nil, include: nil, **filters) | ||
| params = { | ||
| 'page[size]' => page_size, | ||
| 'page[cursor]' => page_cursor, | ||
| 'sort' => sort, | ||
| 'include' => include | ||
| }.compact | ||
|
|
||
| filters.each { |k, v| params["filter[#{k}]"] = v unless v.nil? } | ||
| params.empty? ? nil : params | ||
| end | ||
| end | ||
| end | ||
| end |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,66 @@ | ||
| # frozen_string_literal: true | ||
|
|
||
| module Lettermint | ||
| module Resources | ||
| # Domains resource for managing sending domains and DNS verification. | ||
| class Domains < Base | ||
| # List all domains. | ||
| # @param page_size [Integer, nil] Number of items per page (default: 30) | ||
| # @param page_cursor [String, nil] Cursor for pagination | ||
| # @param sort [String, nil] Sort field: domain, created_at, status_changed_at (prefix - for desc) | ||
| # @param status [String, nil] Filter by status (verified, partially_verified, etc.) | ||
| # @param domain [String, nil] Filter by domain (partial match) | ||
| # @return [Hash] Paginated list of domains | ||
| def list(page_size: nil, page_cursor: nil, sort: nil, status: nil, domain: nil) | ||
| params = build_params(page_size:, page_cursor:, sort:, status:, domain:) | ||
| @http_client.get(path: '/domains', params: params) | ||
| end | ||
|
|
||
| # Create a new domain. | ||
| # @param domain [String] Domain name (max 255 chars) | ||
| # @return [Hash] Created domain data | ||
| def create(domain:) | ||
| @http_client.post(path: '/domains', data: { domain: domain }) | ||
| end | ||
|
|
||
| # Get domain details. | ||
| # @param id [String] Domain ID | ||
| # @param include [String, nil] Related data to include (dnsRecords, dnsRecordsCount, dnsRecordsExists) | ||
| # @return [Hash] Domain data with optional includes | ||
| def find(id, include: nil) | ||
| params = build_params(include: include) | ||
| @http_client.get(path: "/domains/#{id}", params: params) | ||
| end | ||
|
|
||
| # Delete a domain. | ||
| # @param id [String] Domain ID | ||
| # @return [Hash] Confirmation message | ||
| def delete(id) | ||
| @http_client.delete(path: "/domains/#{id}") | ||
| end | ||
|
|
||
| # Verify all DNS records for a domain. | ||
| # @param id [String] Domain ID | ||
| # @return [Hash] Verification result | ||
| def verify_dns(id) | ||
| @http_client.post(path: "/domains/#{id}/dns-records/verify") | ||
| end | ||
|
|
||
| # Verify a specific DNS record. | ||
| # @param domain_id [String] Domain ID | ||
| # @param record_id [String] DNS record ID | ||
| # @return [Hash] Verification result | ||
| def verify_dns_record(domain_id, record_id) | ||
| @http_client.post(path: "/domains/#{domain_id}/dns-records/#{record_id}/verify") | ||
| end | ||
|
|
||
| # Update projects associated with a domain. | ||
| # @param id [String] Domain ID | ||
| # @param project_ids [Array<String>] Array of project UUIDs | ||
| # @return [Hash] Updated domain data | ||
| def update_projects(id, project_ids:) | ||
| @http_client.put(path: "/domains/#{id}/projects", data: { project_ids: project_ids }) | ||
| end | ||
| end | ||
| end | ||
| end |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,81 @@ | ||
| # frozen_string_literal: true | ||
|
|
||
| module Lettermint | ||
| module Resources | ||
| # Messages resource for viewing sent and received messages. | ||
| class Messages < Base | ||
| # List messages. | ||
| # @param page_size [Integer, nil] Number of items per page (default: 30) | ||
| # @param page_cursor [String, nil] Cursor for pagination | ||
| # @param sort [String, nil] Sort field: type, status, from_email, subject, created_at, status_changed_at | ||
| # @param type [String, nil] Filter: inbound, outbound | ||
| # @param status [String, nil] Filter by status | ||
| # @param route_id [String, nil] Filter by route ID | ||
| # @param domain_id [String, nil] Filter by domain ID | ||
| # @param tag [String, nil] Filter by tag | ||
| # @param from_email [String, nil] Filter by sender email | ||
| # @param subject [String, nil] Filter by subject | ||
| # @param from_date [String, nil] Filter from date (Y-m-d) | ||
| # @param to_date [String, nil] Filter to date (Y-m-d) | ||
| # @return [Hash] Paginated list of messages | ||
| # rubocop:disable Metrics/ParameterLists | ||
| def list(page_size: nil, page_cursor: nil, sort: nil, type: nil, status: nil, | ||
| route_id: nil, domain_id: nil, tag: nil, from_email: nil, subject: nil, | ||
| from_date: nil, to_date: nil) | ||
| params = build_params( | ||
| page_size: page_size, | ||
| page_cursor: page_cursor, | ||
| sort: sort, | ||
| type: type, | ||
| status: status, | ||
| route_id: route_id, | ||
| domain_id: domain_id, | ||
| tag: tag, | ||
| from_email: from_email, | ||
| subject: subject, | ||
| from_date: from_date, | ||
| to_date: to_date | ||
| ) | ||
| @http_client.get(path: '/messages', params: params) | ||
| end | ||
|
Comment on lines
+6
to
+40
|
||
| # rubocop:enable Metrics/ParameterLists | ||
|
|
||
| # Get message details. | ||
| # @param id [String] Message ID | ||
| # @return [Hash] Message data | ||
| def find(id) | ||
| @http_client.get(path: "/messages/#{id}") | ||
| end | ||
|
|
||
| # Get message events (delivery history). | ||
| # @param id [String] Message ID | ||
| # @param sort [String, nil] Sort field: timestamp, event | ||
| # @return [Hash] List of message events | ||
| def events(id, sort: nil) | ||
| params = sort ? { 'sort' => sort } : nil | ||
| @http_client.get(path: "/messages/#{id}/events", params: params) | ||
| end | ||
|
|
||
| # Get raw message source (RFC822 format). | ||
| # @param id [String] Message ID | ||
| # @return [String] Raw message source (message/rfc822) | ||
| def source(id) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The def source(id)
@http_client.get(path: "/messages/#{id}/source", headers: { 'Accept' => 'message/rfc822' })
end |
||
| @http_client.get(path: "/messages/#{id}/source", headers: { 'Accept' => 'message/rfc822' }) | ||
| end | ||
|
|
||
| # Get message HTML body. | ||
| # @param id [String] Message ID | ||
| # @return [String] HTML content (text/html) | ||
| def html(id) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
| @http_client.get(path: "/messages/#{id}/html", headers: { 'Accept' => 'text/html' }) | ||
| end | ||
|
|
||
| # Get message plain text body. | ||
| # @param id [String] Message ID | ||
| # @return [String] Plain text content (text/plain) | ||
| def text(id) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
| @http_client.get(path: "/messages/#{id}/text", headers: { 'Accept' => 'text/plain' }) | ||
| end | ||
| end | ||
| end | ||
| end | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The
schemeparameter is compared directly in thecasestatement. To make the client more robust against callers passing strings instead of symbols, it is safer to convert the scheme to a symbol before comparison.