forem-ruby 0.1.0.beta1

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.
Files changed (74) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +21 -0
  3. data/forem-ruby.gemspec +17 -0
  4. data/lib/forem/api_operations/create.rb +47 -0
  5. data/lib/forem/api_operations/delete.rb +88 -0
  6. data/lib/forem/api_operations/list.rb +70 -0
  7. data/lib/forem/api_operations/request.rb +83 -0
  8. data/lib/forem/api_operations/retrieve.rb +43 -0
  9. data/lib/forem/api_operations/save.rb +53 -0
  10. data/lib/forem/api_operations/update.rb +47 -0
  11. data/lib/forem/api_requestor.rb +283 -0
  12. data/lib/forem/api_resource.rb +77 -0
  13. data/lib/forem/client.rb +279 -0
  14. data/lib/forem/configuration.rb +74 -0
  15. data/lib/forem/connection_manager.rb +75 -0
  16. data/lib/forem/errors.rb +118 -0
  17. data/lib/forem/forem_object.rb +264 -0
  18. data/lib/forem/forem_response.rb +50 -0
  19. data/lib/forem/list_object.rb +171 -0
  20. data/lib/forem/resources/admin_concept.rb +169 -0
  21. data/lib/forem/resources/admin_user.rb +152 -0
  22. data/lib/forem/resources/agent_session.rb +110 -0
  23. data/lib/forem/resources/analytics.rb +151 -0
  24. data/lib/forem/resources/article.rb +256 -0
  25. data/lib/forem/resources/billboard.rb +76 -0
  26. data/lib/forem/resources/comment.rb +43 -0
  27. data/lib/forem/resources/concept.rb +192 -0
  28. data/lib/forem/resources/follow.rb +78 -0
  29. data/lib/forem/resources/follower.rb +56 -0
  30. data/lib/forem/resources/health_check.rb +70 -0
  31. data/lib/forem/resources/organization.rb +79 -0
  32. data/lib/forem/resources/page.rb +52 -0
  33. data/lib/forem/resources/podcast_episode.rb +36 -0
  34. data/lib/forem/resources/profile_image.rb +44 -0
  35. data/lib/forem/resources/reaction.rb +61 -0
  36. data/lib/forem/resources/reading_list.rb +29 -0
  37. data/lib/forem/resources/recommended_articles_list.rb +45 -0
  38. data/lib/forem/resources/request_redirect.rb +60 -0
  39. data/lib/forem/resources/segment.rb +103 -0
  40. data/lib/forem/resources/survey.rb +96 -0
  41. data/lib/forem/resources/tag.rb +27 -0
  42. data/lib/forem/resources/trend.rb +80 -0
  43. data/lib/forem/resources/user.rb +229 -0
  44. data/lib/forem/resources/video.rb +28 -0
  45. data/lib/forem/services/admin_concept_service.rb +138 -0
  46. data/lib/forem/services/admin_user_service.rb +114 -0
  47. data/lib/forem/services/agent_session_service.rb +87 -0
  48. data/lib/forem/services/analytics_service.rb +93 -0
  49. data/lib/forem/services/article_service.rb +233 -0
  50. data/lib/forem/services/base_service.rb +45 -0
  51. data/lib/forem/services/billboard_service.rb +91 -0
  52. data/lib/forem/services/comment_service.rb +51 -0
  53. data/lib/forem/services/concept_service.rb +143 -0
  54. data/lib/forem/services/follow_service.rb +61 -0
  55. data/lib/forem/services/follower_service.rb +34 -0
  56. data/lib/forem/services/health_check_service.rb +46 -0
  57. data/lib/forem/services/organization_service.rb +103 -0
  58. data/lib/forem/services/page_service.rb +107 -0
  59. data/lib/forem/services/podcast_episode_service.rb +34 -0
  60. data/lib/forem/services/profile_image_service.rb +32 -0
  61. data/lib/forem/services/reaction_service.rb +72 -0
  62. data/lib/forem/services/reading_list_service.rb +35 -0
  63. data/lib/forem/services/recommended_articles_list_service.rb +87 -0
  64. data/lib/forem/services/request_redirect_service.rb +118 -0
  65. data/lib/forem/services/segment_service.rb +83 -0
  66. data/lib/forem/services/survey_service.rb +48 -0
  67. data/lib/forem/services/tag_service.rb +32 -0
  68. data/lib/forem/services/trend_service.rb +70 -0
  69. data/lib/forem/services/user_service.rb +61 -0
  70. data/lib/forem/services/video_service.rb +33 -0
  71. data/lib/forem/util.rb +43 -0
  72. data/lib/forem/version.rb +4 -0
  73. data/lib/forem.rb +91 -0
  74. metadata +111 -0
