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.
- checksums.yaml +7 -0
- data/LICENSE +21 -0
- data/forem-ruby.gemspec +17 -0
- data/lib/forem/api_operations/create.rb +47 -0
- data/lib/forem/api_operations/delete.rb +88 -0
- data/lib/forem/api_operations/list.rb +70 -0
- data/lib/forem/api_operations/request.rb +83 -0
- data/lib/forem/api_operations/retrieve.rb +43 -0
- data/lib/forem/api_operations/save.rb +53 -0
- data/lib/forem/api_operations/update.rb +47 -0
- data/lib/forem/api_requestor.rb +283 -0
- data/lib/forem/api_resource.rb +77 -0
- data/lib/forem/client.rb +279 -0
- data/lib/forem/configuration.rb +74 -0
- data/lib/forem/connection_manager.rb +75 -0
- data/lib/forem/errors.rb +118 -0
- data/lib/forem/forem_object.rb +264 -0
- data/lib/forem/forem_response.rb +50 -0
- data/lib/forem/list_object.rb +171 -0
- data/lib/forem/resources/admin_concept.rb +169 -0
- data/lib/forem/resources/admin_user.rb +152 -0
- data/lib/forem/resources/agent_session.rb +110 -0
- data/lib/forem/resources/analytics.rb +151 -0
- data/lib/forem/resources/article.rb +256 -0
- data/lib/forem/resources/billboard.rb +76 -0
- data/lib/forem/resources/comment.rb +43 -0
- data/lib/forem/resources/concept.rb +192 -0
- data/lib/forem/resources/follow.rb +78 -0
- data/lib/forem/resources/follower.rb +56 -0
- data/lib/forem/resources/health_check.rb +70 -0
- data/lib/forem/resources/organization.rb +79 -0
- data/lib/forem/resources/page.rb +52 -0
- data/lib/forem/resources/podcast_episode.rb +36 -0
- data/lib/forem/resources/profile_image.rb +44 -0
- data/lib/forem/resources/reaction.rb +61 -0
- data/lib/forem/resources/reading_list.rb +29 -0
- data/lib/forem/resources/recommended_articles_list.rb +45 -0
- data/lib/forem/resources/request_redirect.rb +60 -0
- data/lib/forem/resources/segment.rb +103 -0
- data/lib/forem/resources/survey.rb +96 -0
- data/lib/forem/resources/tag.rb +27 -0
- data/lib/forem/resources/trend.rb +80 -0
- data/lib/forem/resources/user.rb +229 -0
- data/lib/forem/resources/video.rb +28 -0
- data/lib/forem/services/admin_concept_service.rb +138 -0
- data/lib/forem/services/admin_user_service.rb +114 -0
- data/lib/forem/services/agent_session_service.rb +87 -0
- data/lib/forem/services/analytics_service.rb +93 -0
- data/lib/forem/services/article_service.rb +233 -0
- data/lib/forem/services/base_service.rb +45 -0
- data/lib/forem/services/billboard_service.rb +91 -0
- data/lib/forem/services/comment_service.rb +51 -0
- data/lib/forem/services/concept_service.rb +143 -0
- data/lib/forem/services/follow_service.rb +61 -0
- data/lib/forem/services/follower_service.rb +34 -0
- data/lib/forem/services/health_check_service.rb +46 -0
- data/lib/forem/services/organization_service.rb +103 -0
- data/lib/forem/services/page_service.rb +107 -0
- data/lib/forem/services/podcast_episode_service.rb +34 -0
- data/lib/forem/services/profile_image_service.rb +32 -0
- data/lib/forem/services/reaction_service.rb +72 -0
- data/lib/forem/services/reading_list_service.rb +35 -0
- data/lib/forem/services/recommended_articles_list_service.rb +87 -0
- data/lib/forem/services/request_redirect_service.rb +118 -0
- data/lib/forem/services/segment_service.rb +83 -0
- data/lib/forem/services/survey_service.rb +48 -0
- data/lib/forem/services/tag_service.rb +32 -0
- data/lib/forem/services/trend_service.rb +70 -0
- data/lib/forem/services/user_service.rb +61 -0
- data/lib/forem/services/video_service.rb +33 -0
- data/lib/forem/util.rb +43 -0
- data/lib/forem/version.rb +4 -0
- data/lib/forem.rb +91 -0
- metadata +111 -0
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
module Forem
|
|
2
|
+
# Represents an item saved to the authenticated user's reading list.
|
|
3
|
+
#
|
|
4
|
+
# When a user bookmarks an article on Forem, it appears in their reading
|
|
5
|
+
# list. This resource supports listing those saved articles with optional
|
|
6
|
+
# filtering by status.
|
|
7
|
+
#
|
|
8
|
+
# Requires authentication. Returns articles saved to the user's reading
|
|
9
|
+
# list. Default: 30 per page.
|
|
10
|
+
#
|
|
11
|
+
# Available operations (via mixins):
|
|
12
|
+
# - +List+ — GET /api/readinglist
|
|
13
|
+
#
|
|
14
|
+
# @example List all bookmarked articles
|
|
15
|
+
# items = client.reading_list.list
|
|
16
|
+
# items.data.each { |item| puts item.article.title }
|
|
17
|
+
#
|
|
18
|
+
# @example List only confirmed (active) reading list items
|
|
19
|
+
# items = client.reading_list.list(status: "confirmed")
|
|
20
|
+
# items.data.each { |item| puts item.article.title }
|
|
21
|
+
#
|
|
22
|
+
# @see https://developers.forem.com/api/v1#/operations/getReadinglist
|
|
23
|
+
class ReadingList < APIResource
|
|
24
|
+
extend APIOperations::List
|
|
25
|
+
|
|
26
|
+
OBJECT_NAME = "reading_list"
|
|
27
|
+
RESOURCE_PATH = "/api/readinglist"
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
module Forem
|
|
2
|
+
# Represents a curated list of recommended articles on a Forem instance.
|
|
3
|
+
#
|
|
4
|
+
# Curated lists of recommended articles. Used by admins to manage content
|
|
5
|
+
# recommendations.
|
|
6
|
+
#
|
|
7
|
+
# RecommendedArticlesLists are editorial curation objects that group
|
|
8
|
+
# articles for display in recommendation widgets or featured sections.
|
|
9
|
+
# Full CRUD operations are supported. Managing these lists typically
|
|
10
|
+
# requires an admin API key.
|
|
11
|
+
#
|
|
12
|
+
# Available operations (via mixins):
|
|
13
|
+
# - +List+ — GET /api/recommended_articles_lists
|
|
14
|
+
# - +Create+ — POST /api/recommended_articles_lists
|
|
15
|
+
# - +Retrieve+ — GET /api/recommended_articles_lists/:id
|
|
16
|
+
# - +Update+ — PUT /api/recommended_articles_lists/:id
|
|
17
|
+
# - +Save+ — instance-level save (create or update)
|
|
18
|
+
#
|
|
19
|
+
# @example List all recommended article lists
|
|
20
|
+
# lists = client.recommended_articles_lists.list
|
|
21
|
+
# lists.each { |l| puts l.name }
|
|
22
|
+
#
|
|
23
|
+
# @example Create a recommended articles list (flat params)
|
|
24
|
+
# list = client.recommended_articles_lists.create(
|
|
25
|
+
# name: "Top Ruby Articles",
|
|
26
|
+
# article_ids: [101, 202, 303]
|
|
27
|
+
# )
|
|
28
|
+
#
|
|
29
|
+
# @example Retrieve a list by ID and update it
|
|
30
|
+
# list = client.recommended_articles_lists.retrieve(1)
|
|
31
|
+
# list.name = "Updated Name"
|
|
32
|
+
# list.save
|
|
33
|
+
#
|
|
34
|
+
# @see https://developers.forem.com/api/v1
|
|
35
|
+
class RecommendedArticlesList < APIResource
|
|
36
|
+
extend APIOperations::Create
|
|
37
|
+
extend APIOperations::List
|
|
38
|
+
extend APIOperations::Retrieve
|
|
39
|
+
extend APIOperations::Update
|
|
40
|
+
include APIOperations::Save
|
|
41
|
+
|
|
42
|
+
OBJECT_NAME = "recommended_articles_list"
|
|
43
|
+
RESOURCE_PATH = "/api/recommended_articles_lists"
|
|
44
|
+
end
|
|
45
|
+
end
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
module Forem
|
|
2
|
+
# Represents a request redirect used to map legacy or custom-domain paths
|
|
3
|
+
# to a destination URL.
|
|
4
|
+
#
|
|
5
|
+
# Request redirects power organization custom domains: when a request
|
|
6
|
+
# comes in for +request_domain+ at path +original_url+, Forem redirects
|
|
7
|
+
# the visitor to +destination_url+. Managing request redirects is an
|
|
8
|
+
# admin-only operation and requires an admin API key.
|
|
9
|
+
#
|
|
10
|
+
# Available operations (via mixins):
|
|
11
|
+
# - +List+ — GET /api/admin/request_redirects
|
|
12
|
+
# - +Create+ — POST /api/admin/request_redirects
|
|
13
|
+
# - +Retrieve+ — GET /api/admin/request_redirects/:id
|
|
14
|
+
# - +Update+ — PUT /api/admin/request_redirects/:id
|
|
15
|
+
# - +Delete+ — instance-level delete (DELETE /api/admin/request_redirects/:id)
|
|
16
|
+
# - +Save+ — instance-level save (create or update)
|
|
17
|
+
#
|
|
18
|
+
# == RequestRedirect Fields
|
|
19
|
+
#
|
|
20
|
+
# - +original_url+ (String, required) — the incoming request path; must
|
|
21
|
+
# start with +/+ and is unique per +request_domain+
|
|
22
|
+
# - +destination_url+ (String, required) — the fully-qualified HTTP/HTTPS
|
|
23
|
+
# URL to redirect to
|
|
24
|
+
# - +request_domain+ (String, required) — the domain the redirect applies
|
|
25
|
+
# to; normalized to lowercase by the server
|
|
26
|
+
#
|
|
27
|
+
# The create/update endpoints require request bodies wrapped in a
|
|
28
|
+
# +request_redirect:+ key (the API uses strong parameters with
|
|
29
|
+
# +params.require(:request_redirect)+), so callers of the class methods
|
|
30
|
+
# here must supply that wrapper explicitly. {Forem::Services::RequestRedirectService}
|
|
31
|
+
# handles the wrapping automatically for the friendlier, flat-params
|
|
32
|
+
# service interface.
|
|
33
|
+
#
|
|
34
|
+
# @example List all request redirects
|
|
35
|
+
# redirects = client.request_redirects.list
|
|
36
|
+
# redirects.each { |r| puts "#{r.request_domain}#{r.original_url} -> #{r.destination_url}" }
|
|
37
|
+
#
|
|
38
|
+
# @example Create a request redirect (params must be wrapped in +request_redirect:+)
|
|
39
|
+
# redirect = Forem::RequestRedirect.create(
|
|
40
|
+
# { request_redirect: { original_url: "/old", destination_url: "https://example.com/new", request_domain: "example.com" } },
|
|
41
|
+
# requestor: client.requestor
|
|
42
|
+
# )
|
|
43
|
+
#
|
|
44
|
+
# @example Retrieve a request redirect by ID
|
|
45
|
+
# redirect = client.request_redirects.retrieve(7)
|
|
46
|
+
# puts redirect.destination_url
|
|
47
|
+
#
|
|
48
|
+
# @see https://developers.forem.com/api/v1
|
|
49
|
+
class RequestRedirect < APIResource
|
|
50
|
+
extend APIOperations::Create
|
|
51
|
+
extend APIOperations::List
|
|
52
|
+
extend APIOperations::Retrieve
|
|
53
|
+
extend APIOperations::Update
|
|
54
|
+
include APIOperations::Delete
|
|
55
|
+
include APIOperations::Save
|
|
56
|
+
|
|
57
|
+
OBJECT_NAME = "request_redirect"
|
|
58
|
+
RESOURCE_PATH = "/api/admin/request_redirects"
|
|
59
|
+
end
|
|
60
|
+
end
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
module Forem
|
|
2
|
+
# Represents a user segment used for targeted content delivery on Forem.
|
|
3
|
+
#
|
|
4
|
+
# Audience segments for billboard targeting. The API only permits managing
|
|
5
|
+
# segments you create yourself.
|
|
6
|
+
#
|
|
7
|
+
# Segments are named groups of users that can be targeted with specific
|
|
8
|
+
# billboards or other content. Admins can create and delete segments, list
|
|
9
|
+
# their members, and add or remove users from them. Managing segments
|
|
10
|
+
# requires an admin API key.
|
|
11
|
+
#
|
|
12
|
+
# Available operations (via mixins):
|
|
13
|
+
# - +List+ — GET /api/segments (getSegments)
|
|
14
|
+
# - +Create+ — POST /api/segments (createSegment)
|
|
15
|
+
# - +Retrieve+ — GET /api/segments/:id
|
|
16
|
+
# - +Delete+ — instance-level delete (DELETE /api/segments/:id)
|
|
17
|
+
#
|
|
18
|
+
# == Segment Fields
|
|
19
|
+
#
|
|
20
|
+
# - +id+ (Integer) — The segment ID
|
|
21
|
+
# - +type_of+ (String) — Marks segment as manually managed
|
|
22
|
+
# - +user_count+ (Integer) — Current number of users in the segment
|
|
23
|
+
#
|
|
24
|
+
# @example List all segments
|
|
25
|
+
# segments = client.segments.list
|
|
26
|
+
# segments.each { |s| puts s.id }
|
|
27
|
+
#
|
|
28
|
+
# @example Create a segment (no params accepted — the API ignores anything passed)
|
|
29
|
+
# segment = client.segments.create
|
|
30
|
+
# #=> #<Forem::Segment id=14 type_of="manual">
|
|
31
|
+
#
|
|
32
|
+
# @example List users in a segment
|
|
33
|
+
# segment = client.segments.retrieve(5)
|
|
34
|
+
# segment.users.auto_paging_each { |u| puts u.username }
|
|
35
|
+
#
|
|
36
|
+
# @see https://developers.forem.com/api/v1
|
|
37
|
+
class Segment < APIResource
|
|
38
|
+
extend APIOperations::Create
|
|
39
|
+
extend APIOperations::List
|
|
40
|
+
extend APIOperations::Retrieve
|
|
41
|
+
include APIOperations::Delete
|
|
42
|
+
|
|
43
|
+
OBJECT_NAME = "segment"
|
|
44
|
+
RESOURCE_PATH = "/api/segments"
|
|
45
|
+
|
|
46
|
+
# Return the users who belong to this segment.
|
|
47
|
+
#
|
|
48
|
+
# Returns users in this segment. Default: 30 per page, max: 1000.
|
|
49
|
+
#
|
|
50
|
+
# Sends a GET request to +/api/segments/:id/users+ (getUsersInSegment).
|
|
51
|
+
#
|
|
52
|
+
# @param params [Hash] query parameters
|
|
53
|
+
# @option params [Integer] :page page number (default: 1)
|
|
54
|
+
# @option params [Integer] :per_page number of results per page (default: 30, max: 1000)
|
|
55
|
+
# @param opts [Hash] per-request options (e.g., +:api_key+)
|
|
56
|
+
# @return [Forem::ListObject<Forem::User>] paginated list of users
|
|
57
|
+
# belonging to this segment.
|
|
58
|
+
# @example
|
|
59
|
+
# segment = client.segments.retrieve(5)
|
|
60
|
+
# segment.users.auto_paging_each { |u| puts u.username }
|
|
61
|
+
# @see https://developers.forem.com/api/v1
|
|
62
|
+
def users(params = {}, opts = {})
|
|
63
|
+
opts = opts.dup
|
|
64
|
+
opts[:requestor] ||= @requestor
|
|
65
|
+
Forem::User.paginated_list("#{resource_url}/users", params, opts)
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# Add one or more users to this segment.
|
|
69
|
+
#
|
|
70
|
+
# Add users in bulk. The response distinguishes successes (added) from
|
|
71
|
+
# failures (couldn't add).
|
|
72
|
+
#
|
|
73
|
+
# Sends a PUT request to +/api/segments/:id/add_users+ (addUsersToSegment).
|
|
74
|
+
#
|
|
75
|
+
# @param params [Hash] request body
|
|
76
|
+
# @option params [Array<Integer>] :user_ids list of user IDs to add
|
|
77
|
+
# @param opts [Hash] per-request options (e.g., +:api_key+)
|
|
78
|
+
# @return [ForemResponse] the raw API response
|
|
79
|
+
# @example
|
|
80
|
+
# segment = client.segments.retrieve(5)
|
|
81
|
+
# segment.add_users(user_ids: [101, 102, 103])
|
|
82
|
+
# @see https://developers.forem.com/api/v1
|
|
83
|
+
def add_users(params = {}, opts = {})
|
|
84
|
+
request(:put, "#{resource_url}/add_users", params, opts)
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
# Remove one or more users from this segment.
|
|
88
|
+
#
|
|
89
|
+
# Sends a PUT request to +/api/segments/:id/remove_users+.
|
|
90
|
+
#
|
|
91
|
+
# @param params [Hash] request body
|
|
92
|
+
# @option params [Array<Integer>] :user_ids list of user IDs to remove
|
|
93
|
+
# @param opts [Hash] per-request options (e.g., +:api_key+)
|
|
94
|
+
# @return [ForemResponse] the raw API response
|
|
95
|
+
# @example
|
|
96
|
+
# segment = client.segments.retrieve(5)
|
|
97
|
+
# segment.remove_users(user_ids: [101, 102])
|
|
98
|
+
# @see https://developers.forem.com/api/v1
|
|
99
|
+
def remove_users(params = {}, opts = {})
|
|
100
|
+
request(:put, "#{resource_url}/remove_users", params, opts)
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
end
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
module Forem
|
|
2
|
+
# Represents a survey published on a Forem instance.
|
|
3
|
+
#
|
|
4
|
+
# Surveys are structured questionnaires that can be presented to community
|
|
5
|
+
# members. They can be listed or retrieved individually. Survey responses
|
|
6
|
+
# are exposed through two endpoints — {#poll_votes} for multiple-choice
|
|
7
|
+
# poll selections and {#poll_text_responses} for free-text answers.
|
|
8
|
+
#
|
|
9
|
+
# The +/api/surveys/{id}/responses+ endpoint that earlier versions of
|
|
10
|
+
# this gem hit no longer exists in the Forem API; it was replaced by
|
|
11
|
+
# those two cursor-paginated endpoints.
|
|
12
|
+
#
|
|
13
|
+
# Available operations (via mixins):
|
|
14
|
+
# - +List+ — GET /api/surveys
|
|
15
|
+
# - +Retrieve+ — GET /api/surveys/:id_or_slug (getSurveyByIdOrSlug)
|
|
16
|
+
#
|
|
17
|
+
# == Survey Fields
|
|
18
|
+
#
|
|
19
|
+
# - +id+ (Integer)
|
|
20
|
+
# - +title+ (String)
|
|
21
|
+
# - +slug+ (String)
|
|
22
|
+
# - +survey_type_of+ (String) — Survey category
|
|
23
|
+
# - +active+ (Boolean) — Whether the survey is currently active
|
|
24
|
+
#
|
|
25
|
+
# == Authentication
|
|
26
|
+
#
|
|
27
|
+
# All survey endpoints require an admin API key.
|
|
28
|
+
#
|
|
29
|
+
# @example List active surveys
|
|
30
|
+
# surveys = client.surveys.list(active: true)
|
|
31
|
+
# surveys.each { |s| puts s.title }
|
|
32
|
+
#
|
|
33
|
+
# @example Retrieve a specific survey by id or slug
|
|
34
|
+
# survey = client.surveys.retrieve(3)
|
|
35
|
+
# survey = client.surveys.retrieve("my-survey-slug")
|
|
36
|
+
#
|
|
37
|
+
# @example Iterate every poll vote across all pages
|
|
38
|
+
# survey = client.surveys.retrieve(3)
|
|
39
|
+
# survey.poll_votes.auto_paging_each { |v| puts v.poll_option_id }
|
|
40
|
+
#
|
|
41
|
+
# @see https://developers.forem.com/api/v1
|
|
42
|
+
class Survey < APIResource
|
|
43
|
+
extend APIOperations::List
|
|
44
|
+
extend APIOperations::Retrieve
|
|
45
|
+
|
|
46
|
+
OBJECT_NAME = "survey"
|
|
47
|
+
RESOURCE_PATH = "/api/surveys"
|
|
48
|
+
|
|
49
|
+
# Return the multiple-choice poll selections recorded for this survey.
|
|
50
|
+
#
|
|
51
|
+
# Sends a GET request to +/api/surveys/:id_or_slug/poll_votes+.
|
|
52
|
+
# Pagination is cursor-based — pass the last seen vote id as +:after+
|
|
53
|
+
# (or use {Forem::ListObject#auto_paging_each}, which threads the
|
|
54
|
+
# cursor automatically).
|
|
55
|
+
#
|
|
56
|
+
# @param params [Hash] query parameters
|
|
57
|
+
# @option params [Integer] :after return only votes with id strictly
|
|
58
|
+
# greater than this value (cursor)
|
|
59
|
+
# @option params [Integer] :per_page page size (default 30)
|
|
60
|
+
# @param opts [Hash] per-request options
|
|
61
|
+
# @return [Forem::ListObject<Forem::ForemObject>] cursor-paginated list
|
|
62
|
+
# of poll-vote objects.
|
|
63
|
+
# @example
|
|
64
|
+
# survey = client.surveys.retrieve(3)
|
|
65
|
+
# survey.poll_votes.auto_paging_each { |v| puts v.id }
|
|
66
|
+
# @see https://developers.forem.com/api/v1
|
|
67
|
+
def poll_votes(params = {}, opts = {})
|
|
68
|
+
opts = opts.dup
|
|
69
|
+
opts[:requestor] ||= @requestor
|
|
70
|
+
Forem::ForemObject.cursor_list("#{resource_url}/poll_votes", params, opts)
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# Return the free-text answers recorded for this survey.
|
|
74
|
+
#
|
|
75
|
+
# Sends a GET request to +/api/surveys/:id_or_slug/poll_text_responses+.
|
|
76
|
+
# Cursor-paginated by +:after+ on the last seen response id; see
|
|
77
|
+
# {#poll_votes} for paging details.
|
|
78
|
+
#
|
|
79
|
+
# @param params [Hash] query parameters
|
|
80
|
+
# @option params [Integer] :after return only responses with id
|
|
81
|
+
# strictly greater than this value (cursor)
|
|
82
|
+
# @option params [Integer] :per_page page size (default 30)
|
|
83
|
+
# @param opts [Hash] per-request options
|
|
84
|
+
# @return [Forem::ListObject<Forem::ForemObject>] cursor-paginated list
|
|
85
|
+
# of poll text-response objects.
|
|
86
|
+
# @example
|
|
87
|
+
# survey = client.surveys.retrieve(3)
|
|
88
|
+
# survey.poll_text_responses.each { |r| puts r.text_content }
|
|
89
|
+
# @see https://developers.forem.com/api/v1
|
|
90
|
+
def poll_text_responses(params = {}, opts = {})
|
|
91
|
+
opts = opts.dup
|
|
92
|
+
opts[:requestor] ||= @requestor
|
|
93
|
+
Forem::ForemObject.cursor_list("#{resource_url}/poll_text_responses", params, opts)
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
module Forem
|
|
2
|
+
# Represents a Forem tag used to categorize articles.
|
|
3
|
+
#
|
|
4
|
+
# Tags are keywords attached to articles that help readers discover related
|
|
5
|
+
# content. Only listing is supported through the public API; tags are created
|
|
6
|
+
# implicitly when articles are published with new tag names.
|
|
7
|
+
#
|
|
8
|
+
# Tags are ordered by popularity. Default: 10 per page.
|
|
9
|
+
#
|
|
10
|
+
# Available operations (via mixins):
|
|
11
|
+
# - +List+ — GET /api/tags
|
|
12
|
+
#
|
|
13
|
+
# @example List tags ordered by popularity
|
|
14
|
+
# tags = client.tags.list(per_page: 50)
|
|
15
|
+
# tags.data.each { |t| puts "#{t.name} (#{t.points} points)" }
|
|
16
|
+
#
|
|
17
|
+
# @example Iterate over every tag using auto-pagination
|
|
18
|
+
# client.tags.list.auto_paging_each { |t| puts t.name }
|
|
19
|
+
#
|
|
20
|
+
# @see https://developers.forem.com/api/v1#/operations/getTags
|
|
21
|
+
class Tag < APIResource
|
|
22
|
+
extend APIOperations::List
|
|
23
|
+
|
|
24
|
+
OBJECT_NAME = "tag"
|
|
25
|
+
RESOURCE_PATH = "/api/tags"
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
module Forem
|
|
2
|
+
# Represents a trend detected across a Forem instance's content.
|
|
3
|
+
#
|
|
4
|
+
# Trends are algorithmically-derived topic clusters ("hot and recent"
|
|
5
|
+
# subject areas) made up of related articles. They are read-only via the
|
|
6
|
+
# public API — there is no create/update/delete surface, only listing,
|
|
7
|
+
# retrieval, and a nested endpoint for the articles that make up a trend.
|
|
8
|
+
#
|
|
9
|
+
# Available operations (via mixins):
|
|
10
|
+
# - +List+ — GET /api/trends
|
|
11
|
+
# - +Retrieve+ — GET /api/trends/:id_or_slug
|
|
12
|
+
#
|
|
13
|
+
# == Trend Fields
|
|
14
|
+
#
|
|
15
|
+
# - +id+ (Integer)
|
|
16
|
+
# - +name+ (String)
|
|
17
|
+
# - +slug+ (String)
|
|
18
|
+
# - +description+ (String)
|
|
19
|
+
# - +key_questions+ (Array<String>) — Questions the trend's content clusters around
|
|
20
|
+
# - +score+ (Float) — Relative trend strength/ranking score
|
|
21
|
+
# - +articles_count+ (Integer) — Number of articles associated with the trend
|
|
22
|
+
# - +cover_image+ (String) — URL of the trend's cover image
|
|
23
|
+
# - +first_observed_at+ (String) — ISO 8601 timestamp
|
|
24
|
+
# - +last_observed_at+ (String) — ISO 8601 timestamp
|
|
25
|
+
# - +created_at+ (String) — ISO 8601 timestamp
|
|
26
|
+
# - +updated_at+ (String) — ISO 8601 timestamp
|
|
27
|
+
# - +type_of+ (String) — Always +"trend"+
|
|
28
|
+
#
|
|
29
|
+
# The +show+ response additionally includes +top_articles+, an array of up
|
|
30
|
+
# to three of the trend's highest-scoring published articles, each with
|
|
31
|
+
# +id+, +title+, +slug+, +score+, and +published_at+.
|
|
32
|
+
#
|
|
33
|
+
# @example List hot and recent trends
|
|
34
|
+
# trends = client.trends.list(per_page: 10)
|
|
35
|
+
# trends.data.each { |t| puts "#{t.name} (#{t.score})" }
|
|
36
|
+
#
|
|
37
|
+
# @example Retrieve a trend by ID or slug
|
|
38
|
+
# trend = client.trends.retrieve("ai-agents")
|
|
39
|
+
# puts trend.description
|
|
40
|
+
# trend.top_articles.each { |a| puts a["title"] }
|
|
41
|
+
#
|
|
42
|
+
# @example List the articles that make up a trend
|
|
43
|
+
# articles = client.trends.articles("ai-agents", per_page: 20, sort: "score")
|
|
44
|
+
# articles.each { |a| puts a.title }
|
|
45
|
+
#
|
|
46
|
+
# @see https://developers.forem.com/api/v1
|
|
47
|
+
class Trend < APIResource
|
|
48
|
+
extend APIOperations::List
|
|
49
|
+
extend APIOperations::Retrieve
|
|
50
|
+
|
|
51
|
+
OBJECT_NAME = "trend"
|
|
52
|
+
RESOURCE_PATH = "/api/trends"
|
|
53
|
+
|
|
54
|
+
# Return the articles belonging to a trend.
|
|
55
|
+
#
|
|
56
|
+
# Sends a GET request to +/api/trends/:id_or_slug/articles+. Unlike
|
|
57
|
+
# {.list} and {.retrieve}, this is a class method that takes the trend's
|
|
58
|
+
# ID or slug directly, so it can be called without first retrieving the
|
|
59
|
+
# trend itself.
|
|
60
|
+
#
|
|
61
|
+
# @param id_or_slug [Integer, String] the trend's numeric ID or slug
|
|
62
|
+
# @param params [Hash] query parameters
|
|
63
|
+
# @option params [Integer] :page page number (default: 1)
|
|
64
|
+
# @option params [Integer] :per_page number of results per page (default: 10)
|
|
65
|
+
# @option params [String] :sort +"score"+ to sort purely by article score;
|
|
66
|
+
# omit for the default ordering (trend membership distance, then score)
|
|
67
|
+
# @param opts [Hash] per-request options
|
|
68
|
+
# @option opts [String] :api_key override the API key for this request.
|
|
69
|
+
# @option opts [APIRequestor] :requestor a custom requestor to use.
|
|
70
|
+
# @return [Array<Forem::Article>] articles associated with the trend
|
|
71
|
+
# @example
|
|
72
|
+
# Forem::Trend.articles("ai-agents", per_page: 5, requestor: requestor)
|
|
73
|
+
# @see https://developers.forem.com/api/v1
|
|
74
|
+
def self.articles(id_or_slug, params = {}, opts = {})
|
|
75
|
+
requestor = opts[:requestor]
|
|
76
|
+
resp = request(:get, "#{resource_path}/#{id_or_slug}/articles", params, opts)
|
|
77
|
+
(resp.parsed_body || []).map { |item| Forem::Article.construct_from(item, requestor: requestor) }
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
module Forem
|
|
2
|
+
# Represents a Forem user account.
|
|
3
|
+
#
|
|
4
|
+
# Users can be retrieved by ID or by looking up the currently authenticated
|
|
5
|
+
# user. Admin-level operations (suspend, unsuspend, flag as spam, etc.) are
|
|
6
|
+
# also exposed as instance methods and require an admin API key.
|
|
7
|
+
#
|
|
8
|
+
# Available operations (via mixins):
|
|
9
|
+
# - +Retrieve+ — GET /api/users/:id
|
|
10
|
+
#
|
|
11
|
+
# Note: the +id+ parameter passed to +retrieve+ can be a numeric ID or a
|
|
12
|
+
# username string.
|
|
13
|
+
#
|
|
14
|
+
# @example Retrieve the authenticated user
|
|
15
|
+
# me = client.users.me
|
|
16
|
+
# puts "Hello, #{me.name}!"
|
|
17
|
+
#
|
|
18
|
+
# @example Retrieve a user by ID
|
|
19
|
+
# user = client.users.retrieve(12345)
|
|
20
|
+
# puts user.username
|
|
21
|
+
#
|
|
22
|
+
# @example Look up a user by exact email
|
|
23
|
+
# results = client.users.search(email: "alice@example.com")
|
|
24
|
+
# results.each { |u| puts u.username }
|
|
25
|
+
#
|
|
26
|
+
# @see https://developers.forem.com/api/v1#/operations/getUser
|
|
27
|
+
class User < APIResource
|
|
28
|
+
extend APIOperations::Retrieve
|
|
29
|
+
|
|
30
|
+
OBJECT_NAME = "user"
|
|
31
|
+
RESOURCE_PATH = "/api/users"
|
|
32
|
+
|
|
33
|
+
# Return the currently authenticated user's profile.
|
|
34
|
+
#
|
|
35
|
+
# Returns extended user info including +email+ (if the user allows it
|
|
36
|
+
# on their profile).
|
|
37
|
+
#
|
|
38
|
+
# Sends a GET request to +/api/users/me+.
|
|
39
|
+
#
|
|
40
|
+
# @param opts [Hash] per-request options (e.g., +:api_key+)
|
|
41
|
+
# @return [Forem::User] the authenticated user
|
|
42
|
+
# @example
|
|
43
|
+
# me = client.users.me
|
|
44
|
+
# puts "Logged in as #{me.username}"
|
|
45
|
+
# @see https://developers.forem.com/api/v1#/operations/getUserMe
|
|
46
|
+
def self.me(opts = {})
|
|
47
|
+
requestor = opts[:requestor]
|
|
48
|
+
resp = request(:get, "/api/users/me", {}, opts)
|
|
49
|
+
construct_from(resp.parsed_body, requestor: requestor)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# Look up a single user by exact email address.
|
|
53
|
+
#
|
|
54
|
+
# Sends a GET request to +/api/users/search+. Despite the endpoint
|
|
55
|
+
# name, this is an exact-match email lookup — there is no name- or
|
|
56
|
+
# username-prefix search. The endpoint is V1-only, requires admin
|
|
57
|
+
# privileges, and is not currently documented in the public swagger.
|
|
58
|
+
#
|
|
59
|
+
# @param params [Hash] query parameters
|
|
60
|
+
# @option params [String] :email (required) the email address to look up.
|
|
61
|
+
# @param opts [Hash] per-request options (e.g., +:api_key+)
|
|
62
|
+
# @return [Forem::ListObject<Forem::User>] a list containing the matched
|
|
63
|
+
# user, or an empty list if none matches. The list is wrapped for
|
|
64
|
+
# API consistency with other search-style methods even though the
|
|
65
|
+
# endpoint returns at most one result.
|
|
66
|
+
# @example
|
|
67
|
+
# results = client.users.search(email: "alice@example.com")
|
|
68
|
+
# if (user = results.first)
|
|
69
|
+
# puts user.username
|
|
70
|
+
# end
|
|
71
|
+
# @see https://developers.forem.com/api/v1
|
|
72
|
+
def self.search(params = {}, opts = {})
|
|
73
|
+
requestor = opts[:requestor]
|
|
74
|
+
data = begin
|
|
75
|
+
resp = request(:get, "/api/users/search", params, opts)
|
|
76
|
+
body = resp.parsed_body
|
|
77
|
+
if body.is_a?(Hash) && !body.empty?
|
|
78
|
+
[construct_from(body, requestor: requestor)]
|
|
79
|
+
else
|
|
80
|
+
[]
|
|
81
|
+
end
|
|
82
|
+
rescue NotFoundError
|
|
83
|
+
[]
|
|
84
|
+
end
|
|
85
|
+
ListObject.new(
|
|
86
|
+
data: data,
|
|
87
|
+
per_page: [data.length, 1].max,
|
|
88
|
+
resource_class: self,
|
|
89
|
+
filters: params.reject { |k, _| [:per_page, "per_page"].include?(k) },
|
|
90
|
+
requestor: requestor,
|
|
91
|
+
fetcher: ->(*) { nil }
|
|
92
|
+
)
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
# Unpublish all articles and comments authored by this user.
|
|
96
|
+
#
|
|
97
|
+
# Unpublishes all articles by this user.
|
|
98
|
+
#
|
|
99
|
+
# Sends a PUT request to +/api/users/:id/unpublish+. Requires admin privileges.
|
|
100
|
+
#
|
|
101
|
+
# @param opts [Hash] per-request options (e.g., +:api_key+)
|
|
102
|
+
# @return [ForemResponse] the raw API response
|
|
103
|
+
# @example
|
|
104
|
+
# user = client.users.retrieve(42)
|
|
105
|
+
# user.unpublish
|
|
106
|
+
# @see https://developers.forem.com/api/v1#/operations/unpublishUser
|
|
107
|
+
def unpublish(opts = {})
|
|
108
|
+
request(:put, "#{resource_url}/unpublish", {}, opts)
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
# Suspend this user, preventing them from logging in or posting.
|
|
112
|
+
#
|
|
113
|
+
# Prevents new posts and comments but does not delete existing content.
|
|
114
|
+
# The user is not notified in the UI.
|
|
115
|
+
#
|
|
116
|
+
# Sends a PUT request to +/api/users/:id/suspend+. Requires admin privileges.
|
|
117
|
+
#
|
|
118
|
+
# @param opts [Hash] per-request options (e.g., +:api_key+)
|
|
119
|
+
# @return [ForemResponse] the raw API response
|
|
120
|
+
# @example
|
|
121
|
+
# user = client.users.retrieve(42)
|
|
122
|
+
# user.suspend
|
|
123
|
+
# @see https://developers.forem.com/api/v1#/operations/suspendUser
|
|
124
|
+
def suspend(opts = {})
|
|
125
|
+
request(:put, "#{resource_url}/suspend", {}, opts)
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
# Remove the suspension from this user, restoring their access.
|
|
129
|
+
#
|
|
130
|
+
# Sends a DELETE request to +/api/users/:id/suspend+. Requires admin privileges.
|
|
131
|
+
#
|
|
132
|
+
# @param opts [Hash] per-request options (e.g., +:api_key+)
|
|
133
|
+
# @return [ForemResponse] the raw API response
|
|
134
|
+
# @example
|
|
135
|
+
# user = client.users.retrieve(42)
|
|
136
|
+
# user.unsuspend
|
|
137
|
+
# @see https://developers.forem.com/api/v1#/operations/suspendUser
|
|
138
|
+
def unsuspend(opts = {})
|
|
139
|
+
request(:delete, "#{resource_url}/suspend", {}, opts)
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
# Apply the "limited" role to this user, restricting their posting ability.
|
|
143
|
+
#
|
|
144
|
+
# Sends a PUT request to +/api/users/:id/limited+. Requires admin privileges.
|
|
145
|
+
#
|
|
146
|
+
# @param opts [Hash] per-request options (e.g., +:api_key+)
|
|
147
|
+
# @return [ForemResponse] the raw API response
|
|
148
|
+
# @example
|
|
149
|
+
# user = client.users.retrieve(42)
|
|
150
|
+
# user.add_limited
|
|
151
|
+
# @see https://developers.forem.com/api/v1
|
|
152
|
+
def add_limited(opts = {})
|
|
153
|
+
request(:put, "#{resource_url}/limited", {}, opts)
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
# Remove the "limited" role from this user.
|
|
157
|
+
#
|
|
158
|
+
# Sends a DELETE request to +/api/users/:id/limited+. Requires admin privileges.
|
|
159
|
+
#
|
|
160
|
+
# @param opts [Hash] per-request options (e.g., +:api_key+)
|
|
161
|
+
# @return [ForemResponse] the raw API response
|
|
162
|
+
# @example
|
|
163
|
+
# user = client.users.retrieve(42)
|
|
164
|
+
# user.remove_limited
|
|
165
|
+
# @see https://developers.forem.com/api/v1
|
|
166
|
+
def remove_limited(opts = {})
|
|
167
|
+
request(:delete, "#{resource_url}/limited", {}, opts)
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
# Flag this user as a spam account.
|
|
171
|
+
#
|
|
172
|
+
# Prevents new posts and comments but does not delete existing content.
|
|
173
|
+
# The user is not notified in the UI.
|
|
174
|
+
#
|
|
175
|
+
# Sends a PUT request to +/api/users/:id/spam+. Requires admin privileges.
|
|
176
|
+
#
|
|
177
|
+
# @param opts [Hash] per-request options (e.g., +:api_key+)
|
|
178
|
+
# @return [ForemResponse] the raw API response
|
|
179
|
+
# @example
|
|
180
|
+
# user = client.users.retrieve(42)
|
|
181
|
+
# user.add_spam
|
|
182
|
+
# @see https://developers.forem.com/api/v1#/operations/spamUser
|
|
183
|
+
def add_spam(opts = {})
|
|
184
|
+
request(:put, "#{resource_url}/spam", {}, opts)
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
# Remove the spam flag from this user.
|
|
188
|
+
#
|
|
189
|
+
# Sends a DELETE request to +/api/users/:id/spam+. Requires admin privileges.
|
|
190
|
+
#
|
|
191
|
+
# @param opts [Hash] per-request options (e.g., +:api_key+)
|
|
192
|
+
# @return [ForemResponse] the raw API response
|
|
193
|
+
# @example
|
|
194
|
+
# user = client.users.retrieve(42)
|
|
195
|
+
# user.remove_spam
|
|
196
|
+
# @see https://developers.forem.com/api/v1#/operations/spamUser
|
|
197
|
+
def remove_spam(opts = {})
|
|
198
|
+
request(:delete, "#{resource_url}/spam", {}, opts)
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
# Grant the "trusted" role to this user, giving them elevated moderation privileges.
|
|
202
|
+
#
|
|
203
|
+
# Sends a PUT request to +/api/users/:id/trusted+. Requires admin privileges.
|
|
204
|
+
#
|
|
205
|
+
# @param opts [Hash] per-request options (e.g., +:api_key+)
|
|
206
|
+
# @return [ForemResponse] the raw API response
|
|
207
|
+
# @example
|
|
208
|
+
# user = client.users.retrieve(42)
|
|
209
|
+
# user.add_trusted
|
|
210
|
+
# @see https://developers.forem.com/api/v1
|
|
211
|
+
def add_trusted(opts = {})
|
|
212
|
+
request(:put, "#{resource_url}/trusted", {}, opts)
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
# Remove the "trusted" role from this user.
|
|
216
|
+
#
|
|
217
|
+
# Sends a DELETE request to +/api/users/:id/trusted+. Requires admin privileges.
|
|
218
|
+
#
|
|
219
|
+
# @param opts [Hash] per-request options (e.g., +:api_key+)
|
|
220
|
+
# @return [ForemResponse] the raw API response
|
|
221
|
+
# @example
|
|
222
|
+
# user = client.users.retrieve(42)
|
|
223
|
+
# user.remove_trusted
|
|
224
|
+
# @see https://developers.forem.com/api/v1
|
|
225
|
+
def remove_trusted(opts = {})
|
|
226
|
+
request(:delete, "#{resource_url}/trusted", {}, opts)
|
|
227
|
+
end
|
|
228
|
+
end
|
|
229
|
+
end
|