@@ -0,0 +1,28 @@
1
+ module Forem
2
+ # Represents an article with an associated video on a Forem instance.
3
+ #
4
+ # Video articles are a special content type where the primary content is a
5
+ # video rather than text. The public API supports listing video articles,
6
+ # returned ordered by publication date.
7
+ #
8
+ # Returns published articles with video, ordered by descending popularity.
9
+ # Default: 24 per page.
10
+ #
11
+ # Available operations (via mixins):
12
+ # - +List+ — GET /api/videos
13
+ #
14
+ # @example List video articles
15
+ # videos = client.videos.list(per_page: 10)
16
+ # videos.data.each { |v| puts v.title }
17
+ #
18
+ # @example Iterate over all video articles using auto-pagination
19
+ # client.videos.list.auto_paging_each { |v| puts "#{v.title}: #{v.video_source_url}" }
20
+ #
21
+ # @see https://developers.forem.com/api/v1#/operations/videos
22
+ class Video < APIResource
23
+ extend APIOperations::List
24
+
25
+ OBJECT_NAME = "video"
26
+ RESOURCE_PATH = "/api/videos"
27
+ end
28
+ end
@@ -0,0 +1,138 @@
1
+ module Forem
2
+ module Services
3
+ # Service for interacting with the Forem Admin Concepts API.
4
+ #
5
+ # Provides full CRUD over concepts — the curated topics Forem uses to
6
+ # classify articles and comments — plus the +trigger_lookback+ action that
7
+ # re-runs classification over older content. Every endpoint requires an API
8
+ # key with super admin privileges; regular user keys receive HTTP 401.
9
+ #
10
+ # Access via {Client#admin_concepts}. All methods inject the client's
11
+ # requestor automatically so no additional configuration is required.
12
+ #
13
+ # @example
14
+ # client = Forem::Client.new("admin-api-key")
15
+ # concept = client.admin_concepts.create(name: "Machine Learning")
16
+ # client.admin_concepts.trigger_lookback(concept.id, days: 90)
17
+ #
18
+ # @see AdminConcept
19
+ # @see Forem::Concept
20
+ # @see https://developers.forem.com/api/v1
21
+ class AdminConceptService < BaseService
22
+ # List concepts, ordered by name.
23
+ #
24
+ # Returns a trimmed projection of each concept: +id+, +name+, +slug+,
25
+ # +description+, +parent_id+, +similarity_threshold+,
26
+ # +max_lookback_days+, +created_at+, and +updated_at+.
27
+ #
28
+ # @param params [Hash] query parameters
29
+ # @option params [Integer] :page page number (default: 1)
30
+ # @option params [Integer] :per_page results per page (default: 50, max: 100)
31
+ # @param opts [Hash] per-request options
32
+ # @return [ListObject] the current page of {AdminConcept} records
33
+ #
34
+ # @example
35
+ # client.admin_concepts.list(per_page: 100)
36
+ def list(params = {}, opts = {})
37
+ AdminConcept.list(params, opts_with_requestor(opts))
38
+ end
39
+
40
+ # Retrieve a single concept by ID.
41
+ #
42
+ # Returns the full concept record, unlike {#list} which returns a
43
+ # trimmed projection.
44
+ #
45
+ # @param id [Integer, String] the concept ID
46
+ # @param opts [Hash] per-request options
47
+ # @return [AdminConcept] the requested concept
48
+ # @raise [NotFoundError] if no concept has that ID
49
+ #
50
+ # @example
51
+ # client.admin_concepts.retrieve(7)
52
+ def retrieve(id, opts = {})
53
+ AdminConcept.retrieve(id, opts_with_requestor(opts))
54
+ end
55
+
56
+ # Create a new concept.
57
+ #
58
+ # Attributes are sent wrapped in a +concept+ object for you. The API
59
+ # generates the slug, and generates a description and the anchor
60
+ # embedding from +name+, so only +name+ is required.
61
+ #
62
+ # @param params [Hash] concept attributes
63
+ # @option params [String] :name the concept name, max 100 chars (required)
64
+ # @option params [String] :description human-readable description
65
+ # @option params [Integer] :parent_id ID of the parent concept
66
+ # @option params [Float] :similarity_threshold classification cutoff (0.0–1.0)
67
+ # @option params [Float] :score ranking score for the concept
68
+ # @param opts [Hash] per-request options
69
+ # @return [AdminConcept] the newly created concept
70
+ # @raise [InvalidRequestError] on HTTP 422 (validation errors)
71
+ #
72
+ # @example
73
+ # client.admin_concepts.create(
74
+ # name: "Machine Learning",
75
+ # description: "Posts about ML and AI",
76
+ # similarity_threshold: 0.8
77
+ # )
78
+ def create(params = {}, opts = {})
79
+ AdminConcept.create(params, opts_with_requestor(opts))
80
+ end
81
+
82
+ # Update an existing concept.
83
+ #
84
+ # Attributes are sent wrapped in a +concept+ object for you. Only
85
+ # +name+, +description+, +parent_id+, +similarity_threshold+, and
86
+ # +score+ are writable; +slug+ and +max_lookback_days+ are ignored.
87
+ # Changing +name+ or +description+ regenerates the anchor embedding.
88
+ #
89
+ # @param id [Integer, String] the concept ID
90
+ # @param params [Hash] attributes to change (see {#create})
91
+ # @param opts [Hash] per-request options
92
+ # @return [AdminConcept] the updated concept
93
+ # @raise [NotFoundError] if no concept has that ID
94
+ # @raise [InvalidRequestError] on HTTP 422 (validation errors)
95
+ #
96
+ # @example
97
+ # client.admin_concepts.update(7, similarity_threshold: 0.9)
98
+ def update(id, params = {}, opts = {})
99
+ AdminConcept.update(id, params, opts_with_requestor(opts))
100
+ end
101
+
102
+ # Delete a concept.
103
+ #
104
+ # The API responds with HTTP 204 and no body on success.
105
+ #
106
+ # @param id [Integer, String] the concept ID
107
+ # @param opts [Hash] per-request options
108
+ # @return [AdminConcept, nil] +nil+ for the usual empty response
109
+ # @raise [NotFoundError] if no concept has that ID
110
+ #
111
+ # @example
112
+ # client.admin_concepts.delete(7)
113
+ def delete(id, opts = {})
114
+ AdminConcept.delete(id, opts_with_requestor(opts))
115
+ end
116
+
117
+ # Queue a classification lookback for a concept.
118
+ #
119
+ # Enqueues a background job that classifies records from the last
120
+ # +days+ days. The value must be positive and strictly greater than the
121
+ # concept's current +max_lookback_days+, otherwise the API responds with
122
+ # HTTP 422.
123
+ #
124
+ # @param id [Integer, String] the concept ID
125
+ # @param params [Hash] request body
126
+ # @option params [Integer] :days how many days back to classify (required)
127
+ # @param opts [Hash] per-request options
128
+ # @return [ForemObject] an object carrying a +message+
129
+ # @raise [InvalidRequestError] on HTTP 422 when +days+ is out of range
130
+ #
131
+ # @example
132
+ # client.admin_concepts.trigger_lookback(7, days: 90).message
133
+ def trigger_lookback(id, params = {}, opts = {})
134
+ AdminConcept.trigger_lookback(id, params, opts_with_requestor(opts))
135
+ end
136
+ end
137
+ end
138
+ end
@@ -0,0 +1,114 @@
1
+ module Forem
2
+ module Services
3
+ # Service for interacting with the Forem Admin Users API.
4
+ #
5
+ # Provides administrative operations on user accounts. These endpoints
6
+ # require an API key with admin-level privileges.
7
+ # Access via {Client#admin_users}. All methods inject the client's
8
+ # requestor automatically so no additional configuration is required.
9
+ #
10
+ # @example
11
+ # client = Forem::Client.new("admin-api-key")
12
+ # user = client.admin_users.create(
13
+ # email: "newuser@example.com",
14
+ # name: "New User"
15
+ # )
16
+ #
17
+ # @see AdminUser
18
+ # @see https://developers.forem.com/api/v1#/operations/postAdminUsersCreate
19
+ class AdminUserService < BaseService
20
+ # Invite a new user to the Forem instance.
21
+ #
22
+ # Creates a user account and sends them an invitation email.
23
+ # Requires admin privileges.
24
+ #
25
+ # @param params [Hash] user attributes
26
+ # @option params [String] :email the new user's email address (required)
27
+ # @option params [String] :name display name for the new user
28
+ # @option params [String] :username desired username (generated if omitted)
29
+ # @param opts [Hash] per-request options
30
+ # @return [AdminUser] the newly created user record
31
+ #
32
+ # @example
33
+ # client.admin_users.create(
34
+ # email: "jane@example.com",
35
+ # name: "Jane Doe"
36
+ # )
37
+ #
38
+ # @see https://developers.forem.com/api/v1#/operations/postAdminUsersCreate
39
+ def create(params = {}, opts = {})
40
+ AdminUser.create(params, opts_with_requestor(opts))
41
+ end
42
+
43
+ # Link an external identity to a user.
44
+ #
45
+ # @param user_id [Integer, String] the Forem user ID.
46
+ # @param provider [String] the identity provider name.
47
+ # @param uid [String] the provider's stable user identifier.
48
+ # @param opts [Hash] per-request options.
49
+ # @return [ForemObject] the linked identity.
50
+ def link_identity(user_id, provider:, uid:, **opts)
51
+ AdminUser.link_identity(
52
+ user_id,
53
+ provider: provider,
54
+ uid: uid,
55
+ **opts_with_requestor(opts)
56
+ )
57
+ end
58
+
59
+ # Submit multiple external identity links in one request.
60
+ #
61
+ # @param provider [String] the identity provider shared by the identities.
62
+ # @param identities [Array<Hash>] identity hashes containing +user_id+ and
63
+ # +uid+.
64
+ # @param opts [Hash] per-request options.
65
+ # @return [Array<ForemObject>] per-item results containing +user_id+,
66
+ # +status+, and an +error_code+ when that item fails.
67
+ def bulk_link_identities(provider:, identities:, **opts)
68
+ AdminUser.bulk_link_identities(
69
+ provider: provider,
70
+ identities: identities,
71
+ **opts_with_requestor(opts)
72
+ )
73
+ end
74
+
75
+ # List a user's linked external identities.
76
+ #
77
+ # @param user_id [Integer, String] the Forem user ID.
78
+ # @param opts [Hash] per-request options.
79
+ # @return [Array<ForemObject>] the user's linked identities.
80
+ def identities(user_id, **opts)
81
+ AdminUser.identities(user_id, **opts_with_requestor(opts))
82
+ end
83
+
84
+ # Unlink an external identity from a user.
85
+ #
86
+ # @param user_id [Integer, String] the Forem user ID.
87
+ # @param identity_id [Integer, String] the linked identity ID.
88
+ # @param opts [Hash] per-request options.
89
+ # @return [ForemObject, nil] the unlinked identity, or +nil+ for an empty
90
+ # response.
91
+ def unlink_identity(user_id, identity_id, **opts)
92
+ AdminUser.unlink_identity(
93
+ user_id,
94
+ identity_id,
95
+ **opts_with_requestor(opts)
96
+ )
97
+ end
98
+
99
+ # Update the email newsletter notification setting for a user.
100
+ #
101
+ # @param user_id [Integer, String] the Forem user ID.
102
+ # @param email_newsletter [Boolean] whether newsletter email is enabled.
103
+ # @param opts [Hash] per-request options.
104
+ # @return [ForemObject] the updated notification setting.
105
+ def update_notification_settings(user_id, email_newsletter:, **opts)
106
+ AdminUser.update_notification_settings(
107
+ user_id,
108
+ email_newsletter: email_newsletter,
109
+ **opts_with_requestor(opts)
110
+ )
111
+ end
112
+ end
113
+ end
114
+ end
@@ -0,0 +1,87 @@
1
+ module Forem
2
+ module Services
3
+ # Service for interacting with the Forem Agent Sessions API.
4
+ #
5
+ # Agent sessions enable automated or AI-driven interactions with the Forem
6
+ # platform. The presign endpoint provides a pre-signed URL for uploading
7
+ # assets associated with a session.
8
+ # Access via {Client#agent_sessions}. All methods inject the client's
9
+ # requestor automatically so no additional configuration is required.
10
+ #
11
+ # @example
12
+ # client = Forem::Client.new("your-api-key")
13
+ # sessions = client.agent_sessions.list
14
+ # session = client.agent_sessions.create(name: "My Agent")
15
+ #
16
+ # @see AgentSession
17
+ # @see https://developers.forem.com/api/v1#/operations/getAgentSessions
18
+ class AgentSessionService < BaseService
19
+ # List all agent sessions.
20
+ #
21
+ # @param params [Hash] query parameters
22
+ # @option params [Integer] :page page number (default: 1)
23
+ # @option params [Integer] :per_page number of results per page
24
+ # @param opts [Hash] per-request options
25
+ # @return [Array<AgentSession>] list of agent sessions
26
+ #
27
+ # @example
28
+ # client.agent_sessions.list
29
+ #
30
+ # @see https://developers.forem.com/api/v1#/operations/getAgentSessions
31
+ def list(params = {}, opts = {})
32
+ AgentSession.list(params, opts_with_requestor(opts))
33
+ end
34
+
35
+ # Create a new agent session.
36
+ #
37
+ # @param params [Hash] session attributes
38
+ # @option params [String] :name display name for the session
39
+ # @param opts [Hash] per-request options
40
+ # @return [AgentSession] the newly created agent session
41
+ #
42
+ # @example
43
+ # session = client.agent_sessions.create(name: "Content Generation Bot")
44
+ #
45
+ # @see https://developers.forem.com/api/v1#/operations/createAgentSession
46
+ def create(params = {}, opts = {})
47
+ AgentSession.create(params, opts_with_requestor(opts))
48
+ end
49
+
50
+ # Retrieve a single agent session by its numeric ID.
51
+ #
52
+ # @param id [Integer, String] the session ID
53
+ # @param opts [Hash] per-request options
54
+ # @return [AgentSession] the session with the given ID
55
+ #
56
+ # @example
57
+ # client.agent_sessions.retrieve(14)
58
+ #
59
+ # @see https://developers.forem.com/api/v1#/operations/getAgentSessionById
60
+ def retrieve(id, opts = {})
61
+ AgentSession.retrieve(id, opts_with_requestor(opts))
62
+ end
63
+
64
+ # Obtain a pre-signed URL for uploading a file associated with an agent
65
+ # session.
66
+ #
67
+ # @param params [Hash] presign request parameters
68
+ # @option params [String] :filename name of the file to upload
69
+ # @option params [String] :mime_type MIME type of the file
70
+ # @param opts [Hash] per-request options
71
+ # @return [AgentSession] object containing the pre-signed upload URL and
72
+ # related metadata
73
+ #
74
+ # @example
75
+ # presign_data = client.agent_sessions.presign(
76
+ # filename: "image.png",
77
+ # mime_type: "image/png"
78
+ # )
79
+ # puts presign_data.upload_url
80
+ #
81
+ # @see https://developers.forem.com/api/v1
82
+ def presign(params = {}, opts = {})
83
+ AgentSession.presign(params, opts_with_requestor(opts))
84
+ end
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,93 @@
1
+ module Forem
2
+ module Services
3
+ # Service for interacting with the Forem Analytics API.
4
+ #
5
+ # Provides engagement and traffic data for articles and organizations.
6
+ # Access via {Client#analytics}. All methods inject the client's requestor
7
+ # automatically so no additional configuration is required.
8
+ #
9
+ # @example
10
+ # client = Forem::Client.new("your-api-key")
11
+ # totals = client.analytics.totals(username: "jsmith")
12
+ # daily = client.analytics.historical(username: "jsmith", start: "2024-01-01")
13
+ #
14
+ # @see Analytics
15
+ # @see https://developers.forem.com/api/v1
16
+ class AnalyticsService < BaseService
17
+ # Retrieve total engagement metrics for a user or organization.
18
+ #
19
+ # Returns all-time totals for page views, reactions, comments, and
20
+ # follows.
21
+ #
22
+ # @param params [Hash] query parameters
23
+ # @option params [String] :username filter metrics by author username
24
+ # @option params [String] :organization_id filter metrics by organization
25
+ # ID
26
+ # @param opts [Hash] per-request options
27
+ # @return [Analytics] total engagement metrics
28
+ #
29
+ # @example
30
+ # client.analytics.totals(username: "jsmith")
31
+ #
32
+ # @see https://developers.forem.com/api/v1
33
+ def totals(params = {}, opts = {})
34
+ Analytics.totals(params, opts_with_requestor(opts))
35
+ end
36
+
37
+ # Retrieve historical engagement metrics broken down by day.
38
+ #
39
+ # @param params [Hash] query parameters
40
+ # @option params [String] :username filter by author username
41
+ # @option params [String] :organization_id filter by organization ID
42
+ # @option params [String] :start start date in ISO 8601 format
43
+ # (e.g. "2024-01-01")
44
+ # @option params [String] :end end date in ISO 8601 format
45
+ # @param opts [Hash] per-request options
46
+ # @return [Array<Analytics>] daily breakdown of engagement metrics
47
+ #
48
+ # @example
49
+ # client.analytics.historical(
50
+ # username: "jsmith",
51
+ # start: "2024-01-01",
52
+ # end: "2024-03-31"
53
+ # )
54
+ #
55
+ # @see https://developers.forem.com/api/v1
56
+ def historical(params = {}, opts = {})
57
+ Analytics.historical(params, opts_with_requestor(opts))
58
+ end
59
+
60
+ # Retrieve engagement metrics for the past 24 hours.
61
+ #
62
+ # @param params [Hash] query parameters
63
+ # @option params [String] :username filter by author username
64
+ # @option params [String] :organization_id filter by organization ID
65
+ # @param opts [Hash] per-request options
66
+ # @return [Analytics] metrics for the past day
67
+ #
68
+ # @example
69
+ # client.analytics.past_day(username: "jsmith")
70
+ #
71
+ # @see https://developers.forem.com/api/v1
72
+ def past_day(params = {}, opts = {})
73
+ Analytics.past_day(params, opts_with_requestor(opts))
74
+ end
75
+
76
+ # Retrieve referrer traffic data for a user or organization's content.
77
+ #
78
+ # @param params [Hash] query parameters
79
+ # @option params [String] :username filter by author username
80
+ # @option params [String] :organization_id filter by organization ID
81
+ # @param opts [Hash] per-request options
82
+ # @return [Array<Analytics>] referrer breakdown showing traffic sources
83
+ #
84
+ # @example
85
+ # client.analytics.referrers(username: "jsmith")
86
+ #
87
+ # @see https://developers.forem.com/api/v1
88
+ def referrers(params = {}, opts = {})
89
+ Analytics.referrers(params, opts_with_requestor(opts))
90
+ end
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,233 @@
1
+ module Forem
2
+ module Services
3
+ # Service for interacting with the Forem Articles API.
4
+ #
5
+ # Access via {Client#articles}. All methods inject the client's requestor
6
+ # automatically so no additional configuration is required.
7
+ #
8
+ # @example
9
+ # client = Forem::Client.new("your-api-key")
10
+ # service = client.articles
11
+ # service.list(per_page: 5, tag: "ruby")
12
+ #
13
+ # @see Article
14
+ # @see https://developers.forem.com/api/v1#/operations/getArticles
15
+ class ArticleService < BaseService
16
+ # List published articles.
17
+ #
18
+ # @param params [Hash] query parameters
19
+ # @option params [Integer] :page page number (default: 1)
20
+ # @option params [Integer] :per_page number of results per page (max: 1000)
21
+ # @option params [String] :tag filter by a single tag name
22
+ # @option params [String] :tags comma-separated list of tags to include
23
+ # @option params [String] :tags_exclude comma-separated list of tags to exclude
24
+ # @option params [String] :username filter by author username
25
+ # @option params [String] :state article state ("fresh", "rising", "all")
26
+ # @option params [Integer] :top number of days back to look for top articles
27
+ # @option params [String] :collection_id filter by collection ID
28
+ # @param opts [Hash] per-request options
29
+ # @return [Array<Article>] list of published articles
30
+ #
31
+ # @example
32
+ # client.articles.list(tag: "ruby", per_page: 10)
33
+ #
34
+ # @see https://developers.forem.com/api/v1#/operations/getArticles
35
+ def list(params = {}, opts = {})
36
+ Article.list(params, opts_with_requestor(opts))
37
+ end
38
+
39
+ # Create a new article.
40
+ #
41
+ # @param params [Hash] article attributes
42
+ # @option params [String] :title article title
43
+ # @option params [String] :body_markdown article body in Markdown
44
+ # @option params [Boolean] :published whether to publish immediately
45
+ # @option params [Array<String>] :tags list of tag names
46
+ # @option params [String] :series name of a series to add the article to
47
+ # @option params [String] :canonical_url canonical URL override
48
+ # @option params [String] :description article description / excerpt
49
+ # @param opts [Hash] per-request options
50
+ # @return [Article] the newly created article
51
+ #
52
+ # @example
53
+ # client.articles.create(
54
+ # title: "Hello World",
55
+ # body_markdown: "# Hello\nThis is my first post.",
56
+ # published: true,
57
+ # tags: ["ruby", "beginners"]
58
+ # )
59
+ #
60
+ # @see https://developers.forem.com/api/v1#/operations/createArticle
61
+ def create(params = {}, opts = {})
62
+ Article.create(params, opts_with_requestor(opts))
63
+ end
64
+
65
+ # Retrieve a single article by its numeric ID.
66
+ #
67
+ # @param id [Integer, String] the article ID
68
+ # @param opts [Hash] per-request options
69
+ # @return [Article] the article with the given ID
70
+ #
71
+ # @example
72
+ # client.articles.retrieve(12345)
73
+ #
74
+ # @see https://developers.forem.com/api/v1#/operations/getArticleById
75
+ def retrieve(id, opts = {})
76
+ Article.retrieve(id, opts_with_requestor(opts))
77
+ end
78
+
79
+ # Update an existing article.
80
+ #
81
+ # @param id [Integer, String] the article ID to update
82
+ # @param params [Hash] article attributes to change
83
+ # @option params [String] :title new title
84
+ # @option params [String] :body_markdown new body in Markdown
85
+ # @option params [Boolean] :published publish or unpublish the article
86
+ # @option params [Array<String>] :tags updated list of tag names
87
+ # @param opts [Hash] per-request options
88
+ # @return [Article] the updated article
89
+ #
90
+ # @example
91
+ # client.articles.update(12345, title: "Updated Title", published: true)
92
+ #
93
+ # @see https://developers.forem.com/api/v1#/operations/updateArticle
94
+ def update(id, params = {}, opts = {})
95
+ Article.update(id, params, opts_with_requestor(opts))
96
+ end
97
+
98
+ # List articles authored by the authenticated user.
99
+ #
100
+ # @param params [Hash] query parameters
101
+ # @option params [Integer] :page page number (default: 1)
102
+ # @option params [Integer] :per_page number of results per page (max: 1000)
103
+ # @param opts [Hash] per-request options
104
+ # @return [Array<Article>] articles belonging to the current user
105
+ #
106
+ # @example
107
+ # client.articles.me(per_page: 30)
108
+ #
109
+ # @see https://developers.forem.com/api/v1#/operations/getUserArticles
110
+ def me(params = {}, opts = {})
111
+ Article.me(params, opts_with_requestor(opts))
112
+ end
113
+
114
+ # List published articles authored by the authenticated user.
115
+ #
116
+ # @param params [Hash] query parameters
117
+ # @option params [Integer] :page page number (default: 1)
118
+ # @option params [Integer] :per_page number of results per page (max: 1000)
119
+ # @param opts [Hash] per-request options
120
+ # @return [Array<Article>] published articles belonging to the current user
121
+ #
122
+ # @example
123
+ # client.articles.me_published
124
+ #
125
+ # @see https://developers.forem.com/api/v1#/operations/getUserArticles
126
+ def me_published(params = {}, opts = {})
127
+ Article.me_published(params, opts_with_requestor(opts))
128
+ end
129
+
130
+ # List unpublished articles (drafts) authored by the authenticated user.
131
+ #
132
+ # @param params [Hash] query parameters
133
+ # @option params [Integer] :page page number (default: 1)
134
+ # @option params [Integer] :per_page number of results per page (max: 1000)
135
+ # @param opts [Hash] per-request options
136
+ # @return [Array<Article>] unpublished articles belonging to the current user
137
+ #
138
+ # @example
139
+ # client.articles.me_unpublished
140
+ #
141
+ # @see https://developers.forem.com/api/v1#/operations/getUserArticles
142
+ def me_unpublished(params = {}, opts = {})
143
+ Article.me_unpublished(params, opts_with_requestor(opts))
144
+ end
145
+
146
+ # List all articles (published and unpublished) authored by the authenticated user.
147
+ #
148
+ # @param params [Hash] query parameters
149
+ # @option params [Integer] :page page number (default: 1)
150
+ # @option params [Integer] :per_page number of results per page (max: 1000)
151
+ # @param opts [Hash] per-request options
152
+ # @return [Array<Article>] all articles belonging to the current user
153
+ #
154
+ # @example
155
+ # client.articles.me_all
156
+ #
157
+ # @see https://developers.forem.com/api/v1#/operations/getUserArticles
158
+ def me_all(params = {}, opts = {})
159
+ Article.me_all(params, opts_with_requestor(opts))
160
+ end
161
+
162
+ # List the most recently published articles.
163
+ #
164
+ # @param params [Hash] query parameters
165
+ # @option params [Integer] :page page number (default: 1)
166
+ # @option params [Integer] :per_page number of results per page (max: 1000)
167
+ # @param opts [Hash] per-request options
168
+ # @return [Array<Article>] latest published articles in chronological order
169
+ #
170
+ # @example
171
+ # client.articles.latest(per_page: 20)
172
+ #
173
+ # @see https://developers.forem.com/api/v1#/operations/getLatestArticles
174
+ def latest(params = {}, opts = {})
175
+ Article.latest(params, opts_with_requestor(opts))
176
+ end
177
+
178
+ # Search articles by keyword.
179
+ #
180
+ # @param params [Hash] query parameters
181
+ # @option params [String] :q the search term
182
+ # @option params [Integer] :page page number (default: 1)
183
+ # @option params [Integer] :per_page number of results per page
184
+ # @param opts [Hash] per-request options
185
+ # @return [Array<Article>] articles matching the search query
186
+ #
187
+ # @example
188
+ # client.articles.search(q: "ruby on rails")
189
+ #
190
+ # @see https://developers.forem.com/api/v1#/operations/searchArticles
191
+ def search(params = {}, opts = {})
192
+ Article.search(params, opts_with_requestor(opts))
193
+ end
194
+
195
+ # Semantically search articles using Forem's embeddings-based search.
196
+ #
197
+ # Unlike +search+ (keyword matching), this finds articles whose meaning
198
+ # is close to the query text. Requires authentication.
199
+ #
200
+ # @param params [Hash] query parameters
201
+ # @option params [String] :q the search query text (required)
202
+ # @option params [Integer] :page page number (default: 1)
203
+ # @option params [Integer] :per_page number of results per page (default: 10, max: 50)
204
+ # @option params [Float] :threshold optional cosine distance threshold (0.0-2.0)
205
+ # @param opts [Hash] per-request options
206
+ # @return [Array<Article>] articles matching the query, each exposing
207
+ # +distance+ and +similarity+ attributes
208
+ #
209
+ # @example
210
+ # client.articles.semantic_search(q: "how to deploy rails apps")
211
+ #
212
+ # @see https://developers.forem.com/api/v1#/operations/semanticSearchArticles
213
+ def semantic_search(params = {}, opts = {})
214
+ Article.semantic_search(params, opts_with_requestor(opts))
215
+ end
216
+
217
+ # Retrieve an article by its author username and slug.
218
+ #
219
+ # @param username [String] the author's username
220
+ # @param slug [String] the article slug
221
+ # @param opts [Hash] per-request options
222
+ # @return [Article] the matching article
223
+ #
224
+ # @example
225
+ # client.articles.retrieve_by_path("jsmith", "my-great-post")
226
+ #
227
+ # @see https://developers.forem.com/api/v1#/operations/getArticleByPath
228
+ def retrieve_by_path(username, slug, opts = {})
229
+ Article.retrieve_by_path(username, slug, opts_with_requestor(opts))
230
+ end
231
+ end
232
+ end
233
+ end