From 75dc878fd1048179b40060f174a2efec5dfd740b Mon Sep 17 00:00:00 2001 From: Joshua Wehner Date: Thu, 30 Mar 2023 09:36:24 +0200 Subject: [PATCH 01/13] Add exclude_article_ids int array --- ...30320152715_add_exclude_article_ids_to_display_ads.rb | 9 +++++++++ ...52927_add_exclude_article_ids_index_to_display_ads.rb | 7 +++++++ db/schema.rb | 4 +++- 3 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 db/migrate/20230320152715_add_exclude_article_ids_to_display_ads.rb create mode 100644 db/migrate/20230320152927_add_exclude_article_ids_index_to_display_ads.rb diff --git a/db/migrate/20230320152715_add_exclude_article_ids_to_display_ads.rb b/db/migrate/20230320152715_add_exclude_article_ids_to_display_ads.rb new file mode 100644 index 0000000000000..e518c0a0fe487 --- /dev/null +++ b/db/migrate/20230320152715_add_exclude_article_ids_to_display_ads.rb @@ -0,0 +1,9 @@ +class AddExcludeArticleIdsToDisplayAds < ActiveRecord::Migration[7.0] + def up + add_column :display_ads, :exclude_article_ids, :integer, array: true, default: [] + end + + def down + safety_assured { remove_column :display_ads, :exclude_article_ids, :integer, array: true } + end +end diff --git a/db/migrate/20230320152927_add_exclude_article_ids_index_to_display_ads.rb b/db/migrate/20230320152927_add_exclude_article_ids_index_to_display_ads.rb new file mode 100644 index 0000000000000..7f294ea969217 --- /dev/null +++ b/db/migrate/20230320152927_add_exclude_article_ids_index_to_display_ads.rb @@ -0,0 +1,7 @@ +class AddExcludeArticleIdsIndexToDisplayAds < ActiveRecord::Migration[7.0] + disable_ddl_transaction! + + def change + add_index :display_ads, :exclude_article_ids, using: 'gin', algorithm: :concurrently + end +end diff --git a/db/schema.rb b/db/schema.rb index 43f39ff0ee1ee..fdf78a3a14aed 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.0].define(version: 2023_02_16_132930) do +ActiveRecord::Schema[7.0].define(version: 2023_03_20_152927) do # These are extensions that must be enabled in order to support this database enable_extension "citext" enable_extension "pg_stat_statements" @@ -461,6 +461,7 @@ t.datetime "created_at", precision: nil, null: false t.integer "creator_id" t.integer "display_to", default: 0, null: false + t.integer "exclude_article_ids", default: [], array: true t.integer "impressions_count", default: 0 t.string "name" t.bigint "organization_id" @@ -471,6 +472,7 @@ t.integer "type_of", default: 0, null: false t.datetime "updated_at", precision: nil, null: false t.index ["cached_tag_list"], name: "index_display_ads_on_cached_tag_list", opclass: :gin_trgm_ops, using: :gin + t.index ["exclude_article_ids"], name: "index_display_ads_on_exclude_article_ids", using: :gin end create_table "email_authorizations", force: :cascade do |t| From 99ca65c7e00baf781daa9b976b1549585d426889 Mon Sep 17 00:00:00 2001 From: Joshua Wehner Date: Thu, 30 Mar 2023 09:37:34 +0200 Subject: [PATCH 02/13] Add specs, normalize inputs better --- app/models/display_ad.rb | 8 +++++++ spec/models/display_ad_spec.rb | 40 ++++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/app/models/display_ad.rb b/app/models/display_ad.rb index f1e59d1400e0b..e45331cf3f63e 100644 --- a/app/models/display_ad.rb +++ b/app/models/display_ad.rb @@ -84,6 +84,14 @@ def as_json(options = {}) end # rubocop:enable Style/OptionHash + # exclude_article_ids is an integer array, web inputs are comma-separated strings + # ActiveRecord normalizes these in a bad way, so we've intervening + def exclude_article_ids=(input) + adjusted_input = input.is_a?(String) ? input.split(",") : input + adjusted_input = adjusted_input&.filter_map { |value| value.presence&.to_i } + write_attribute :exclude_article_ids, (adjusted_input || []) + end + private def generate_display_ad_name diff --git a/spec/models/display_ad_spec.rb b/spec/models/display_ad_spec.rb index b87108b522ab3..ce4813c7014b5 100644 --- a/spec/models/display_ad_spec.rb +++ b/spec/models/display_ad_spec.rb @@ -152,4 +152,44 @@ expect(display_ad.tag_list).to eq(tags.downcase.split(", ")) end end + + describe "#exclude_articles_ids" do + it "processes array of integer ids as expected" do + display_ad.exclude_article_ids = ["11"] + expect(display_ad.exclude_article_ids).to contain_exactly(11) + + display_ad.exclude_article_ids = %w[11 12 13 14] + expect(display_ad.exclude_article_ids).to contain_exactly(11, 12, 13, 14) + + display_ad.exclude_article_ids = "11,12,13,14" + expect(display_ad.exclude_article_ids).to contain_exactly(11, 12, 13, 14) + + display_ad.exclude_article_ids = "" + expect(display_ad.exclude_article_ids).to eq([]) + + display_ad.exclude_article_ids = [] + expect(display_ad.exclude_article_ids).to eq([]) + + display_ad.exclude_article_ids = ["", "", ""] + expect(display_ad.exclude_article_ids).to eq([]) + + display_ad.exclude_article_ids = [nil] + expect(display_ad.exclude_article_ids).to eq([]) + + display_ad.exclude_article_ids = nil + expect(display_ad.exclude_article_ids).to eq([]) + end + + it "round-trips to the database as expected" do + display_ad.exclude_article_ids = [11] + display_ad.save! + expect(display_ad.exclude_article_ids).to contain_exactly(11) + + display_ad.update(exclude_article_ids: "11,12,13,14") + expect(display_ad.exclude_article_ids).to contain_exactly(11, 12, 13, 14) + + display_ad.update(exclude_article_ids: nil) + expect(display_ad.exclude_article_ids).to eq([]) + end + end end From ef7532b892065c2886f2a88713fc501cd4aa6824 Mon Sep 17 00:00:00 2001 From: Joshua Wehner Date: Thu, 30 Mar 2023 09:38:31 +0200 Subject: [PATCH 03/13] Add to form & controller --- .../admin/display_ads_controller.rb | 2 +- app/javascript/packs/admin/displayAds.jsx | 43 +++++++++++++++++-- app/views/admin/display_ads/_form.html.erb | 5 +++ 3 files changed, 46 insertions(+), 4 deletions(-) diff --git a/app/controllers/admin/display_ads_controller.rb b/app/controllers/admin/display_ads_controller.rb index 750f65c8b51b3..cfd161c91ba46 100644 --- a/app/controllers/admin/display_ads_controller.rb +++ b/app/controllers/admin/display_ads_controller.rb @@ -60,7 +60,7 @@ def destroy def display_ad_params params.permit(:organization_id, :body_markdown, :placement_area, :published, :approved, :name, :display_to, - :tag_list, :type_of) + :tag_list, :type_of, :exclude_article_ids) end def authorize_admin diff --git a/app/javascript/packs/admin/displayAds.jsx b/app/javascript/packs/admin/displayAds.jsx index 6f807d32ba6d7..ec6577bed40f5 100644 --- a/app/javascript/packs/admin/displayAds.jsx +++ b/app/javascript/packs/admin/displayAds.jsx @@ -74,6 +74,38 @@ function defaultTagValues() { return defaultValue; } +/** + * Shows and Renders Exclude Article IDs group + */ +function showExcludeIds() { + const excludeField = document.getElementsByClassName( + 'js-exclude-ids-textfield', + )[0].parentElement; + excludeField?.classList.remove('hidden'); +} + +/** + * Hides the Exclude Article IDs group + */ +function hideExcludeIds() { + const excludeField = document.getElementsByClassName( + 'js-exclude-ids-textfield', + )[0].parentElement; + excludeField?.classList.add('hidden'); +} + +/** + * Clears the content (i.e. value) of the Exclude Article IDs group + */ +function clearExcludeIds() { + const excludeField = document.getElementsByClassName( + 'js-exclude-ids-textfield', + )[0]; + if (excludeField) { + excludeField.value = ''; + } +} + /** * Shows and sets up the Targeted Tag(s) field if the placement area value is "post_comments". * Listens for change events on the select placement area dropdown @@ -81,17 +113,22 @@ function defaultTagValues() { */ document.ready.then(() => { const select = document.getElementsByClassName('js-placement-area')[0]; - const placementAreasWithTags = ['post_comments', 'post_sidebar'] - if (placementAreasWithTags.includes(select.value)) { + const articleSpecificPlacement = ['post_comments', 'post_sidebar']; + if (articleSpecificPlacement.includes(select.value)) { showTagsField(); + showExcludeIds(); } select.addEventListener('change', (event) => { - if (placementAreasWithTags.includes(event.target.value)) { + if (articleSpecificPlacement.includes(event.target.value)) { showTagsField(); + showExcludeIds(); } else { hideTagsField(); clearTagList(); + + hideExcludeIds(); + clearExcludeIds(); } }); }); diff --git a/app/views/admin/display_ads/_form.html.erb b/app/views/admin/display_ads/_form.html.erb index 9c04dc5b5c2d8..2e24c88d2d63d 100644 --- a/app/views/admin/display_ads/_form.html.erb +++ b/app/views/admin/display_ads/_form.html.erb @@ -36,6 +36,11 @@ <%= text_field_tag :tag_list, @display_ad.tag_list.to_s, class: "crayons-textfield js-tags-textfield", autocomplete: "off" %> + +
Display to user group From 14a969f3afaf5a26159c8336f9e81c4e97365118 Mon Sep 17 00:00:00 2001 From: Joshua Wehner Date: Thu, 30 Mar 2023 09:52:29 +0200 Subject: [PATCH 04/13] Add exclude_article_ids to DisplayAd API --- .../api/v1/display_ads_controller.rb | 2 +- app/models/display_ad.rb | 6 +- spec/requests/api/v1/display_ads_spec.rb | 4 +- spec/requests/api/v1/docs/display_ads_spec.rb | 2 + swagger/v1/api_v1.json | 572 +++++++++--------- 5 files changed, 300 insertions(+), 286 deletions(-) diff --git a/app/controllers/api/v1/display_ads_controller.rb b/app/controllers/api/v1/display_ads_controller.rb index 3dd3497c9cf86..04e6dbaf21b02 100644 --- a/app/controllers/api/v1/display_ads_controller.rb +++ b/app/controllers/api/v1/display_ads_controller.rb @@ -52,7 +52,7 @@ def require_admin def permitted_params params.permit :approved, :body_markdown, :creator_id, :display_to, :name, :organization_id, :placement_area, :published, - :tag_list, :type_of + :tag_list, :type_of, :exclude_article_ids end end end diff --git a/app/models/display_ad.rb b/app/models/display_ad.rb index e45331cf3f63e..9251609afbc81 100644 --- a/app/models/display_ad.rb +++ b/app/models/display_ad.rb @@ -80,7 +80,11 @@ def validate_tag # This needs to correspond with Rails built-in method signature # rubocop:disable Style/OptionHash def as_json(options = {}) - super(options.merge(except: %i[tags tag_list])).merge("tag_list" => cached_tag_list) + overrides = { + "tag_list" => cached_tag_list, + "exclude_article_ids" => exclude_article_ids.join(",") + } + super(options.merge(except: %i[tags tag_list])).merge(overrides) end # rubocop:enable Style/OptionHash diff --git a/spec/requests/api/v1/display_ads_spec.rb b/spec/requests/api/v1/display_ads_spec.rb index 3067c1cb08755..fc6cdc997255b 100644 --- a/spec/requests/api/v1/display_ads_spec.rb +++ b/spec/requests/api/v1/display_ads_spec.rb @@ -49,7 +49,7 @@ "impressions_count", "name", "organization_id", "placement_area", "processed_html", "published", "success_rate", "tag_list", "type_of", "updated_at", - "creator_id") + "creator_id", "exclude_article_ids") end it "returns a malformed response" do @@ -95,7 +95,7 @@ "impressions_count", "name", "organization_id", "placement_area", "processed_html", "published", "success_rate", "tag_list", "type_of", "updated_at", - "creator_id") + "creator_id", "exclude_article_ids") end end diff --git a/spec/requests/api/v1/docs/display_ads_spec.rb b/spec/requests/api/v1/docs/display_ads_spec.rb index 602387e80c03c..c601adceaba90 100644 --- a/spec/requests/api/v1/docs/display_ads_spec.rb +++ b/spec/requests/api/v1/docs/display_ads_spec.rb @@ -68,6 +68,8 @@ placement_area: { type: :string, enum: DisplayAd::ALLOWED_PLACEMENT_AREAS, description: "Identifies which area of site layout the ad can appear in" }, tag_list: { type: :string, description: "Tags on which this ad can be displayed (blank is all/any tags)" }, + article_exclude_ids: { type: :string, + description: "Articles this ad should *not* appear (blank is all/any article), comma-separated list of integer Article IDs" }, creator_id: { type: :integer, description: "Identifies the user who created the ad." } }, required: %w[name body_markdown placement_area] diff --git a/swagger/v1/api_v1.json b/swagger/v1/api_v1.json index 2e97be5fa2d44..dc62dfc9e3f4a 100644 --- a/swagger/v1/api_v1.json +++ b/swagger/v1/api_v1.json @@ -24,26 +24,26 @@ "application/json": { "example": { "type_of": "article", - "id": 607, + "id": 490, "title": "New article", "description": "New post example", - "readable_publish_date": "Feb 27", - "slug": "new-article-1j5a", - "path": "/username383/new-article-1j5a", - "url": "http://localhost:3000/username383/new-article-1j5a", + "readable_publish_date": "Mar 30", + "slug": "new-article-2fi7", + "path": "/username383/new-article-2fi7", + "url": "http://localhost:3000/username383/new-article-2fi7", "comments_count": 0, "public_reactions_count": 0, - "collection_id": 16, - "published_timestamp": "2023-02-27T10:58:03Z", + "collection_id": 22, + "published_timestamp": "2023-03-30T07:50:19Z", "positive_reactions_count": 0, "cover_image": "https://thepracticaldev.s3.amazonaws.com/i/5wfo25724gzgk5e5j50g.jpg", "social_image": "https://thepracticaldev.s3.amazonaws.com/i/5wfo25724gzgk5e5j50g.jpg", "canonical_url": "https://dev.to/fdocr/headless-chrome-dual-mode-tests-for-ruby-on-rails-4p6g", - "created_at": "2023-02-27T10:58:03Z", + "created_at": "2023-03-30T07:50:19Z", "edited_at": null, "crossposted_at": null, - "published_at": "2023-02-27T10:58:03Z", - "last_comment_at": "2023-02-27T10:58:03Z", + "published_at": "2023-03-30T07:50:19Z", + "last_comment_at": "2023-03-30T07:50:19Z", "reading_time_minutes": 1, "tag_list": "", "tags": [ @@ -52,14 +52,14 @@ "body_html": "

New body for the article

\n\n", "body_markdown": "**New** body for the article", "user": { - "name": "King \"Kurtis\" \\:/ Hilpert", + "name": "Chester \"Norah\" \\:/ O'Reilly", "username": "username383", "twitter_username": "twitter383", "github_username": "github383", - "user_id": 819, + "user_id": 1143, "website_url": null, - "profile_image": "/uploads/user/profile_image/819/8d11e7ba-593a-4192-8977-14b323d77018.jpeg", - "profile_image_90": "/uploads/user/profile_image/819/8d11e7ba-593a-4192-8977-14b323d77018.jpeg" + "profile_image": "/uploads/user/profile_image/1143/016564ce-c63d-4e33-9746-2d6298502f4f.jpeg", + "profile_image_90": "/uploads/user/profile_image/1143/016564ce-c63d-4e33-9746-2d6298502f4f.jpeg" } } } @@ -202,47 +202,47 @@ "example": [ { "type_of": "article", - "id": 610, - "title": "The Wind's Twelve Quarters175", - "description": "Iphone yr etsy goth skateboard sustainable twee direct trade. Freegan cardigan +1 twee blog gastropub...", - "readable_publish_date": "Feb 27", - "slug": "the-winds-twelve-quarters175-p58", - "path": "/username387/the-winds-twelve-quarters175-p58", - "url": "http://localhost:3000/username387/the-winds-twelve-quarters175-p58", + "id": 493, + "title": "Vile Bodies175", + "description": "Actually photo booth occupy semiotics whatever gentrify tumblr. Narwhal forage pour-over portland....", + "readable_publish_date": "Mar 30", + "slug": "vile-bodies175-54a4", + "path": "/username387/vile-bodies175-54a4", + "url": "http://localhost:3000/username387/vile-bodies175-54a4", "comments_count": 0, "public_reactions_count": 0, "collection_id": null, - "published_timestamp": "2023-02-27T10:58:04Z", + "published_timestamp": "2023-03-30T07:50:19Z", "positive_reactions_count": 0, - "cover_image": "http://localhost:3000/assets/10-56ac1726da8a3bcbe4f93b48752287ea41bb79199cd8a8a61a9e4280ce9ae5b8.png", - "social_image": "http://localhost:3000/assets/10-56ac1726da8a3bcbe4f93b48752287ea41bb79199cd8a8a61a9e4280ce9ae5b8.png", - "canonical_url": "http://localhost:3000/username387/the-winds-twelve-quarters175-p58", - "created_at": "2023-02-27T10:58:04Z", + "cover_image": "http://localhost:3000/assets/11-f4a704eef06d25d2d2fa2026ef08f1089754beaf5b6ee01160115d3c36ed3d34.png", + "social_image": "http://localhost:3000/assets/11-f4a704eef06d25d2d2fa2026ef08f1089754beaf5b6ee01160115d3c36ed3d34.png", + "canonical_url": "http://localhost:3000/username387/vile-bodies175-54a4", + "created_at": "2023-03-30T07:50:19Z", "edited_at": null, "crossposted_at": null, - "published_at": "2023-02-27T10:58:04Z", - "last_comment_at": "2023-02-27T10:58:04Z", + "published_at": "2023-03-30T07:50:19Z", + "last_comment_at": "2023-03-30T07:50:19Z", "reading_time_minutes": 1, "tag_list": [ "discuss" ], "tags": "discuss", "user": { - "name": "Boyce \"Jimmy\" \\:/ Ledner", + "name": "Kim \"Tresa\" \\:/ Pagac", "username": "username387", "twitter_username": "twitter387", "github_username": "github387", - "user_id": 823, + "user_id": 1147, "website_url": null, - "profile_image": "/uploads/user/profile_image/823/265a22f6-a63a-4bae-9f3f-6a5d8d046de5.jpeg", - "profile_image_90": "/uploads/user/profile_image/823/265a22f6-a63a-4bae-9f3f-6a5d8d046de5.jpeg" + "profile_image": "/uploads/user/profile_image/1147/38003cae-b483-4bf3-b77d-e4a73938e17e.jpeg", + "profile_image_90": "/uploads/user/profile_image/1147/38003cae-b483-4bf3-b77d-e4a73938e17e.jpeg" }, "organization": { - "name": "O'Connell, Bosco and Skiles", + "name": "Klein, Larson and Stamm", "username": "org70", "slug": "org70", - "profile_image": "/uploads/organization/profile_image/72/0ac6f538-133b-4535-a194-9762e9953ed2.png", - "profile_image_90": "/uploads/organization/profile_image/72/0ac6f538-133b-4535-a194-9762e9953ed2.png" + "profile_image": "/uploads/organization/profile_image/1031/c3696c92-ad67-42cd-98be-052639c43106.png", + "profile_image_90": "/uploads/organization/profile_image/1031/c3696c92-ad67-42cd-98be-052639c43106.png" }, "flare_tag": { "name": "discuss", @@ -290,26 +290,26 @@ "example": [ { "type_of": "article", - "id": 613, - "title": "Absalom, Absalom!178", - "description": "Sartorial photo booth muggle magic chambray occupy umami leggings. Celiac pug paleo yolo...", - "readable_publish_date": "Feb 27", - "slug": "absalom-absalom178-4a5e", - "path": "/username390/absalom-absalom178-4a5e", - "url": "http://localhost:3000/username390/absalom-absalom178-4a5e", + "id": 496, + "title": "The Needle's Eye178", + "description": "Next level fanny pack pork belly flannel heirloom hammock yr direct trade. Biodiesel occupy etsy....", + "readable_publish_date": "Mar 30", + "slug": "the-needles-eye178-3j1i", + "path": "/username390/the-needles-eye178-3j1i", + "url": "http://localhost:3000/username390/the-needles-eye178-3j1i", "comments_count": 0, "public_reactions_count": 0, "collection_id": null, - "published_timestamp": "2023-02-27T10:58:04Z", + "published_timestamp": "2023-03-30T07:50:19Z", "positive_reactions_count": 0, - "cover_image": "http://localhost:3000/assets/24-377bc0861a9a539e8d1875ea9d4eea9e0226d93e1b6e9317e0c73c754699cc14.png", - "social_image": "http://localhost:3000/assets/24-377bc0861a9a539e8d1875ea9d4eea9e0226d93e1b6e9317e0c73c754699cc14.png", - "canonical_url": "http://localhost:3000/username390/absalom-absalom178-4a5e", - "created_at": "2023-02-27T10:58:04Z", + "cover_image": "http://localhost:3000/assets/19-ed58d3e8defcefc445020631589697a05e725243e834b5192aee4e6b91a3e927.png", + "social_image": "http://localhost:3000/assets/19-ed58d3e8defcefc445020631589697a05e725243e834b5192aee4e6b91a3e927.png", + "canonical_url": "http://localhost:3000/username390/the-needles-eye178-3j1i", + "created_at": "2023-03-30T07:50:19Z", "edited_at": null, "crossposted_at": null, - "published_at": "2023-02-27T10:58:04Z", - "last_comment_at": "2023-02-27T10:58:04Z", + "published_at": "2023-03-30T07:50:19Z", + "last_comment_at": "2023-03-30T07:50:19Z", "reading_time_minutes": 1, "tag_list": [ "javascript", @@ -318,14 +318,14 @@ ], "tags": "javascript, html, discuss", "user": { - "name": "Samantha \"Clemencia\" \\:/ Kemmer", + "name": "Elva \"Daniel\" \\:/ Bode", "username": "username390", "twitter_username": "twitter390", "github_username": "github390", - "user_id": 826, + "user_id": 1150, "website_url": null, - "profile_image": "/uploads/user/profile_image/826/dd79a3c7-6da2-4138-ac15-fab1628b409d.jpeg", - "profile_image_90": "/uploads/user/profile_image/826/dd79a3c7-6da2-4138-ac15-fab1628b409d.jpeg" + "profile_image": "/uploads/user/profile_image/1150/ef4bb832-1dc2-4c15-87c9-7f1561563cdf.jpeg", + "profile_image_90": "/uploads/user/profile_image/1150/ef4bb832-1dc2-4c15-87c9-7f1561563cdf.jpeg" }, "flare_tag": { "name": "discuss", @@ -335,26 +335,26 @@ }, { "type_of": "article", - "id": 612, - "title": "If Not Now, When?177", - "description": "Master taxidermy yuccie polaroid tousled 90's street. Green juice helvetica chartreuse listicle banh...", - "readable_publish_date": "Feb 27", - "slug": "if-not-now-when177-4iin", - "path": "/username389/if-not-now-when177-4iin", - "url": "http://localhost:3000/username389/if-not-now-when177-4iin", + "id": 495, + "title": "The Heart Is Deceitful Above All Things177", + "description": "Forage loko neutra. Gentrify meh cold-pressed roof distillery etsy. Keffiyeh knausgaard pour-over...", + "readable_publish_date": "Mar 30", + "slug": "the-heart-is-deceitful-above-all-things177-47p4", + "path": "/username389/the-heart-is-deceitful-above-all-things177-47p4", + "url": "http://localhost:3000/username389/the-heart-is-deceitful-above-all-things177-47p4", "comments_count": 0, "public_reactions_count": 0, "collection_id": null, - "published_timestamp": "2023-02-27T10:58:04Z", + "published_timestamp": "2023-03-30T07:50:19Z", "positive_reactions_count": 0, - "cover_image": "http://localhost:3000/assets/2-1a96ae446ded018b65b215cce3aecc40a00e701642da521fdd6edd3c593ff6c1.png", - "social_image": "http://localhost:3000/assets/2-1a96ae446ded018b65b215cce3aecc40a00e701642da521fdd6edd3c593ff6c1.png", - "canonical_url": "http://localhost:3000/username389/if-not-now-when177-4iin", - "created_at": "2023-02-27T10:58:04Z", + "cover_image": "http://localhost:3000/assets/4-dcfcc4d8dd259bc0751c2de24b1cf244b181c789934368ca1cb471f0944b695d.png", + "social_image": "http://localhost:3000/assets/4-dcfcc4d8dd259bc0751c2de24b1cf244b181c789934368ca1cb471f0944b695d.png", + "canonical_url": "http://localhost:3000/username389/the-heart-is-deceitful-above-all-things177-47p4", + "created_at": "2023-03-30T07:50:19Z", "edited_at": null, "crossposted_at": null, - "published_at": "2023-02-27T10:58:04Z", - "last_comment_at": "2023-02-27T10:58:04Z", + "published_at": "2023-03-30T07:50:19Z", + "last_comment_at": "2023-03-30T07:50:19Z", "reading_time_minutes": 1, "tag_list": [ "javascript", @@ -363,14 +363,14 @@ ], "tags": "javascript, html, discuss", "user": { - "name": "Brianna \"Gabriel\" \\:/ Mante", + "name": "Antonio \"Clifford\" \\:/ Beahan", "username": "username389", "twitter_username": "twitter389", "github_username": "github389", - "user_id": 825, + "user_id": 1149, "website_url": null, - "profile_image": "/uploads/user/profile_image/825/3bf3e66f-9268-4e22-89d9-431e0a5fa9dc.jpeg", - "profile_image_90": "/uploads/user/profile_image/825/3bf3e66f-9268-4e22-89d9-431e0a5fa9dc.jpeg" + "profile_image": "/uploads/user/profile_image/1149/5eece559-3df5-4fce-8e02-d204208303fb.jpeg", + "profile_image_90": "/uploads/user/profile_image/1149/5eece559-3df5-4fce-8e02-d204208303fb.jpeg" }, "flare_tag": { "name": "discuss", @@ -380,26 +380,26 @@ }, { "type_of": "article", - "id": 611, - "title": "Have His Carcase176", - "description": "Salvia sartorial carry you probably haven't heard of them try-hard dreamcatcher meggings 8-bit....", - "readable_publish_date": "Feb 27", - "slug": "have-his-carcase176-1phd", - "path": "/username388/have-his-carcase176-1phd", - "url": "http://localhost:3000/username388/have-his-carcase176-1phd", + "id": 494, + "title": "Carrion Comfort176", + "description": "Etsy quinoa tote bag blue bottle austin vice. Wolf slow-carb ethical. Vinyl single-origin coffee...", + "readable_publish_date": "Mar 30", + "slug": "carrion-comfort176-35c4", + "path": "/username388/carrion-comfort176-35c4", + "url": "http://localhost:3000/username388/carrion-comfort176-35c4", "comments_count": 0, "public_reactions_count": 0, "collection_id": null, - "published_timestamp": "2023-02-27T10:58:04Z", + "published_timestamp": "2023-03-30T07:50:19Z", "positive_reactions_count": 0, - "cover_image": "http://localhost:3000/assets/24-377bc0861a9a539e8d1875ea9d4eea9e0226d93e1b6e9317e0c73c754699cc14.png", - "social_image": "http://localhost:3000/assets/24-377bc0861a9a539e8d1875ea9d4eea9e0226d93e1b6e9317e0c73c754699cc14.png", - "canonical_url": "http://localhost:3000/username388/have-his-carcase176-1phd", - "created_at": "2023-02-27T10:58:04Z", + "cover_image": "http://localhost:3000/assets/20-92231c1d2ddb3b707b8c1b5cb711ef17632ff2a64495970a58518ce33c3a4f76.png", + "social_image": "http://localhost:3000/assets/20-92231c1d2ddb3b707b8c1b5cb711ef17632ff2a64495970a58518ce33c3a4f76.png", + "canonical_url": "http://localhost:3000/username388/carrion-comfort176-35c4", + "created_at": "2023-03-30T07:50:19Z", "edited_at": null, "crossposted_at": null, - "published_at": "2023-02-27T10:58:04Z", - "last_comment_at": "2023-02-27T10:58:04Z", + "published_at": "2023-03-30T07:50:19Z", + "last_comment_at": "2023-03-30T07:50:19Z", "reading_time_minutes": 1, "tag_list": [ "javascript", @@ -408,14 +408,14 @@ ], "tags": "javascript, html, discuss", "user": { - "name": "Leeanna \"Miles\" \\:/ Hills", + "name": "Allene \"Denita\" \\:/ Kilback", "username": "username388", "twitter_username": "twitter388", "github_username": "github388", - "user_id": 824, + "user_id": 1148, "website_url": null, - "profile_image": "/uploads/user/profile_image/824/50463451-9323-40fc-b439-c7df125a27fa.jpeg", - "profile_image_90": "/uploads/user/profile_image/824/50463451-9323-40fc-b439-c7df125a27fa.jpeg" + "profile_image": "/uploads/user/profile_image/1148/5fa0ee05-bfe8-43a8-9351-b4e09f12dc8e.jpeg", + "profile_image_90": "/uploads/user/profile_image/1148/5fa0ee05-bfe8-43a8-9351-b4e09f12dc8e.jpeg" }, "flare_tag": { "name": "discuss", @@ -464,42 +464,42 @@ "application/json": { "example": { "type_of": "article", - "id": 614, - "title": "Cover Her Face179", - "description": "Banjo carry cray vhs swag. Whatever celiac quinoa pabst chillwave. Vice pickled park lumbersexual...", - "readable_publish_date": "Feb 27", - "slug": "cover-her-face179-4gbc", - "path": "/username391/cover-her-face179-4gbc", - "url": "http://localhost:3000/username391/cover-her-face179-4gbc", + "id": 497, + "title": "Dance Dance Dance179", + "description": "Helvetica slow-carb shabby chic mlkshk. Bitters pop-up readymade waistcoat. Tote bag chicharrones...", + "readable_publish_date": "Mar 30", + "slug": "dance-dance-dance179-265m", + "path": "/username391/dance-dance-dance179-265m", + "url": "http://localhost:3000/username391/dance-dance-dance179-265m", "comments_count": 0, "public_reactions_count": 0, "collection_id": null, - "published_timestamp": "2023-02-27T10:58:04Z", + "published_timestamp": "2023-03-30T07:50:20Z", "positive_reactions_count": 0, - "cover_image": "http://localhost:3000/assets/2-1a96ae446ded018b65b215cce3aecc40a00e701642da521fdd6edd3c593ff6c1.png", - "social_image": "http://localhost:3000/assets/2-1a96ae446ded018b65b215cce3aecc40a00e701642da521fdd6edd3c593ff6c1.png", - "canonical_url": "http://localhost:3000/username391/cover-her-face179-4gbc", - "created_at": "2023-02-27T10:58:04Z", + "cover_image": "http://localhost:3000/assets/3-93b6b57b5a6115cffe5d63d29a22825eb9e65f647bfef57a88244bc2b98186f0.png", + "social_image": "http://localhost:3000/assets/3-93b6b57b5a6115cffe5d63d29a22825eb9e65f647bfef57a88244bc2b98186f0.png", + "canonical_url": "http://localhost:3000/username391/dance-dance-dance179-265m", + "created_at": "2023-03-30T07:50:20Z", "edited_at": null, "crossposted_at": null, - "published_at": "2023-02-27T10:58:04Z", - "last_comment_at": "2023-02-27T10:58:04Z", + "published_at": "2023-03-30T07:50:20Z", + "last_comment_at": "2023-03-30T07:50:20Z", "reading_time_minutes": 1, "tag_list": "discuss", "tags": [ "discuss" ], - "body_html": "

Banjo carry cray vhs swag. Whatever celiac quinoa pabst chillwave. Vice pickled park lumbersexual salvia synth. Blog etsy austin mustache.

\n\n

Biodiesel forage street thundercats deep v.

\n\n", - "body_markdown": "---\ntitle: Cover Her Face179\npublished: true\ntags: discuss\ndate: \nseries: \ncanonical_url: \n\n---\n\nBanjo carry cray vhs swag. Whatever celiac quinoa pabst chillwave. Vice pickled park lumbersexual salvia synth. Blog etsy austin mustache.\n\n\nBiodiesel forage street thundercats deep v.\n\n", + "body_html": "

Helvetica slow-carb shabby chic mlkshk. Bitters pop-up readymade waistcoat. Tote bag chicharrones muggle magic ennui whatever photo booth small batch. Hammock drinking humblebrag 90's letterpress.

\n\n

Pinterest pour-over trust fund banh mi.

\n\n", + "body_markdown": "---\ntitle: Dance Dance Dance179\npublished: true\ntags: discuss\ndate: \nseries: \ncanonical_url: \n\n---\n\nHelvetica slow-carb shabby chic mlkshk. Bitters pop-up readymade waistcoat. Tote bag chicharrones muggle magic ennui whatever photo booth small batch. Hammock drinking humblebrag 90's letterpress.\n\n\nPinterest pour-over trust fund banh mi.\n\n", "user": { - "name": "Von \"Joan\" \\:/ Swaniawski", + "name": "Doreen \"Melvina\" \\:/ Kerluke", "username": "username391", "twitter_username": "twitter391", "github_username": "github391", - "user_id": 827, + "user_id": 1151, "website_url": null, - "profile_image": "/uploads/user/profile_image/827/90d87f32-bafb-49f5-8001-c7f1146a84f8.jpeg", - "profile_image_90": "/uploads/user/profile_image/827/90d87f32-bafb-49f5-8001-c7f1146a84f8.jpeg" + "profile_image": "/uploads/user/profile_image/1151/317b32a2-0a5a-4fb4-9c1f-82c2de66b782.jpeg", + "profile_image_90": "/uploads/user/profile_image/1151/317b32a2-0a5a-4fb4-9c1f-82c2de66b782.jpeg" }, "flare_tag": { "name": "discuss", @@ -557,26 +557,26 @@ "application/json": { "example": { "type_of": "article", - "id": 615, - "title": "Nectar in a Sieve180", - "description": "Humblebrag brooklyn master 3 wolf moon small batch thundercats typewriter chia. Gluten-free direct...", - "readable_publish_date": "Feb 27", - "slug": "nectar-in-a-sieve180-51j6", - "path": "/username392/nectar-in-a-sieve180-51j6", - "url": "http://localhost:3000/username392/nectar-in-a-sieve180-51j6", + "id": 498, + "title": "The Wings of the Dove180", + "description": "Swag umami everyday williamsburg squid knausgaard neutra. Ramps flexitarian pabst dreamcatcher...", + "readable_publish_date": "Mar 30", + "slug": "the-wings-of-the-dove180-57c4", + "path": "/username392/the-wings-of-the-dove180-57c4", + "url": "http://localhost:3000/username392/the-wings-of-the-dove180-57c4", "comments_count": 0, "public_reactions_count": 0, "collection_id": null, - "published_timestamp": "2023-02-27T10:58:04Z", + "published_timestamp": "2023-03-30T07:50:20Z", "positive_reactions_count": 0, - "cover_image": "http://localhost:3000/assets/16-77521848e7b5fcc073ac3e0bb004826e97f737238194e4c79330f662cc946ab2.png", - "social_image": "http://localhost:3000/assets/16-77521848e7b5fcc073ac3e0bb004826e97f737238194e4c79330f662cc946ab2.png", - "canonical_url": "http://localhost:3000/username392/nectar-in-a-sieve180-51j6", - "created_at": "2023-02-27T10:58:04Z", - "edited_at": "2023-02-27T10:58:04Z", + "cover_image": "http://localhost:3000/assets/39-20fc2599938fbd7c41146577147aa7c6925e3b8ff069aba58c9304bc1b944cf1.png", + "social_image": "http://localhost:3000/assets/39-20fc2599938fbd7c41146577147aa7c6925e3b8ff069aba58c9304bc1b944cf1.png", + "canonical_url": "http://localhost:3000/username392/the-wings-of-the-dove180-57c4", + "created_at": "2023-03-30T07:50:20Z", + "edited_at": "2023-03-30T07:50:20Z", "crossposted_at": null, - "published_at": "2023-02-27T10:58:04Z", - "last_comment_at": "2023-02-27T10:58:04Z", + "published_at": "2023-03-30T07:50:20Z", + "last_comment_at": "2023-03-30T07:50:20Z", "reading_time_minutes": 1, "tag_list": "", "tags": [ @@ -585,14 +585,14 @@ "body_html": "

New body for the article

\n\n", "body_markdown": "**New** body for the article", "user": { - "name": "Lyndon \"Kaley\" \\:/ Torphy", + "name": "Emil \"Nettie\" \\:/ Denesik", "username": "username392", "twitter_username": "twitter392", "github_username": "github392", - "user_id": 828, + "user_id": 1152, "website_url": null, - "profile_image": "/uploads/user/profile_image/828/bd640b77-6394-4cf5-8d72-646c8ef542d5.jpeg", - "profile_image_90": "/uploads/user/profile_image/828/bd640b77-6394-4cf5-8d72-646c8ef542d5.jpeg" + "profile_image": "/uploads/user/profile_image/1152/9cd5a7a0-243c-4394-bc26-95614664188c.jpeg", + "profile_image_90": "/uploads/user/profile_image/1152/9cd5a7a0-243c-4394-bc26-95614664188c.jpeg" } } } @@ -679,42 +679,42 @@ "application/json": { "example": { "type_of": "article", - "id": 618, - "title": "The Line of Beauty183", - "description": "Synth tote bag venmo vice hoodie disrupt bitters mixtape. Fashion axe goth shoreditch kogi loko...", - "readable_publish_date": "Feb 27", - "slug": "the-line-of-beauty183-33nj", - "path": "/username396/the-line-of-beauty183-33nj", - "url": "http://localhost:3000/username396/the-line-of-beauty183-33nj", + "id": 501, + "title": "A Scanner Darkly183", + "description": "Blue bottle marfa muggle magic. Synth brunch letterpress franzen kitsch 3 wolf moon everyday. Tumblr...", + "readable_publish_date": "Mar 30", + "slug": "a-scanner-darkly183-3mp3", + "path": "/username396/a-scanner-darkly183-3mp3", + "url": "http://localhost:3000/username396/a-scanner-darkly183-3mp3", "comments_count": 0, "public_reactions_count": 0, "collection_id": null, - "published_timestamp": "2023-02-27T10:58:04Z", + "published_timestamp": "2023-03-30T07:50:20Z", "positive_reactions_count": 0, - "cover_image": "http://localhost:3000/assets/3-93b6b57b5a6115cffe5d63d29a22825eb9e65f647bfef57a88244bc2b98186f0.png", - "social_image": "http://localhost:3000/assets/3-93b6b57b5a6115cffe5d63d29a22825eb9e65f647bfef57a88244bc2b98186f0.png", - "canonical_url": "http://localhost:3000/username396/the-line-of-beauty183-33nj", - "created_at": "2023-02-27T10:58:04Z", + "cover_image": "http://localhost:3000/assets/32-543e7c7f0a939e829c37aab48d705350b855c887dc16dfab30fd9a0825c09291.png", + "social_image": "http://localhost:3000/assets/32-543e7c7f0a939e829c37aab48d705350b855c887dc16dfab30fd9a0825c09291.png", + "canonical_url": "http://localhost:3000/username396/a-scanner-darkly183-3mp3", + "created_at": "2023-03-30T07:50:20Z", "edited_at": null, "crossposted_at": null, - "published_at": "2023-02-27T10:58:04Z", - "last_comment_at": "2023-02-27T10:58:04Z", + "published_at": "2023-03-30T07:50:20Z", + "last_comment_at": "2023-03-30T07:50:20Z", "reading_time_minutes": 1, "tag_list": "discuss", "tags": [ "discuss" ], - "body_html": "

Synth tote bag venmo vice hoodie disrupt bitters mixtape. Fashion axe goth shoreditch kogi loko literally.

\n\n

Franzen ramps forage wayfarers thundercats put a bird on it loko.

\n\n", - "body_markdown": "---\ntitle: The Line of Beauty183\npublished: true\ntags: discuss\ndate: \nseries: \ncanonical_url: \n\n---\n\nSynth tote bag venmo vice hoodie disrupt bitters mixtape. Fashion axe goth shoreditch kogi loko literally.\n\n\nFranzen ramps forage wayfarers thundercats put a bird on it loko.\n\n", + "body_html": "

Blue bottle marfa muggle magic. Synth brunch letterpress franzen kitsch 3 wolf moon everyday.

\n\n

Tumblr migas deep v street. Tumblr yuccie muggle magic crucifix actually forage.

\n\n", + "body_markdown": "---\ntitle: A Scanner Darkly183\npublished: true\ntags: discuss\ndate: \nseries: \ncanonical_url: \n\n---\n\nBlue bottle marfa muggle magic. Synth brunch letterpress franzen kitsch 3 wolf moon everyday.\n\n\nTumblr migas deep v street. Tumblr yuccie muggle magic crucifix actually forage.\n\n", "user": { - "name": "Danial \"Charles\" \\:/ Grant", + "name": "Milo \"Karly\" \\:/ Mertz", "username": "username396", "twitter_username": "twitter396", "github_username": "github396", - "user_id": 832, + "user_id": 1156, "website_url": null, - "profile_image": "/uploads/user/profile_image/832/80339e58-8c50-4c64-b8a5-0ae9d3bf6d2d.jpeg", - "profile_image_90": "/uploads/user/profile_image/832/80339e58-8c50-4c64-b8a5-0ae9d3bf6d2d.jpeg" + "profile_image": "/uploads/user/profile_image/1156/93b1f8a9-2e49-4480-bb6f-e7fe1a8eb25e.jpeg", + "profile_image_90": "/uploads/user/profile_image/1156/93b1f8a9-2e49-4480-bb6f-e7fe1a8eb25e.jpeg" }, "flare_tag": { "name": "discuss", @@ -1039,18 +1039,18 @@ "example": [ { "type_of": "comment", - "id_code": "60", - "created_at": "2023-02-27T10:58:05Z", - "body_html": "

Tumblr organic put a bird on it everyday mustache typewriter pug.

\n\n", + "id_code": "b3", + "created_at": "2023-03-30T07:50:21Z", + "body_html": "

Freegan tacos scenester 90's pabst. Listicle hashtag pickled austin biodiesel street.

\n\n", "user": { - "name": "Dwight \"Pedro\" \\:/ Parker", + "name": "Gabriel \"Rosario\" \\:/ Dickens", "username": "username410", "twitter_username": "twitter410", "github_username": "github410", - "user_id": 846, + "user_id": 1170, "website_url": null, - "profile_image": "/uploads/user/profile_image/846/8af90bef-f000-41c1-a90f-0e364c163a8a.jpeg", - "profile_image_90": "/uploads/user/profile_image/846/8af90bef-f000-41c1-a90f-0e364c163a8a.jpeg" + "profile_image": "/uploads/user/profile_image/1170/f2170bd2-18d6-43a4-9500-7c179e75602e.jpeg", + "profile_image_90": "/uploads/user/profile_image/1170/f2170bd2-18d6-43a4-9500-7c179e75602e.jpeg" }, "children": [ @@ -1110,18 +1110,18 @@ "application/json": { "example": { "type_of": "comment", - "id_code": "62", - "created_at": "2023-02-27T10:58:05Z", - "body_html": "

Farm-to-table park banjo. Cronut gentrify farm-to-table. Salvia distillery letterpress deep v keffiyeh kickstarter thundercats cray.

\n\n", + "id_code": "b5", + "created_at": "2023-03-30T07:50:21Z", + "body_html": "

Meditation health 90's post-ironic twee iphone retro food truck.

\n\n", "user": { - "name": "Gilbert \"Alverta\" \\:/ Schroeder", + "name": "Antonia \"Cora\" \\:/ Tillman", "username": "username414", "twitter_username": "twitter414", "github_username": "github414", - "user_id": 850, + "user_id": 1174, "website_url": null, - "profile_image": "/uploads/user/profile_image/850/6976f67a-4df7-4ed1-967f-0a3ea0d52670.jpeg", - "profile_image_90": "/uploads/user/profile_image/850/6976f67a-4df7-4ed1-967f-0a3ea0d52670.jpeg" + "profile_image": "/uploads/user/profile_image/1174/b656cd3a-d8c8-4afe-b795-2384d6b3bb09.jpeg", + "profile_image_90": "/uploads/user/profile_image/1174/b656cd3a-d8c8-4afe-b795-2384d6b3bb09.jpeg" }, "children": [ @@ -1190,14 +1190,15 @@ "content": { "application/json": { "example": { - "id": 10, + "id": 935, "approved": true, "body_markdown": "# Hi, this is ad\nYep, it's an ad", "cached_tag_list": "", "clicks_count": 0, - "created_at": "2023-02-27T21:58:05.881+11:00", + "created_at": "2023-03-30T13:20:21.892+05:30", "creator_id": null, "display_to": "all", + "exclude_article_ids": "", "impressions_count": 0, "name": "Example Ad", "organization_id": null, @@ -1206,7 +1207,7 @@ "published": true, "success_rate": 0.0, "type_of": "in_house", - "updated_at": "2023-02-27T21:58:05.881+11:00", + "updated_at": "2023-03-30T13:20:21.892+05:30", "tag_list": "" } } @@ -1236,6 +1237,7 @@ "created_at": null, "creator_id": null, "display_to": "all", + "exclude_article_ids": "", "impressions_count": 0, "name": "Example Ad", "organization_id": null, @@ -1312,6 +1314,10 @@ "type": "string", "description": "Tags on which this ad can be displayed (blank is all/any tags)" }, + "article_exclude_ids": { + "type": "string", + "description": "Articles this ad should *not* appear (blank is all/any article), comma-separated list of integer Article IDs" + }, "creator_id": { "type": "integer", "description": "Identifies the user who created the ad." @@ -1355,23 +1361,24 @@ "content": { "application/json": { "example": { - "id": 11, + "id": 936, "approved": false, "body_markdown": "Hello _hey_ Hey hey 9", "cached_tag_list": "", "clicks_count": 0, - "created_at": "2023-02-27T21:58:06.000+11:00", + "created_at": "2023-03-30T13:20:22.034+05:30", "creator_id": null, "display_to": "all", + "exclude_article_ids": "", "impressions_count": 0, - "name": "Display Ad 11", - "organization_id": 73, + "name": "Display Ad 936", + "organization_id": 1032, "placement_area": "sidebar_left", "processed_html": "

Hello hey Hey hey 9

", "published": false, "success_rate": 0.0, "type_of": "in_house", - "updated_at": "2023-02-27T21:58:06.003+11:00", + "updated_at": "2023-03-30T13:20:22.037+05:30", "tag_list": "" } } @@ -1431,19 +1438,20 @@ "body_markdown": "Hello _hey_ Hey hey 10", "creator_id": null, "display_to": "all", - "name": "Display Ad 12", - "organization_id": 74, + "name": "Display Ad 937", + "organization_id": 1033, "placement_area": "sidebar_left", "published": false, "type_of": "in_house", + "exclude_article_ids": "", "processed_html": "

Hello hey Hey hey 10

", "cached_tag_list": "", - "id": 12, + "id": 937, "clicks_count": 0, - "created_at": "2023-02-27T21:58:06.134+11:00", + "created_at": "2023-03-30T13:20:22.200+05:30", "impressions_count": 0, "success_rate": 0.0, - "updated_at": "2023-02-27T21:58:06.137+11:00", + "updated_at": "2023-03-30T13:20:22.203+05:30", "tag_list": "" } } @@ -1616,12 +1624,12 @@ "application/json": { "example": [ { - "id": 1220, + "id": 2051, "name": "tag3", "points": 1.0 }, { - "id": 1221, + "id": 2052, "name": "tag4", "points": 1.0 } @@ -1672,23 +1680,23 @@ "example": [ { "type_of": "user_follower", - "id": 7, - "created_at": "2023-02-27T10:58:06Z", - "user_id": 871, - "name": "Benjamin \"Sol\" \\:/ Senger", + "id": 27, + "created_at": "2023-03-30T07:50:22Z", + "user_id": 1195, + "name": "Irvin \"Francesco\" \\:/ Bruen", "path": "/username435", "username": "username435", - "profile_image": "/uploads/user/profile_image/871/51d055b1-32e3-4ccd-878a-a63e0ab5f69b.jpeg" + "profile_image": "/uploads/user/profile_image/1195/dd7acac2-e6a8-431b-a72b-7431a6eac64c.jpeg" }, { "type_of": "user_follower", - "id": 6, - "created_at": "2023-02-27T10:58:06Z", - "user_id": 869, - "name": "Christin \"Anthony\" \\:/ Metz", + "id": 26, + "created_at": "2023-03-30T07:50:22Z", + "user_id": 1193, + "name": "Babette \"Trey\" \\:/ Dickens", "path": "/username433", "username": "username433", - "profile_image": "/uploads/user/profile_image/869/8ba1b0fb-ed63-4d36-a21d-11615b8e42d0.jpeg" + "profile_image": "/uploads/user/profile_image/1193/f66a0475-6b4c-4144-bddb-4b0d7a486c02.jpeg" } ], "schema": { @@ -1770,19 +1778,19 @@ "application/json": { "example": { "type_of": "organization", - "id": 79, + "id": 1038, "username": "org77", - "name": "Beatty Inc", - "summary": "Stumptown schlitz umami try-hard blog mumblecore. Typewriter 8-bit five dollar toast neutra locavore put a bird on it farm-to-table tilde.", - "twitter_username": "org8840", - "github_username": "org217", - "url": "http://spinka-armstrong.com/hollis", + "name": "Frami-Sauer", + "summary": "Gluten-free jean shorts bushwick franzen mixtape.", + "twitter_username": "org65", + "github_username": "org3603", + "url": "http://flatley.com/jan", "location": null, "tech_stack": null, "tag_line": null, "story": null, - "joined_at": "2023-02-27T10:58:06Z", - "profile_image": "/uploads/organization/profile_image/79/a1244f11-60ba-4f71-8c00-4e3f29ddf7f3.png" + "joined_at": "2023-03-30T07:50:22Z", + "profile_image": "/uploads/organization/profile_image/1038/b764d03f-c6cb-4523-b518-ab359021452c.png" }, "schema": { "type": "object", @@ -1843,29 +1851,29 @@ "example": [ { "type_of": "user", - "id": 881, + "id": 1205, "username": "username445", - "name": "Jeromy \"Spencer\" \\:/ VonRueden", + "name": "Lola \"Martina\" \\:/ Lang", "twitter_username": "twitter445", "github_username": "github445", "summary": null, "location": null, "website_url": null, - "joined_at": "Feb 27, 2023", - "profile_image": "/uploads/user/profile_image/881/66c7cfc8-df38-4758-aad0-3d8b6b225a35.jpeg" + "joined_at": "Mar 30, 2023", + "profile_image": "/uploads/user/profile_image/1205/5b35efd1-afa4-4399-acc0-fb19eb033327.jpeg" }, { "type_of": "user", - "id": 882, + "id": 1206, "username": "username446", - "name": "Annabel \"Tisa\" \\:/ Rogahn", + "name": "Courtney \"Stefan\" \\:/ Schuster", "twitter_username": "twitter446", "github_username": "github446", "summary": null, "location": null, "website_url": null, - "joined_at": "Feb 27, 2023", - "profile_image": "/uploads/user/profile_image/882/9cc02e02-adbb-4735-85bf-5f336714bb18.jpeg" + "joined_at": "Mar 30, 2023", + "profile_image": "/uploads/user/profile_image/1206/7c2b85ca-80da-49a8-a544-a3e545fef640.jpeg" } ], "schema": { @@ -1927,26 +1935,26 @@ "example": [ { "type_of": "article", - "id": 630, - "title": "Postern of Fate195", - "description": "Tilde master jean shorts farm-to-table yuccie. Poutine freegan semiotics. Cronut tacos post-ironic...", - "readable_publish_date": "Feb 27", - "slug": "postern-of-fate195-51k4", - "path": "/org81/postern-of-fate195-51k4", - "url": "http://localhost:3000/org81/postern-of-fate195-51k4", + "id": 513, + "title": "Tirra Lirra by the River195", + "description": "Tumblr forage thundercats art party salvia everyday. Sartorial church-key selfies keytar cred....", + "readable_publish_date": "Mar 30", + "slug": "tirra-lirra-by-the-river195-27j3", + "path": "/org81/tirra-lirra-by-the-river195-27j3", + "url": "http://localhost:3000/org81/tirra-lirra-by-the-river195-27j3", "comments_count": 0, "public_reactions_count": 0, "collection_id": null, - "published_timestamp": "2023-02-27T10:58:07Z", + "published_timestamp": "2023-03-30T07:50:23Z", "positive_reactions_count": 0, - "cover_image": "http://localhost:3000/assets/12-f9d673ae4ff98002f782ab82c641f2f26673be728e8f5409bea83f2d1de15323.png", - "social_image": "http://localhost:3000/assets/12-f9d673ae4ff98002f782ab82c641f2f26673be728e8f5409bea83f2d1de15323.png", - "canonical_url": "http://localhost:3000/org81/postern-of-fate195-51k4", - "created_at": "2023-02-27T10:58:07Z", + "cover_image": "http://localhost:3000/assets/37-94b286825ffd9f2b47c9842cf4f262b7c89e789797eba40196bc14b5c2359e75.png", + "social_image": "http://localhost:3000/assets/37-94b286825ffd9f2b47c9842cf4f262b7c89e789797eba40196bc14b5c2359e75.png", + "canonical_url": "http://localhost:3000/org81/tirra-lirra-by-the-river195-27j3", + "created_at": "2023-03-30T07:50:23Z", "edited_at": null, "crossposted_at": null, - "published_at": "2023-02-27T10:58:07Z", - "last_comment_at": "2023-02-27T10:58:07Z", + "published_at": "2023-03-30T07:50:23Z", + "last_comment_at": "2023-03-30T07:50:23Z", "reading_time_minutes": 1, "tag_list": [ "javascript", @@ -1955,21 +1963,21 @@ ], "tags": "javascript, html, discuss", "user": { - "name": "Rowena \"Zack\" \\:/ Howell", + "name": "Randall \"Larisa\" \\:/ Will", "username": "username453", "twitter_username": "twitter453", "github_username": "github453", - "user_id": 889, + "user_id": 1213, "website_url": null, - "profile_image": "/uploads/user/profile_image/889/9d1a2834-1117-4f0d-9e87-aa4f3d3dc525.jpeg", - "profile_image_90": "/uploads/user/profile_image/889/9d1a2834-1117-4f0d-9e87-aa4f3d3dc525.jpeg" + "profile_image": "/uploads/user/profile_image/1213/15de4f8e-2b27-4bab-b936-a2538be7a7fd.jpeg", + "profile_image_90": "/uploads/user/profile_image/1213/15de4f8e-2b27-4bab-b936-a2538be7a7fd.jpeg" }, "organization": { - "name": "Schaden-Fritsch", + "name": "Schaefer LLC", "username": "org81", "slug": "org81", - "profile_image": "/uploads/organization/profile_image/83/8d2996b4-f9fb-4947-aea3-17898ab9d7ec.png", - "profile_image_90": "/uploads/organization/profile_image/83/8d2996b4-f9fb-4947-aea3-17898ab9d7ec.png" + "profile_image": "/uploads/organization/profile_image/1042/622cd5f5-59ab-4416-8322-2bf104d4187f.png", + "profile_image_90": "/uploads/organization/profile_image/1042/622cd5f5-59ab-4416-8322-2bf104d4187f.png" } } ], @@ -2013,16 +2021,16 @@ "application/json": { "example": [ { - "id": 1, - "title": "This Side of Paradise", - "slug": "push_premium", - "description": "Voluptas ut laboriosam neque.", + "id": 26, + "title": "Beneath the Bleeding", + "slug": "push-shock", + "description": "Atque reiciendis ut quaerat.", "is_top_level_path": false, "landing_page": false, "body_html": null, "body_json": null, - "body_markdown": "Velit autem nisi distinctio.", - "processed_html": "

Velit autem nisi distinctio.

\n\n", + "body_markdown": "Dolores officia ab accusamus.", + "processed_html": "

Dolores officia ab accusamus.

\n\n", "social_image": { "url": null }, @@ -2055,7 +2063,7 @@ "content": { "application/json": { "example": { - "id": 3, + "id": 28, "title": "Example Page", "slug": "example1", "description": "a new page", @@ -2186,16 +2194,16 @@ "content": { "application/json": { "example": { - "id": 6, - "title": "In a Glass Darkly", - "slug": "satisfaction-scale", - "description": "Voluptatibus quod dolor dolores.", + "id": 31, + "title": "Pale Kings and Princes", + "slug": "thirsty_highway", + "description": "Libero molestiae eligendi cupiditate.", "is_top_level_path": false, "landing_page": false, "body_html": null, "body_json": null, - "body_markdown": "Amet rerum nostrum earum.", - "processed_html": "

Amet rerum nostrum earum.

\n\n", + "body_markdown": "Consequatur accusantium perspiciatis illo.", + "processed_html": "

Consequatur accusantium perspiciatis illo.

\n\n", "social_image": { "url": null }, @@ -2235,16 +2243,16 @@ "content": { "application/json": { "example": { - "id": 7, + "id": 32, "title": "New Title", - "slug": "corn-premium", - "description": "Ut reiciendis qui iste.", + "slug": "seller-ample", + "description": "Similique qui voluptates autem.", "is_top_level_path": false, "landing_page": false, "body_html": null, "body_json": null, - "body_markdown": "Qui sed sit dolorem.", - "processed_html": "

Qui sed sit dolorem.

\n\n", + "body_markdown": "Enim ex optio maxime.", + "processed_html": "

Enim ex optio maxime.

\n\n", "social_image": { "url": null }, @@ -2272,16 +2280,16 @@ "content": { "application/json": { "example": { - "id": 9, - "title": "Dying of the Light", - "slug": "seller_arena", - "description": "Sapiente rerum labore est.", + "id": 34, + "title": "The Curious Incident of the Dog in the Night-Time", + "slug": "minister_appointment", + "description": "Est nulla enim dolorum.", "is_top_level_path": false, "landing_page": false, "body_html": null, "body_json": null, - "body_markdown": "Dolorum earum quod deleniti.", - "processed_html": "

Voluptas illo dolorem nisi.

\n\n", + "body_markdown": "Quia voluptate labore blanditiis.", + "processed_html": "

Corporis sequi doloremque minima.

\n\n", "social_image": { "url": null }, @@ -2327,16 +2335,16 @@ "content": { "application/json": { "example": { - "id": 10, - "title": "The Green Bay Tree", - "slug": "message-premium", - "description": "Est molestias eius voluptas.", + "id": 35, + "title": "Great Work of Time", + "slug": "wear_ambiguous", + "description": "Aliquid sunt laborum nihil.", "is_top_level_path": false, "landing_page": false, "body_html": null, "body_json": null, - "body_markdown": "In soluta qui odio.", - "processed_html": "

In soluta qui odio.

\n\n", + "body_markdown": "Quibusdam est et laborum.", + "processed_html": "

Quibusdam est et laborum.

\n\n", "social_image": { "url": null }, @@ -2416,14 +2424,14 @@ { "type_of": "podcast_episodes", "class_name": "PodcastEpisode", - "id": 4, + "id": 26, "path": "/codenewbie/slug-4", - "title": "20", - "image_url": "/uploads/podcast/image/4/5e637d0a-0446-47a1-a77c-09dd5adaa4b6.jpeg", + "title": "26", + "image_url": "/uploads/podcast/image/21/b10865d4-188b-47ae-a577-ff15471b9fef.jpeg", "podcast": { - "title": "Delirium Tremens", + "title": "Chocolate St", "slug": "codenewbie", - "image_url": "/uploads/podcast/image/4/5e637d0a-0446-47a1-a77c-09dd5adaa4b6.jpeg" + "image_url": "/uploads/podcast/image/21/b10865d4-188b-47ae-a577-ff15471b9fef.jpeg" } } ], @@ -2478,8 +2486,8 @@ "example": { "type_of": "profile_image", "image_of": "user", - "profile_image": "/uploads/user/profile_image/904/b992f4eb-7fca-49a1-b292-d3f9b013d81c.jpeg", - "profile_image_90": "/uploads/user/profile_image/904/b992f4eb-7fca-49a1-b292-d3f9b013d81c.jpeg" + "profile_image": "/uploads/user/profile_image/1228/7dbcd107-d779-4a4c-b827-eefe1f45c76a.jpeg", + "profile_image_90": "/uploads/user/profile_image/1228/7dbcd107-d779-4a4c-b827-eefe1f45c76a.jpeg" }, "schema": { "type": "object", @@ -2558,8 +2566,8 @@ "example": { "result": "create", "category": "like", - "id": 9, - "reactable_id": 632, + "id": 15, + "reactable_id": 515, "reactable_type": "Article" } } @@ -2633,8 +2641,8 @@ "example": { "result": "none", "category": "like", - "id": 11, - "reactable_id": 634, + "id": 17, + "reactable_id": 517, "reactable_type": "Article" } } @@ -2727,19 +2735,19 @@ "application/json": { "example": [ { - "id": 1254, + "id": 2085, "name": "tag7", "bg_color_hex": null, "text_color_hex": null }, { - "id": 1253, + "id": 2084, "name": "tag6", "bg_color_hex": null, "text_color_hex": null }, { - "id": 1252, + "id": 2083, "name": "tag5", "bg_color_hex": null, "text_color_hex": null @@ -2772,16 +2780,16 @@ "application/json": { "example": { "type_of": "user", - "id": 916, + "id": 1240, "username": "username480", - "name": "Dennis \"Rodger\" \\:/ Gorczany", + "name": "Javier \"Dwight\" \\:/ Hand", "twitter_username": "twitter480", "github_username": "github480", "summary": null, "location": null, "website_url": null, - "joined_at": "Feb 27, 2023", - "profile_image": "/uploads/user/profile_image/916/fc0d6dd7-6dee-4df6-9720-ac6618f19fd5.jpeg" + "joined_at": "Mar 30, 2023", + "profile_image": "/uploads/user/profile_image/1240/b9dc6f0b-8622-4e53-9b0f-3fe093b1fa0f.jpeg" }, "schema": { "type": "object", @@ -3020,28 +3028,28 @@ "example": [ { "type_of": "video_article", - "id": 636, - "path": "/username499/i-know-why-the-caged-bird-sings201-4ncl", + "id": 519, + "path": "/username499/alone-on-a-wide-wide-sea201-2jja", "cloudinary_video_url": "https://dw71fyauz7yz9.cloudfront.net/video-upload__1e42eb0bab4abb3c63baeb5e8bdfe69f/thumbs-video-upload__1e42eb0bab4abb3c63baeb5e8bdfe69f-00001.png", - "title": "I Know Why the Caged Bird Sings201", - "user_id": 936, + "title": "Alone on a Wide, Wide Sea201", + "user_id": 1260, "video_duration_in_minutes": "00:00", "video_source_url": "https://dw71fyauz7yz9.cloudfront.net/video-upload__1e42eb0bab4abb3c63baeb5e8bdfe69f/video-upload__1e42eb0bab4abb3c63baeb5e8bdfe69f.m3u8", "user": { - "name": "Kenneth \"Ardelia\" \\:/ Luettgen" + "name": "Lane \"Ed\" \\:/ Erdman" } }, { "type_of": "video_article", - "id": 637, - "path": "/username500/as-i-lay-dying202-1ba2", + "id": 520, + "path": "/username500/great-work-of-time202-289k", "cloudinary_video_url": "https://dw71fyauz7yz9.cloudfront.net/video-upload__1e42eb0bab4abb3c63baeb5e8bdfe69f/thumbs-video-upload__1e42eb0bab4abb3c63baeb5e8bdfe69f-00001.png", - "title": "As I Lay Dying202", - "user_id": 937, + "title": "Great Work of Time202", + "user_id": 1261, "video_duration_in_minutes": "00:00", "video_source_url": "https://dw71fyauz7yz9.cloudfront.net/video-upload__1e42eb0bab4abb3c63baeb5e8bdfe69f/video-upload__1e42eb0bab4abb3c63baeb5e8bdfe69f.m3u8", "user": { - "name": "Fleta \"Alleen\" \\:/ Jerde" + "name": "Willy \"Sabrina\" \\:/ MacGyver" } } ], From d9a61db87777b562b45209c2709644186904dfdd Mon Sep 17 00:00:00 2001 From: Joshua Wehner Date: Thu, 30 Mar 2023 10:02:41 +0200 Subject: [PATCH 05/13] Use exclude_article_ids in query --- app/queries/display_ads/filtered_ads_query.rb | 11 +++++++++- app/views/articles/_sticky_nav.html.erb | 1 + app/views/articles/show.html.erb | 3 ++- .../display_ads/filtered_ads_query_spec.rb | 20 +++++++++++++++++++ 4 files changed, 33 insertions(+), 2 deletions(-) diff --git a/app/queries/display_ads/filtered_ads_query.rb b/app/queries/display_ads/filtered_ads_query.rb index 23d7be96df788..b28407697b871 100644 --- a/app/queries/display_ads/filtered_ads_query.rb +++ b/app/queries/display_ads/filtered_ads_query.rb @@ -5,12 +5,13 @@ def self.call(...) end def initialize(area:, user_signed_in:, organization_id: nil, article_tags: [], - permit_adjacent_sponsors: true, display_ads: DisplayAd) + permit_adjacent_sponsors: true, article_id: nil, display_ads: DisplayAd) @filtered_display_ads = display_ads.includes([:organization]) @area = area @user_signed_in = user_signed_in @organization_id = organization_id @article_tags = article_tags + @article_id = article_id @permit_adjacent_sponsors = permit_adjacent_sponsors end @@ -26,6 +27,10 @@ def call @filtered_display_ads = untagged_post_comment_ads end + if @article_id.present? + @filtered_display_ads = unexcluded_article_ads + end + @filtered_display_ads = if @user_signed_in authenticated_ads(%w[all logged_in]) else @@ -56,6 +61,10 @@ def untagged_post_comment_ads @filtered_display_ads.where(cached_tag_list: "") end + def unexcluded_article_ads + @filtered_display_ads.where("NOT (:id = ANY(exclude_article_ids))", id: @article_id) + end + def authenticated_ads(display_auth_audience) @filtered_display_ads.where(display_to: display_auth_audience) end diff --git a/app/views/articles/_sticky_nav.html.erb b/app/views/articles/_sticky_nav.html.erb index 2b212a6ddf264..fda46aee7a8be 100644 --- a/app/views/articles/_sticky_nav.html.erb +++ b/app/views/articles/_sticky_nav.html.erb @@ -60,6 +60,7 @@ user_signed_in: user_signed_in?, organization_id: @article.organization_id, article_tags: @article.decorate.cached_tag_list_array, + article_id: @article.id, permit_adjacent_sponsors: @article.decorate.permit_adjacent_sponsors?) %> <% if sidebar_ad %>
diff --git a/app/views/articles/show.html.erb b/app/views/articles/show.html.erb index 34a547653e115..fcc1c23490d4e 100644 --- a/app/views/articles/show.html.erb +++ b/app/views/articles/show.html.erb @@ -197,7 +197,8 @@ user_signed_in: user_signed_in?, organization_id: @article.organization_id, permit_adjacent_sponsors: @article.decorate.permit_adjacent_sponsors?, - article_tags: @article.decorate.cached_tag_list_array) %> + article_tags: @article.decorate.cached_tag_list_array), + article_id: @article.id %> <% if @display_ad %>
<%= render partial: "shared/display_ad", locals: { display_ad: @display_ad, data_context_type: DisplayAdEvent::CONTEXT_TYPE_ARTICLE } %> diff --git a/spec/queries/display_ads/filtered_ads_query_spec.rb b/spec/queries/display_ads/filtered_ads_query_spec.rb index 0e76b6c023854..ca44555e864cf 100644 --- a/spec/queries/display_ads/filtered_ads_query_spec.rb +++ b/spec/queries/display_ads/filtered_ads_query_spec.rb @@ -75,6 +75,26 @@ def filter_ads(**options) end end + context "when considering article_exclude_ids" do + let!(:exclude_article1) { create_display_ad exclude_article_ids: "11,12" } + let!(:exclude_article2) { create_display_ad exclude_article_ids: "12,13" } + let!(:no_excludes) { create_display_ad } + + it "will show display ads that exclude articles appropriately" do + filtered = filter_ads article_id: 11 + expect(filtered).to contain_exactly(exclude_article2, no_excludes) + + filtered = filter_ads article_id: 12 + expect(filtered).to contain_exactly(no_excludes) + + filtered = filter_ads article_id: 13 + expect(filtered).to contain_exactly(exclude_article1, no_excludes) + + filtered = filter_ads article_id: 14 + expect(filtered).to contain_exactly(exclude_article1, exclude_article2, no_excludes) + end + end + context "when considering ads with organization_id" do let!(:in_house_ad) { create_display_ad type_of: :in_house } From 819aca72d567ac4e96978dbde2547f6e7cf6b6da Mon Sep 17 00:00:00 2001 From: Joshua Wehner Date: Thu, 30 Mar 2023 14:32:48 +0200 Subject: [PATCH 06/13] Rubocop --- spec/requests/api/v1/docs/display_ads_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/requests/api/v1/docs/display_ads_spec.rb b/spec/requests/api/v1/docs/display_ads_spec.rb index c601adceaba90..5fe863490125f 100644 --- a/spec/requests/api/v1/docs/display_ads_spec.rb +++ b/spec/requests/api/v1/docs/display_ads_spec.rb @@ -69,7 +69,7 @@ description: "Identifies which area of site layout the ad can appear in" }, tag_list: { type: :string, description: "Tags on which this ad can be displayed (blank is all/any tags)" }, article_exclude_ids: { type: :string, - description: "Articles this ad should *not* appear (blank is all/any article), comma-separated list of integer Article IDs" }, + description: "Articles this ad should *not* appear (blank is all/any article), comma-separated list of integer Article IDs" }, # rubocop:disable Layout/LineLength creator_id: { type: :integer, description: "Identifies the user who created the ad." } }, required: %w[name body_markdown placement_area] From bafc9784012743b39c25056349e44dea94d2bbb4 Mon Sep 17 00:00:00 2001 From: Joshua Wehner Date: Thu, 30 Mar 2023 14:34:11 +0200 Subject: [PATCH 07/13] Comment typo --- app/models/display_ad.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/display_ad.rb b/app/models/display_ad.rb index 9251609afbc81..cebef22728cc8 100644 --- a/app/models/display_ad.rb +++ b/app/models/display_ad.rb @@ -89,7 +89,7 @@ def as_json(options = {}) # rubocop:enable Style/OptionHash # exclude_article_ids is an integer array, web inputs are comma-separated strings - # ActiveRecord normalizes these in a bad way, so we've intervening + # ActiveRecord normalizes these in a bad way, so we are intervening def exclude_article_ids=(input) adjusted_input = input.is_a?(String) ? input.split(",") : input adjusted_input = adjusted_input&.filter_map { |value| value.presence&.to_i } From 85ed451d3d524897885520f03271efe8e63b3740 Mon Sep 17 00:00:00 2001 From: Joshua Wehner Date: Thu, 30 Mar 2023 14:36:23 +0200 Subject: [PATCH 08/13] Tweak rspec example length config --- .rubocop.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.rubocop.yml b/.rubocop.yml index 903f1c7b76bbc..4b4dec97a5a6b 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -939,9 +939,7 @@ RSpec/DescribedClassModuleWrapping: RSpec/ExampleLength: Description: Checks for long examples. - Enabled: true - Max: 15 - StyleGuide: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ExampleLength + Enabled: false RSpec/IdenticalEqualityAssertion: Description: Checks for equality assertions with identical expressions on both sides. From 05d5512c2151be9fc57027343f2b67ed1e3e6657 Mon Sep 17 00:00:00 2001 From: Joshua Wehner Date: Thu, 30 Mar 2023 14:48:09 +0200 Subject: [PATCH 09/13] Arguments all the way down --- app/models/display_ad.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/models/display_ad.rb b/app/models/display_ad.rb index cebef22728cc8..2803d3ed8d84a 100644 --- a/app/models/display_ad.rb +++ b/app/models/display_ad.rb @@ -37,12 +37,14 @@ class DisplayAd < ApplicationRecord search: "%#{term}%" } - def self.for_display(area:, user_signed_in:, organization_id: nil, article_tags: [], permit_adjacent_sponsors: true) + def self.for_display(area:, user_signed_in:, organization_id: nil, article_id: nil, + article_tags: [], permit_adjacent_sponsors: true) ads_for_display = DisplayAds::FilteredAdsQuery.call( display_ads: self, area: area, organization_id: organization_id, user_signed_in: user_signed_in, + article_id: article_id, article_tags: article_tags, permit_adjacent_sponsors: permit_adjacent_sponsors, ) From e3c6260a15ab6a5b3e1a750aa8745942431fa4fb Mon Sep 17 00:00:00 2001 From: Joshua Wehner Date: Thu, 30 Mar 2023 14:48:19 +0200 Subject: [PATCH 10/13] Typo --- app/views/articles/show.html.erb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/articles/show.html.erb b/app/views/articles/show.html.erb index fcc1c23490d4e..e8ed56d364031 100644 --- a/app/views/articles/show.html.erb +++ b/app/views/articles/show.html.erb @@ -197,8 +197,8 @@ user_signed_in: user_signed_in?, organization_id: @article.organization_id, permit_adjacent_sponsors: @article.decorate.permit_adjacent_sponsors?, - article_tags: @article.decorate.cached_tag_list_array), - article_id: @article.id %> + article_tags: @article.decorate.cached_tag_list_array, + article_id: @article.id) %> <% if @display_ad %>
<%= render partial: "shared/display_ad", locals: { display_ad: @display_ad, data_context_type: DisplayAdEvent::CONTEXT_TYPE_ARTICLE } %> From c1ba42a419056912fda1671e53df9dcdec7e8c2e Mon Sep 17 00:00:00 2001 From: Joshua Wehner Date: Fri, 31 Mar 2023 09:04:45 +0200 Subject: [PATCH 11/13] Update spec/requests/api/v1/docs/display_ads_spec.rb Co-authored-by: Ben Halpern --- spec/requests/api/v1/docs/display_ads_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/requests/api/v1/docs/display_ads_spec.rb b/spec/requests/api/v1/docs/display_ads_spec.rb index 5fe863490125f..7a939e8cc58c5 100644 --- a/spec/requests/api/v1/docs/display_ads_spec.rb +++ b/spec/requests/api/v1/docs/display_ads_spec.rb @@ -69,7 +69,7 @@ description: "Identifies which area of site layout the ad can appear in" }, tag_list: { type: :string, description: "Tags on which this ad can be displayed (blank is all/any tags)" }, article_exclude_ids: { type: :string, - description: "Articles this ad should *not* appear (blank is all/any article), comma-separated list of integer Article IDs" }, # rubocop:disable Layout/LineLength + description: "Articles this ad should *not* appear (blank means no articles are disallowed, and this ad can appear next to any/all articles). Comma-separated list of integer Article IDs" }, # rubocop:disable Layout/LineLength creator_id: { type: :integer, description: "Identifies the user who created the ad." } }, required: %w[name body_markdown placement_area] From 2fff253ded1f0a55b359e7be646e1b8c9f3e29ea Mon Sep 17 00:00:00 2001 From: Joshua Wehner Date: Fri, 31 Mar 2023 11:49:07 +0200 Subject: [PATCH 12/13] Update spec/requests/api/v1/docs/display_ads_spec.rb Co-authored-by: Ridhwana --- spec/requests/api/v1/docs/display_ads_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/requests/api/v1/docs/display_ads_spec.rb b/spec/requests/api/v1/docs/display_ads_spec.rb index 7a939e8cc58c5..46092abf40bf4 100644 --- a/spec/requests/api/v1/docs/display_ads_spec.rb +++ b/spec/requests/api/v1/docs/display_ads_spec.rb @@ -69,7 +69,7 @@ description: "Identifies which area of site layout the ad can appear in" }, tag_list: { type: :string, description: "Tags on which this ad can be displayed (blank is all/any tags)" }, article_exclude_ids: { type: :string, - description: "Articles this ad should *not* appear (blank means no articles are disallowed, and this ad can appear next to any/all articles). Comma-separated list of integer Article IDs" }, # rubocop:disable Layout/LineLength + description: "Articles this ad should *not* appear on (blank means no articles are disallowed, and this ad can appear next to any/all articles). Comma-separated list of integer Article IDs" }, # rubocop:disable Layout/LineLength creator_id: { type: :integer, description: "Identifies the user who created the ad." } }, required: %w[name body_markdown placement_area] From 8f5acff703c4123a9aed8bd31b976c13e47ba93d Mon Sep 17 00:00:00 2001 From: Joshua Wehner Date: Fri, 31 Mar 2023 12:17:15 +0200 Subject: [PATCH 13/13] Swagger schema for Display Ad --- spec/requests/api/v1/docs/display_ads_spec.rb | 61 +- spec/swagger_helper.rb | 30 + swagger/v1/api_v1.json | 1146 +++++++---------- 3 files changed, 505 insertions(+), 732 deletions(-) diff --git a/spec/requests/api/v1/docs/display_ads_spec.rb b/spec/requests/api/v1/docs/display_ads_spec.rb index 46092abf40bf4..3285f6767c162 100644 --- a/spec/requests/api/v1/docs/display_ads_spec.rb +++ b/spec/requests/api/v1/docs/display_ads_spec.rb @@ -23,6 +23,8 @@ produces "application/json" response(200, "successful") do + schema type: :array, + items: { "$ref": "#/components/schemas/DisplayAd" } let(:"api-key") { api_secret.secret } add_examples @@ -47,33 +49,8 @@ produces "application/json" consumes "application/json" - parameter name: :display_ad, in: :body, schema: { - type: :object, - properties: { - name: { type: :string, description: "For internal use, helps distinguish ads from one another" }, - body_markdown: { type: :string, description: "The text (in markdown) of the ad (required)" }, - approved: { type: :boolean, description: "Ad must be both published and approved to be in rotation" }, - published: { type: :boolean, description: "Ad must be both published and approved to be in rotation" }, - organization_id: { type: :integer, description: "Identifies the organization to which the ad belongs" }, - display_to: { type: :string, enum: DisplayAd.display_tos.keys, default: "all", - description: "Potentially limits visitors to whom the ad is visible" }, - type_of: { type: :string, enum: DisplayAd.type_ofs.keys, default: "in_house", - description: <<~DESCRIBE - Types of the billboards: - in_house (created by admins), - community (created by an entity, appears on entity's content), - external ( created by an entity, or a non-entity, can appear everywhere) - DESCRIBE - }, - placement_area: { type: :string, enum: DisplayAd::ALLOWED_PLACEMENT_AREAS, - description: "Identifies which area of site layout the ad can appear in" }, - tag_list: { type: :string, description: "Tags on which this ad can be displayed (blank is all/any tags)" }, - article_exclude_ids: { type: :string, - description: "Articles this ad should *not* appear on (blank means no articles are disallowed, and this ad can appear next to any/all articles). Comma-separated list of integer Article IDs" }, # rubocop:disable Layout/LineLength - creator_id: { type: :integer, description: "Identifies the user who created the ad." } - }, - required: %w[name body_markdown placement_area] - } + parameter name: :display_ad, in: :body, schema: { type: :object, + items: { "$ref": "#/components/schemas/DisplayAd" } } let(:display_ad) do { @@ -89,6 +66,8 @@ let(:placement_area) { "post_comments" } response(200, "successful") do + schema type: :object, + items: { "$ref": "#/components/schemas/DisplayAd" } let(:"api-key") { api_secret.secret } add_examples @@ -125,7 +104,7 @@ parameter name: :id, in: :path, required: true, - description: "The ID of the user to unpublish.", + description: "The ID of the display ad.", schema: { type: :integer, format: :int32, @@ -172,7 +151,7 @@ parameter name: :id, in: :path, required: true, - description: "The ID of the user to unpublish.", + description: "The ID of the display ad.", schema: { type: :integer, format: :int32, @@ -180,28 +159,14 @@ }, example: 123 - parameter name: :display_ad, in: :body, schema: { - type: :object, - properties: { - name: { type: :string, description: "For internal use, helps distinguish ads from one another" }, - body_markdown: { type: :string, description: "The text (in markdown) of the ad (required)" }, - approved: { type: :boolean, description: "Ad must be both published and approved to be in rotation" }, - published: { type: :boolean, description: "Ad must be both published and approved to be in rotation" }, - organization_id: { type: :integer, - description: "Identifies the organization to which the ad belongs, required for 'community' type ads" }, # rubocop:disable Layout/LineLength - display_to: { type: :string, enum: DisplayAd.display_tos.keys, default: "all", - description: "Potentially limits visitors to whom the ad is visible" }, - placement_area: { type: :string, enum: DisplayAd::ALLOWED_PLACEMENT_AREAS, - description: "Identifies which area of site layout the ad can appear in" }, - tag_list: { type: :string, description: "Tags on which this ad can be displayed (blank is all/any tags)" }, - creator_id: { type: :integer, description: "Identifies the user who created the ad." } - }, - required: %w[name body_markdown placement_area] - } + parameter name: :display_ad, in: :body, schema: { type: :object, + items: { "$ref": "#/components/schemas/DisplayAd" } } let(:placement_area) { "post_comments" } response(200, "successful") do + schema type: :object, + items: { "$ref": "#/components/schemas/DisplayAd" } let(:"api-key") { api_secret.secret } let(:id) { display_ad.id } add_examples @@ -241,7 +206,7 @@ parameter name: :id, in: :path, required: true, - description: "The ID of the user to unpublish.", + description: "The ID of the display ad to unpublish.", schema: { type: :integer, format: :int32, diff --git a/spec/swagger_helper.rb b/spec/swagger_helper.rb index 6f228acd4deb4..815dc2ef81660 100644 --- a/spec/swagger_helper.rb +++ b/spec/swagger_helper.rb @@ -397,6 +397,36 @@ email: { type: :string }, name: { type: :string, nullable: true } } + }, + DisplayAd: { + description: "A Display Ad, aka Billboard, aka Widget", + type: :object, + properties: { + id: { type: :integer, description: "The ID of the Display Ad" }, + name: { type: :string, description: "For internal use, helps distinguish ads from one another" }, + body_markdown: { type: :string, description: "The text (in markdown) of the ad (required)" }, + approved: { type: :boolean, description: "Ad must be both published and approved to be in rotation" }, + published: { type: :boolean, description: "Ad must be both published and approved to be in rotation" }, + organization_id: { type: :integer, description: "Identifies the organization to which the ad belongs", nullable: true }, + creator_id: { type: :integer, description: "Identifies the user who created the ad.", nullable: true }, + placement_area: { type: :string, enum: DisplayAd::ALLOWED_PLACEMENT_AREAS, + description: "Identifies which area of site layout the ad can appear in" }, + tag_list: { type: :string, description: "Tags on which this ad can be displayed (blank is all/any tags)" }, + article_exclude_ids: { type: :string, + nullable: true, + description: "Articles this ad should *not* appear on (blank means no articles are disallowed, and this ad can appear next to any/all articles). Comma-separated list of integer Article IDs" }, # rubocop:disable Layout/LineLength + display_to: { type: :string, enum: DisplayAd.display_tos.keys, default: "all", + description: "Potentially limits visitors to whom the ad is visible" }, + type_of: { type: :string, enum: DisplayAd.type_ofs.keys, default: "in_house", + description: <<~DESCRIBE + Types of the billboards: + in_house (created by admins), + community (created by an entity, appears on entity's content), + external ( created by an entity, or a non-entity, can appear everywhere) + DESCRIBE + } + }, + required: %w[name body_markdown placement_area] } } } diff --git a/swagger/v1/api_v1.json b/swagger/v1/api_v1.json index dc62dfc9e3f4a..080de11f685d9 100644 --- a/swagger/v1/api_v1.json +++ b/swagger/v1/api_v1.json @@ -9,14 +9,10 @@ "/api/articles": { "post": { "summary": "Publish article", - "tags": [ - "articles" - ], + "tags": ["articles"], "description": "This endpoint allows the client to create a new article.\n\n\"Articles\" are all the posts that users create on DEV that typically show up in the feed. They can be a blog post, a discussion question, a help thread etc. but is referred to as article within the code.", "operationId": "createArticle", - "parameters": [ - - ], + "parameters": [], "responses": { "201": { "description": "An Article", @@ -24,42 +20,40 @@ "application/json": { "example": { "type_of": "article", - "id": 490, + "id": 788, "title": "New article", "description": "New post example", - "readable_publish_date": "Mar 30", - "slug": "new-article-2fi7", - "path": "/username383/new-article-2fi7", - "url": "http://localhost:3000/username383/new-article-2fi7", + "readable_publish_date": "Mar 31", + "slug": "new-article-60h", + "path": "/username383/new-article-60h", + "url": "http://localhost:3000/username383/new-article-60h", "comments_count": 0, "public_reactions_count": 0, - "collection_id": 22, - "published_timestamp": "2023-03-30T07:50:19Z", + "collection_id": 33, + "published_timestamp": "2023-03-31T10:15:43Z", "positive_reactions_count": 0, "cover_image": "https://thepracticaldev.s3.amazonaws.com/i/5wfo25724gzgk5e5j50g.jpg", "social_image": "https://thepracticaldev.s3.amazonaws.com/i/5wfo25724gzgk5e5j50g.jpg", "canonical_url": "https://dev.to/fdocr/headless-chrome-dual-mode-tests-for-ruby-on-rails-4p6g", - "created_at": "2023-03-30T07:50:19Z", + "created_at": "2023-03-31T10:15:43Z", "edited_at": null, "crossposted_at": null, - "published_at": "2023-03-30T07:50:19Z", - "last_comment_at": "2023-03-30T07:50:19Z", + "published_at": "2023-03-31T10:15:43Z", + "last_comment_at": "2023-03-31T10:15:43Z", "reading_time_minutes": 1, "tag_list": "", - "tags": [ - - ], + "tags": [], "body_html": "

New body for the article

\n\n", "body_markdown": "**New** body for the article", "user": { - "name": "Chester \"Norah\" \\:/ O'Reilly", + "name": "Geraldo \"Linwood\" \\:/ Hoeger", "username": "username383", "twitter_username": "twitter383", "github_username": "github383", - "user_id": 1143, + "user_id": 1978, "website_url": null, - "profile_image": "/uploads/user/profile_image/1143/016564ce-c63d-4e33-9746-2d6298502f4f.jpeg", - "profile_image_90": "/uploads/user/profile_image/1143/016564ce-c63d-4e33-9746-2d6298502f4f.jpeg" + "profile_image": "/uploads/user/profile_image/1978/0e99ce88-e824-408e-b0eb-ecaff3550d31.jpeg", + "profile_image_90": "/uploads/user/profile_image/1978/0e99ce88-e824-408e-b0eb-ecaff3550d31.jpeg" } } } @@ -100,12 +94,8 @@ }, "get": { "summary": "Published articles", - "security": [ - - ], - "tags": [ - "articles" - ], + "security": [], + "tags": ["articles"], "description": "This endpoint allows the client to retrieve a list of articles.\n\n\"Articles\" are all the posts that users create on DEV that typically\nshow up in the feed. They can be a blog post, a discussion question,\na help thread etc. but is referred to as article within the code.\n\nBy default it will return featured, published articles ordered\nby descending popularity.\n\nIt supports pagination, each page will contain `30` articles by default.", "operationId": "getArticles", "parameters": [ @@ -162,11 +152,7 @@ "description": "Using this parameter will allow the client to check which articles are fresh or rising.\n If `state=fresh` the server will return fresh articles.\n If `state=rising` the server will return rising articles.\n This param can be used in conjuction with `username`, only if set to `all`.", "schema": { "type": "string", - "enum": [ - "fresh", - "rising", - "all" - ] + "enum": ["fresh", "rising", "all"] }, "example": "fresh" }, @@ -202,47 +188,45 @@ "example": [ { "type_of": "article", - "id": 493, - "title": "Vile Bodies175", - "description": "Actually photo booth occupy semiotics whatever gentrify tumblr. Narwhal forage pour-over portland....", - "readable_publish_date": "Mar 30", - "slug": "vile-bodies175-54a4", - "path": "/username387/vile-bodies175-54a4", - "url": "http://localhost:3000/username387/vile-bodies175-54a4", + "id": 791, + "title": "The Moving Finger175", + "description": "Artisan raw denim pinterest art party gluten-free butcher chia photo booth. Messenger bag gastropub...", + "readable_publish_date": "Mar 31", + "slug": "the-moving-finger175-2jmn", + "path": "/username387/the-moving-finger175-2jmn", + "url": "http://localhost:3000/username387/the-moving-finger175-2jmn", "comments_count": 0, "public_reactions_count": 0, "collection_id": null, - "published_timestamp": "2023-03-30T07:50:19Z", + "published_timestamp": "2023-03-31T10:15:43Z", "positive_reactions_count": 0, - "cover_image": "http://localhost:3000/assets/11-f4a704eef06d25d2d2fa2026ef08f1089754beaf5b6ee01160115d3c36ed3d34.png", - "social_image": "http://localhost:3000/assets/11-f4a704eef06d25d2d2fa2026ef08f1089754beaf5b6ee01160115d3c36ed3d34.png", - "canonical_url": "http://localhost:3000/username387/vile-bodies175-54a4", - "created_at": "2023-03-30T07:50:19Z", + "cover_image": "http://localhost:3000/assets/23-33ea5a2b5af3dc15b9ed90de0b850f67e2390eaec3361d6687d3b9750c699f84.png", + "social_image": "http://localhost:3000/assets/23-33ea5a2b5af3dc15b9ed90de0b850f67e2390eaec3361d6687d3b9750c699f84.png", + "canonical_url": "http://localhost:3000/username387/the-moving-finger175-2jmn", + "created_at": "2023-03-31T10:15:43Z", "edited_at": null, "crossposted_at": null, - "published_at": "2023-03-30T07:50:19Z", - "last_comment_at": "2023-03-30T07:50:19Z", + "published_at": "2023-03-31T10:15:43Z", + "last_comment_at": "2023-03-31T10:15:43Z", "reading_time_minutes": 1, - "tag_list": [ - "discuss" - ], + "tag_list": ["discuss"], "tags": "discuss", "user": { - "name": "Kim \"Tresa\" \\:/ Pagac", + "name": "Aron \"Ivan\" \\:/ Shanahan", "username": "username387", "twitter_username": "twitter387", "github_username": "github387", - "user_id": 1147, + "user_id": 1982, "website_url": null, - "profile_image": "/uploads/user/profile_image/1147/38003cae-b483-4bf3-b77d-e4a73938e17e.jpeg", - "profile_image_90": "/uploads/user/profile_image/1147/38003cae-b483-4bf3-b77d-e4a73938e17e.jpeg" + "profile_image": "/uploads/user/profile_image/1982/3a581727-fe5a-4aed-b98c-6de7efbf3334.jpeg", + "profile_image_90": "/uploads/user/profile_image/1982/3a581727-fe5a-4aed-b98c-6de7efbf3334.jpeg" }, "organization": { - "name": "Klein, Larson and Stamm", + "name": "Gerlach-Kemmer", "username": "org70", "slug": "org70", - "profile_image": "/uploads/organization/profile_image/1031/c3696c92-ad67-42cd-98be-052639c43106.png", - "profile_image_90": "/uploads/organization/profile_image/1031/c3696c92-ad67-42cd-98be-052639c43106.png" + "profile_image": "/uploads/organization/profile_image/439/05d7686f-381b-4db9-a4a5-3b449718c75f.png", + "profile_image_90": "/uploads/organization/profile_image/439/05d7686f-381b-4db9-a4a5-3b449718c75f.png" }, "flare_tag": { "name": "discuss", @@ -266,12 +250,8 @@ "/api/articles/latest": { "get": { "summary": "Published articles sorted by published date", - "security": [ - - ], - "tags": [ - "articles" - ], + "security": [], + "tags": ["articles"], "description": "This endpoint allows the client to retrieve a list of articles. ordered by descending publish date.\n\nIt supports pagination, each page will contain 30 articles by default.", "operationId": "getLatestArticles", "parameters": [ @@ -290,42 +270,38 @@ "example": [ { "type_of": "article", - "id": 496, - "title": "The Needle's Eye178", - "description": "Next level fanny pack pork belly flannel heirloom hammock yr direct trade. Biodiesel occupy etsy....", - "readable_publish_date": "Mar 30", - "slug": "the-needles-eye178-3j1i", - "path": "/username390/the-needles-eye178-3j1i", - "url": "http://localhost:3000/username390/the-needles-eye178-3j1i", + "id": 794, + "title": "Behold the Man178", + "description": "Intelligentsia mumblecore williamsburg farm-to-table echo truffaut celiac vinegar. Bespoke chia...", + "readable_publish_date": "Mar 31", + "slug": "behold-the-man178-2n8g", + "path": "/username390/behold-the-man178-2n8g", + "url": "http://localhost:3000/username390/behold-the-man178-2n8g", "comments_count": 0, "public_reactions_count": 0, "collection_id": null, - "published_timestamp": "2023-03-30T07:50:19Z", + "published_timestamp": "2023-03-31T10:15:43Z", "positive_reactions_count": 0, - "cover_image": "http://localhost:3000/assets/19-ed58d3e8defcefc445020631589697a05e725243e834b5192aee4e6b91a3e927.png", - "social_image": "http://localhost:3000/assets/19-ed58d3e8defcefc445020631589697a05e725243e834b5192aee4e6b91a3e927.png", - "canonical_url": "http://localhost:3000/username390/the-needles-eye178-3j1i", - "created_at": "2023-03-30T07:50:19Z", + "cover_image": "http://localhost:3000/assets/21-8c16e6ef44da175a1e51f1ba9d0cb55af8a920db6aacbf1e4b7a055afc1b3d30.png", + "social_image": "http://localhost:3000/assets/21-8c16e6ef44da175a1e51f1ba9d0cb55af8a920db6aacbf1e4b7a055afc1b3d30.png", + "canonical_url": "http://localhost:3000/username390/behold-the-man178-2n8g", + "created_at": "2023-03-31T10:15:43Z", "edited_at": null, "crossposted_at": null, - "published_at": "2023-03-30T07:50:19Z", - "last_comment_at": "2023-03-30T07:50:19Z", + "published_at": "2023-03-31T10:15:43Z", + "last_comment_at": "2023-03-31T10:15:43Z", "reading_time_minutes": 1, - "tag_list": [ - "javascript", - "html", - "discuss" - ], + "tag_list": ["javascript", "html", "discuss"], "tags": "javascript, html, discuss", "user": { - "name": "Elva \"Daniel\" \\:/ Bode", + "name": "Hee \"Margret\" \\:/ Schowalter", "username": "username390", "twitter_username": "twitter390", "github_username": "github390", - "user_id": 1150, + "user_id": 1985, "website_url": null, - "profile_image": "/uploads/user/profile_image/1150/ef4bb832-1dc2-4c15-87c9-7f1561563cdf.jpeg", - "profile_image_90": "/uploads/user/profile_image/1150/ef4bb832-1dc2-4c15-87c9-7f1561563cdf.jpeg" + "profile_image": "/uploads/user/profile_image/1985/25091728-8afd-492c-b6ca-751c500c9eba.jpeg", + "profile_image_90": "/uploads/user/profile_image/1985/25091728-8afd-492c-b6ca-751c500c9eba.jpeg" }, "flare_tag": { "name": "discuss", @@ -335,42 +311,38 @@ }, { "type_of": "article", - "id": 495, - "title": "The Heart Is Deceitful Above All Things177", - "description": "Forage loko neutra. Gentrify meh cold-pressed roof distillery etsy. Keffiyeh knausgaard pour-over...", - "readable_publish_date": "Mar 30", - "slug": "the-heart-is-deceitful-above-all-things177-47p4", - "path": "/username389/the-heart-is-deceitful-above-all-things177-47p4", - "url": "http://localhost:3000/username389/the-heart-is-deceitful-above-all-things177-47p4", + "id": 793, + "title": "Time To Murder And Create177", + "description": "Kitsch cliche occupy. Brunch godard goth. Food truck venmo hella. Asymmetrical gastropub heirloom...", + "readable_publish_date": "Mar 31", + "slug": "time-to-murder-and-create177-4bgk", + "path": "/username389/time-to-murder-and-create177-4bgk", + "url": "http://localhost:3000/username389/time-to-murder-and-create177-4bgk", "comments_count": 0, "public_reactions_count": 0, "collection_id": null, - "published_timestamp": "2023-03-30T07:50:19Z", + "published_timestamp": "2023-03-31T10:15:43Z", "positive_reactions_count": 0, - "cover_image": "http://localhost:3000/assets/4-dcfcc4d8dd259bc0751c2de24b1cf244b181c789934368ca1cb471f0944b695d.png", - "social_image": "http://localhost:3000/assets/4-dcfcc4d8dd259bc0751c2de24b1cf244b181c789934368ca1cb471f0944b695d.png", - "canonical_url": "http://localhost:3000/username389/the-heart-is-deceitful-above-all-things177-47p4", - "created_at": "2023-03-30T07:50:19Z", + "cover_image": "http://localhost:3000/assets/15-680d1f40ea6901cfc18b12fab21c19e432463aa63a44853f8ad84e469adb2e54.png", + "social_image": "http://localhost:3000/assets/15-680d1f40ea6901cfc18b12fab21c19e432463aa63a44853f8ad84e469adb2e54.png", + "canonical_url": "http://localhost:3000/username389/time-to-murder-and-create177-4bgk", + "created_at": "2023-03-31T10:15:43Z", "edited_at": null, "crossposted_at": null, - "published_at": "2023-03-30T07:50:19Z", - "last_comment_at": "2023-03-30T07:50:19Z", + "published_at": "2023-03-31T10:15:43Z", + "last_comment_at": "2023-03-31T10:15:43Z", "reading_time_minutes": 1, - "tag_list": [ - "javascript", - "html", - "discuss" - ], + "tag_list": ["javascript", "html", "discuss"], "tags": "javascript, html, discuss", "user": { - "name": "Antonio \"Clifford\" \\:/ Beahan", + "name": "Curt \"Jimmy\" \\:/ Keeling", "username": "username389", "twitter_username": "twitter389", "github_username": "github389", - "user_id": 1149, + "user_id": 1984, "website_url": null, - "profile_image": "/uploads/user/profile_image/1149/5eece559-3df5-4fce-8e02-d204208303fb.jpeg", - "profile_image_90": "/uploads/user/profile_image/1149/5eece559-3df5-4fce-8e02-d204208303fb.jpeg" + "profile_image": "/uploads/user/profile_image/1984/d22d15d8-337d-41c1-b5d3-2f2ed6898234.jpeg", + "profile_image_90": "/uploads/user/profile_image/1984/d22d15d8-337d-41c1-b5d3-2f2ed6898234.jpeg" }, "flare_tag": { "name": "discuss", @@ -380,42 +352,38 @@ }, { "type_of": "article", - "id": 494, - "title": "Carrion Comfort176", - "description": "Etsy quinoa tote bag blue bottle austin vice. Wolf slow-carb ethical. Vinyl single-origin coffee...", - "readable_publish_date": "Mar 30", - "slug": "carrion-comfort176-35c4", - "path": "/username388/carrion-comfort176-35c4", - "url": "http://localhost:3000/username388/carrion-comfort176-35c4", + "id": 792, + "title": "Ah, Wilderness!176", + "description": "Cliche beard vinegar retro xoxo godard five dollar toast. Cleanse small batch godard cold-pressed....", + "readable_publish_date": "Mar 31", + "slug": "ah-wilderness176-4o72", + "path": "/username388/ah-wilderness176-4o72", + "url": "http://localhost:3000/username388/ah-wilderness176-4o72", "comments_count": 0, "public_reactions_count": 0, "collection_id": null, - "published_timestamp": "2023-03-30T07:50:19Z", + "published_timestamp": "2023-03-31T10:15:43Z", "positive_reactions_count": 0, - "cover_image": "http://localhost:3000/assets/20-92231c1d2ddb3b707b8c1b5cb711ef17632ff2a64495970a58518ce33c3a4f76.png", - "social_image": "http://localhost:3000/assets/20-92231c1d2ddb3b707b8c1b5cb711ef17632ff2a64495970a58518ce33c3a4f76.png", - "canonical_url": "http://localhost:3000/username388/carrion-comfort176-35c4", - "created_at": "2023-03-30T07:50:19Z", + "cover_image": "http://localhost:3000/assets/24-377bc0861a9a539e8d1875ea9d4eea9e0226d93e1b6e9317e0c73c754699cc14.png", + "social_image": "http://localhost:3000/assets/24-377bc0861a9a539e8d1875ea9d4eea9e0226d93e1b6e9317e0c73c754699cc14.png", + "canonical_url": "http://localhost:3000/username388/ah-wilderness176-4o72", + "created_at": "2023-03-31T10:15:43Z", "edited_at": null, "crossposted_at": null, - "published_at": "2023-03-30T07:50:19Z", - "last_comment_at": "2023-03-30T07:50:19Z", + "published_at": "2023-03-31T10:15:43Z", + "last_comment_at": "2023-03-31T10:15:43Z", "reading_time_minutes": 1, - "tag_list": [ - "javascript", - "html", - "discuss" - ], + "tag_list": ["javascript", "html", "discuss"], "tags": "javascript, html, discuss", "user": { - "name": "Allene \"Denita\" \\:/ Kilback", + "name": "Julissa \"Morgan\" \\:/ Will", "username": "username388", "twitter_username": "twitter388", "github_username": "github388", - "user_id": 1148, + "user_id": 1983, "website_url": null, - "profile_image": "/uploads/user/profile_image/1148/5fa0ee05-bfe8-43a8-9351-b4e09f12dc8e.jpeg", - "profile_image_90": "/uploads/user/profile_image/1148/5fa0ee05-bfe8-43a8-9351-b4e09f12dc8e.jpeg" + "profile_image": "/uploads/user/profile_image/1983/6f103fac-9341-4c9f-88ee-12782d8e45ad.jpeg", + "profile_image_90": "/uploads/user/profile_image/1983/6f103fac-9341-4c9f-88ee-12782d8e45ad.jpeg" }, "flare_tag": { "name": "discuss", @@ -439,12 +407,8 @@ "/api/articles/{id}": { "get": { "summary": "Published article by id", - "security": [ - - ], - "tags": [ - "articles" - ], + "security": [], + "tags": ["articles"], "description": "This endpoint allows the client to retrieve a single published article given its `id`.", "operationId": "getArticleById", "parameters": [ @@ -464,42 +428,40 @@ "application/json": { "example": { "type_of": "article", - "id": 497, - "title": "Dance Dance Dance179", - "description": "Helvetica slow-carb shabby chic mlkshk. Bitters pop-up readymade waistcoat. Tote bag chicharrones...", - "readable_publish_date": "Mar 30", - "slug": "dance-dance-dance179-265m", - "path": "/username391/dance-dance-dance179-265m", - "url": "http://localhost:3000/username391/dance-dance-dance179-265m", + "id": 795, + "title": "His Dark Materials179", + "description": "Umami salvia park green juice. Waistcoat fanny pack squid letterpress shoreditch. Park pop-up tilde...", + "readable_publish_date": "Mar 31", + "slug": "his-dark-materials179-34fi", + "path": "/username391/his-dark-materials179-34fi", + "url": "http://localhost:3000/username391/his-dark-materials179-34fi", "comments_count": 0, "public_reactions_count": 0, "collection_id": null, - "published_timestamp": "2023-03-30T07:50:20Z", + "published_timestamp": "2023-03-31T10:15:43Z", "positive_reactions_count": 0, - "cover_image": "http://localhost:3000/assets/3-93b6b57b5a6115cffe5d63d29a22825eb9e65f647bfef57a88244bc2b98186f0.png", - "social_image": "http://localhost:3000/assets/3-93b6b57b5a6115cffe5d63d29a22825eb9e65f647bfef57a88244bc2b98186f0.png", - "canonical_url": "http://localhost:3000/username391/dance-dance-dance179-265m", - "created_at": "2023-03-30T07:50:20Z", + "cover_image": "http://localhost:3000/assets/40-57aabe055a9fc60491e0fca9a4dade362141764e7ad214956bbfc9c9e69763b0.png", + "social_image": "http://localhost:3000/assets/40-57aabe055a9fc60491e0fca9a4dade362141764e7ad214956bbfc9c9e69763b0.png", + "canonical_url": "http://localhost:3000/username391/his-dark-materials179-34fi", + "created_at": "2023-03-31T10:15:43Z", "edited_at": null, "crossposted_at": null, - "published_at": "2023-03-30T07:50:20Z", - "last_comment_at": "2023-03-30T07:50:20Z", + "published_at": "2023-03-31T10:15:43Z", + "last_comment_at": "2023-03-31T10:15:43Z", "reading_time_minutes": 1, "tag_list": "discuss", - "tags": [ - "discuss" - ], - "body_html": "

Helvetica slow-carb shabby chic mlkshk. Bitters pop-up readymade waistcoat. Tote bag chicharrones muggle magic ennui whatever photo booth small batch. Hammock drinking humblebrag 90's letterpress.

\n\n

Pinterest pour-over trust fund banh mi.

\n\n", - "body_markdown": "---\ntitle: Dance Dance Dance179\npublished: true\ntags: discuss\ndate: \nseries: \ncanonical_url: \n\n---\n\nHelvetica slow-carb shabby chic mlkshk. Bitters pop-up readymade waistcoat. Tote bag chicharrones muggle magic ennui whatever photo booth small batch. Hammock drinking humblebrag 90's letterpress.\n\n\nPinterest pour-over trust fund banh mi.\n\n", + "tags": ["discuss"], + "body_html": "

Umami salvia park green juice. Waistcoat fanny pack squid letterpress shoreditch. Park pop-up tilde post-ironic williamsburg vegan. Pork belly master chicharrones leggings readymade street.

\n\n

Phlogiston park pinterest kombucha yolo master schlitz. Cred cliche lomo williamsburg taxidermy. Iphone keffiyeh distillery loko microdosing echo yuccie.

\n\n", + "body_markdown": "---\ntitle: His Dark Materials179\npublished: true\ntags: discuss\ndate: \nseries: \ncanonical_url: \n\n---\n\nUmami salvia park green juice. Waistcoat fanny pack squid letterpress shoreditch. Park pop-up tilde post-ironic williamsburg vegan. Pork belly master chicharrones leggings readymade street.\n\n\nPhlogiston park pinterest kombucha yolo master schlitz. Cred cliche lomo williamsburg taxidermy. Iphone keffiyeh distillery loko microdosing echo yuccie.\n\n", "user": { - "name": "Doreen \"Melvina\" \\:/ Kerluke", + "name": "China \"Joan\" \\:/ Gibson", "username": "username391", "twitter_username": "twitter391", "github_username": "github391", - "user_id": 1151, + "user_id": 1986, "website_url": null, - "profile_image": "/uploads/user/profile_image/1151/317b32a2-0a5a-4fb4-9c1f-82c2de66b782.jpeg", - "profile_image_90": "/uploads/user/profile_image/1151/317b32a2-0a5a-4fb4-9c1f-82c2de66b782.jpeg" + "profile_image": "/uploads/user/profile_image/1986/2f8cfd04-ad24-4672-8205-891ef0768278.jpeg", + "profile_image_90": "/uploads/user/profile_image/1986/2f8cfd04-ad24-4672-8205-891ef0768278.jpeg" }, "flare_tag": { "name": "discuss", @@ -531,9 +493,7 @@ }, "put": { "summary": "Update an article by id", - "tags": [ - "articles" - ], + "tags": ["articles"], "description": "This endpoint allows the client to update an existing article.\n\n\"Articles\" are all the posts that users create on DEV that typically show up in the feed. They can be a blog post, a discussion question, a help thread etc. but is referred to as article within the code.", "operationId": "updateArticle", "parameters": [ @@ -557,42 +517,40 @@ "application/json": { "example": { "type_of": "article", - "id": 498, - "title": "The Wings of the Dove180", - "description": "Swag umami everyday williamsburg squid knausgaard neutra. Ramps flexitarian pabst dreamcatcher...", - "readable_publish_date": "Mar 30", - "slug": "the-wings-of-the-dove180-57c4", - "path": "/username392/the-wings-of-the-dove180-57c4", - "url": "http://localhost:3000/username392/the-wings-of-the-dove180-57c4", + "id": 796, + "title": "Where Angels Fear to Tread180", + "description": "Freegan portland chicharrones. Whatever flannel hammock sustainable yr lomo. Pork belly fashion axe...", + "readable_publish_date": "Mar 31", + "slug": "where-angels-fear-to-tread180-8l9", + "path": "/username392/where-angels-fear-to-tread180-8l9", + "url": "http://localhost:3000/username392/where-angels-fear-to-tread180-8l9", "comments_count": 0, "public_reactions_count": 0, "collection_id": null, - "published_timestamp": "2023-03-30T07:50:20Z", + "published_timestamp": "2023-03-31T10:15:44Z", "positive_reactions_count": 0, - "cover_image": "http://localhost:3000/assets/39-20fc2599938fbd7c41146577147aa7c6925e3b8ff069aba58c9304bc1b944cf1.png", - "social_image": "http://localhost:3000/assets/39-20fc2599938fbd7c41146577147aa7c6925e3b8ff069aba58c9304bc1b944cf1.png", - "canonical_url": "http://localhost:3000/username392/the-wings-of-the-dove180-57c4", - "created_at": "2023-03-30T07:50:20Z", - "edited_at": "2023-03-30T07:50:20Z", + "cover_image": "http://localhost:3000/assets/22-837b6c737e37b6d229b36d73e95ead7f26e0a346e0aa7dfbca74630ae161fb0d.png", + "social_image": "http://localhost:3000/assets/22-837b6c737e37b6d229b36d73e95ead7f26e0a346e0aa7dfbca74630ae161fb0d.png", + "canonical_url": "http://localhost:3000/username392/where-angels-fear-to-tread180-8l9", + "created_at": "2023-03-31T10:15:44Z", + "edited_at": "2023-03-31T10:15:44Z", "crossposted_at": null, - "published_at": "2023-03-30T07:50:20Z", - "last_comment_at": "2023-03-30T07:50:20Z", + "published_at": "2023-03-31T10:15:44Z", + "last_comment_at": "2023-03-31T10:15:44Z", "reading_time_minutes": 1, "tag_list": "", - "tags": [ - - ], + "tags": [], "body_html": "

New body for the article

\n\n", "body_markdown": "**New** body for the article", "user": { - "name": "Emil \"Nettie\" \\:/ Denesik", + "name": "Tommie \"Joleen\" \\:/ Ryan", "username": "username392", "twitter_username": "twitter392", "github_username": "github392", - "user_id": 1152, + "user_id": 1987, "website_url": null, - "profile_image": "/uploads/user/profile_image/1152/9cd5a7a0-243c-4394-bc26-95614664188c.jpeg", - "profile_image_90": "/uploads/user/profile_image/1152/9cd5a7a0-243c-4394-bc26-95614664188c.jpeg" + "profile_image": "/uploads/user/profile_image/1987/fff4ff85-f32d-4840-99e1-7737e12da3d7.jpeg", + "profile_image_90": "/uploads/user/profile_image/1987/fff4ff85-f32d-4840-99e1-7737e12da3d7.jpeg" } } } @@ -646,12 +604,8 @@ "/api/articles/{username}/{slug}": { "get": { "summary": "Published article by path", - "security": [ - - ], - "tags": [ - "articles" - ], + "security": [], + "tags": ["articles"], "description": "This endpoint allows the client to retrieve a single published article given its `path`.", "operationId": "getArticleByPath", "parameters": [ @@ -679,42 +633,40 @@ "application/json": { "example": { "type_of": "article", - "id": 501, - "title": "A Scanner Darkly183", - "description": "Blue bottle marfa muggle magic. Synth brunch letterpress franzen kitsch 3 wolf moon everyday. Tumblr...", - "readable_publish_date": "Mar 30", - "slug": "a-scanner-darkly183-3mp3", - "path": "/username396/a-scanner-darkly183-3mp3", - "url": "http://localhost:3000/username396/a-scanner-darkly183-3mp3", + "id": 799, + "title": "Dance Dance Dance183", + "description": "Tilde cronut meggings. Flannel crucifix vice put a bird on it pork belly everyday. Squid swag park....", + "readable_publish_date": "Mar 31", + "slug": "dance-dance-dance183-2095", + "path": "/username396/dance-dance-dance183-2095", + "url": "http://localhost:3000/username396/dance-dance-dance183-2095", "comments_count": 0, "public_reactions_count": 0, "collection_id": null, - "published_timestamp": "2023-03-30T07:50:20Z", + "published_timestamp": "2023-03-31T10:15:44Z", "positive_reactions_count": 0, - "cover_image": "http://localhost:3000/assets/32-543e7c7f0a939e829c37aab48d705350b855c887dc16dfab30fd9a0825c09291.png", - "social_image": "http://localhost:3000/assets/32-543e7c7f0a939e829c37aab48d705350b855c887dc16dfab30fd9a0825c09291.png", - "canonical_url": "http://localhost:3000/username396/a-scanner-darkly183-3mp3", - "created_at": "2023-03-30T07:50:20Z", + "cover_image": "http://localhost:3000/assets/8-915172672c34364d29c3fce07afa413c1ac072beff54ddd79fc7e3ed633556a1.png", + "social_image": "http://localhost:3000/assets/8-915172672c34364d29c3fce07afa413c1ac072beff54ddd79fc7e3ed633556a1.png", + "canonical_url": "http://localhost:3000/username396/dance-dance-dance183-2095", + "created_at": "2023-03-31T10:15:44Z", "edited_at": null, "crossposted_at": null, - "published_at": "2023-03-30T07:50:20Z", - "last_comment_at": "2023-03-30T07:50:20Z", + "published_at": "2023-03-31T10:15:44Z", + "last_comment_at": "2023-03-31T10:15:44Z", "reading_time_minutes": 1, "tag_list": "discuss", - "tags": [ - "discuss" - ], - "body_html": "

Blue bottle marfa muggle magic. Synth brunch letterpress franzen kitsch 3 wolf moon everyday.

\n\n

Tumblr migas deep v street. Tumblr yuccie muggle magic crucifix actually forage.

\n\n", - "body_markdown": "---\ntitle: A Scanner Darkly183\npublished: true\ntags: discuss\ndate: \nseries: \ncanonical_url: \n\n---\n\nBlue bottle marfa muggle magic. Synth brunch letterpress franzen kitsch 3 wolf moon everyday.\n\n\nTumblr migas deep v street. Tumblr yuccie muggle magic crucifix actually forage.\n\n", + "tags": ["discuss"], + "body_html": "

Tilde cronut meggings. Flannel crucifix vice put a bird on it pork belly everyday.

\n\n

Squid swag park. Listicle mustache jean shorts slow-carb pinterest xoxo forage. Narwhal phlogiston master tumblr venmo.

\n\n", + "body_markdown": "---\ntitle: Dance Dance Dance183\npublished: true\ntags: discuss\ndate: \nseries: \ncanonical_url: \n\n---\n\nTilde cronut meggings. Flannel crucifix vice put a bird on it pork belly everyday.\n\n\nSquid swag park. Listicle mustache jean shorts slow-carb pinterest xoxo forage. Narwhal phlogiston master tumblr venmo.\n\n", "user": { - "name": "Milo \"Karly\" \\:/ Mertz", + "name": "Charles \"Lemuel\" \\:/ Durgan", "username": "username396", "twitter_username": "twitter396", "github_username": "github396", - "user_id": 1156, + "user_id": 1991, "website_url": null, - "profile_image": "/uploads/user/profile_image/1156/93b1f8a9-2e49-4480-bb6f-e7fe1a8eb25e.jpeg", - "profile_image_90": "/uploads/user/profile_image/1156/93b1f8a9-2e49-4480-bb6f-e7fe1a8eb25e.jpeg" + "profile_image": "/uploads/user/profile_image/1991/89d3493e-b015-4ab5-b81a-78ad2b90b6dc.jpeg", + "profile_image_90": "/uploads/user/profile_image/1991/89d3493e-b015-4ab5-b81a-78ad2b90b6dc.jpeg" }, "flare_tag": { "name": "discuss", @@ -748,10 +700,7 @@ "/api/articles/me": { "get": { "summary": "User's articles", - "tags": [ - "articles", - "users" - ], + "tags": ["articles", "users"], "description": "This endpoint allows the client to retrieve a list of published articles on behalf of an authenticated user.\n\n\"Articles\" are all the posts that users create on DEV that typically show up in the feed. They can be a blog post, a discussion question, a help thread etc. but is referred to as article within the code.\n\nPublished articles will be in reverse chronological publication order.\n\nIt will return published articles with pagination. By default a page will contain 30 articles.", "operationId": "getUserArticles", "parameters": [ @@ -778,9 +727,7 @@ "description": "A List of the authenticated user's Articles", "content": { "application/json": { - "example": [ - - ], + "example": [], "schema": { "type": "array", "items": { @@ -796,10 +743,7 @@ "/api/articles/me/published": { "get": { "summary": "User's published articles", - "tags": [ - "articles", - "users" - ], + "tags": ["articles", "users"], "description": "This endpoint allows the client to retrieve a list of published articles on behalf of an authenticated user.\n\n\"Articles\" are all the posts that users create on DEV that typically show up in the feed. They can be a blog post, a discussion question, a help thread etc. but is referred to as article within the code.\n\nPublished articles will be in reverse chronological publication order.\n\nIt will return published articles with pagination. By default a page will contain 30 articles.", "operationId": "getUserPublishedArticles", "parameters": [ @@ -826,9 +770,7 @@ "description": "A List of the authenticated user's Articles", "content": { "application/json": { - "example": [ - - ], + "example": [], "schema": { "type": "array", "items": { @@ -844,10 +786,7 @@ "/api/articles/me/unpublished": { "get": { "summary": "User's unpublished articles", - "tags": [ - "articles", - "users" - ], + "tags": ["articles", "users"], "description": "This endpoint allows the client to retrieve a list of unpublished articles on behalf of an authenticated user.\n\n\"Articles\" are all the posts that users create on DEV that typically show up in the feed. They can be a blog post, a discussion question, a help thread etc. but is referred to as article within the code.\n\nUnpublished articles will be in reverse chronological creation order.\n\nIt will return unpublished articles with pagination. By default a page will contain 30 articles.", "operationId": "getUserUnpublishedArticles", "parameters": [ @@ -874,9 +813,7 @@ "description": "A List of the authenticated user's Articles", "content": { "application/json": { - "example": [ - - ], + "example": [], "schema": { "type": "array", "items": { @@ -892,10 +829,7 @@ "/api/articles/me/all": { "get": { "summary": "User's all articles", - "tags": [ - "articles", - "users" - ], + "tags": ["articles", "users"], "description": "This endpoint allows the client to retrieve a list of all articles on behalf of an authenticated user.\n\n\"Articles\" are all the posts that users create on DEV that typically show up in the feed. They can be a blog post, a discussion question, a help thread etc. but is referred to as article within the code.\n\nIt will return both published and unpublished articles with pagination.\n\nUnpublished articles will be at the top of the list in reverse chronological creation order. Published articles will follow in reverse chronological publication order.\n\nBy default a page will contain 30 articles.", "operationId": "getUserAllArticles", "parameters": [ @@ -922,9 +856,7 @@ "description": "A List of the authenticated user's Articles", "content": { "application/json": { - "example": [ - - ], + "example": [], "schema": { "type": "array", "items": { @@ -940,9 +872,7 @@ "/api/articles/{id}/unpublish": { "put": { "summary": "Unpublish an article", - "tags": [ - "articles" - ], + "tags": ["articles"], "description": "This endpoint allows the client to unpublish an article.\n\nThe user associated with the API key must have any 'admin' or 'moderator' role.\n\nThe article will be unpublished and will no longer be visible to the public. It will remain\nin the database and will set back to draft status on the author's posts dashboard. Any\nnotifications associated with the article will be deleted. Any comments on the article\nwill remain.", "operationId": "unpublishArticle", "parameters": [ @@ -1001,12 +931,8 @@ "/api/comments": { "get": { "summary": "Comments", - "security": [ - - ], - "tags": [ - "comments" - ], + "security": [], + "tags": ["comments"], "description": "This endpoint allows the client to retrieve all comments belonging to an article or podcast episode as threaded conversations.\n\nIt will return the all top level comments with their nested comments as threads. See the format specification for further details.", "operationId": "getCommentsByArticleId", "parameters": [ @@ -1039,22 +965,20 @@ "example": [ { "type_of": "comment", - "id_code": "b3", - "created_at": "2023-03-30T07:50:21Z", - "body_html": "

Freegan tacos scenester 90's pabst. Listicle hashtag pickled austin biodiesel street.

\n\n", + "id_code": "h4", + "created_at": "2023-03-31T10:15:45Z", + "body_html": "

Narwhal truffaut heirloom trust fund.

\n\n", "user": { - "name": "Gabriel \"Rosario\" \\:/ Dickens", + "name": "Christoper \"Elbert\" \\:/ Parker", "username": "username410", "twitter_username": "twitter410", "github_username": "github410", - "user_id": 1170, + "user_id": 2005, "website_url": null, - "profile_image": "/uploads/user/profile_image/1170/f2170bd2-18d6-43a4-9500-7c179e75602e.jpeg", - "profile_image_90": "/uploads/user/profile_image/1170/f2170bd2-18d6-43a4-9500-7c179e75602e.jpeg" + "profile_image": "/uploads/user/profile_image/2005/2249cc76-68cb-4491-9c09-2fa540f1f813.jpeg", + "profile_image_90": "/uploads/user/profile_image/2005/2249cc76-68cb-4491-9c09-2fa540f1f813.jpeg" }, - "children": [ - - ] + "children": [] } ], "schema": { @@ -1083,12 +1007,8 @@ "/api/comments/{id}": { "get": { "summary": "Comment by id", - "security": [ - - ], - "tags": [ - "comments" - ], + "security": [], + "tags": ["comments"], "description": "This endpoint allows the client to retrieve a comment as well as his descendants comments.\n\n It will return the required comment (the root) with its nested descendants as a thread.\n\n See the format specification for further details.", "operationId": "getCommentById", "parameters": [ @@ -1110,22 +1030,20 @@ "application/json": { "example": { "type_of": "comment", - "id_code": "b5", - "created_at": "2023-03-30T07:50:21Z", - "body_html": "

Meditation health 90's post-ironic twee iphone retro food truck.

\n\n", + "id_code": "h6", + "created_at": "2023-03-31T10:15:45Z", + "body_html": "

Cornhole fixie narwhal.

\n\n", "user": { - "name": "Antonia \"Cora\" \\:/ Tillman", + "name": "Nicolasa \"Sebrina\" \\:/ Abernathy", "username": "username414", "twitter_username": "twitter414", "github_username": "github414", - "user_id": 1174, + "user_id": 2009, "website_url": null, - "profile_image": "/uploads/user/profile_image/1174/b656cd3a-d8c8-4afe-b795-2384d6b3bb09.jpeg", - "profile_image_90": "/uploads/user/profile_image/1174/b656cd3a-d8c8-4afe-b795-2384d6b3bb09.jpeg" + "profile_image": "/uploads/user/profile_image/2009/0a69d592-a56e-44af-914f-74d896ee472b.jpeg", + "profile_image_90": "/uploads/user/profile_image/2009/0a69d592-a56e-44af-914f-74d896ee472b.jpeg" }, - "children": [ - - ] + "children": [] } } } @@ -1147,18 +1065,20 @@ "/api/display_ads": { "get": { "summary": "display ads", - "tags": [ - "display ads" - ], + "tags": ["display ads"], "description": "This endpoint allows the client to retrieve a list of all display ads.", "responses": { "200": { "description": "successful", "content": { "application/json": { - "example": [ - - ] + "example": [], + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DisplayAd" + } + } } } }, @@ -1177,25 +1097,21 @@ }, "post": { "summary": "display ads", - "tags": [ - "display ads" - ], + "tags": ["display ads"], "description": "This endpoint allows the client to create a new display ad.", - "parameters": [ - - ], + "parameters": [], "responses": { "200": { "description": "successful", "content": { "application/json": { "example": { - "id": 935, + "id": 154, "approved": true, "body_markdown": "# Hi, this is ad\nYep, it's an ad", "cached_tag_list": "", "clicks_count": 0, - "created_at": "2023-03-30T13:20:21.892+05:30", + "created_at": "2023-03-31T20:15:45.715+10:00", "creator_id": null, "display_to": "all", "exclude_article_ids": "", @@ -1207,8 +1123,14 @@ "published": true, "success_rate": 0.0, "type_of": "in_house", - "updated_at": "2023-03-30T13:20:21.892+05:30", + "updated_at": "2023-03-31T20:15:45.715+10:00", "tag_list": "" + }, + "schema": { + "type": "object", + "items": { + "$ref": "#/components/schemas/DisplayAd" + } } } } @@ -1258,76 +1180,9 @@ "application/json": { "schema": { "type": "object", - "properties": { - "name": { - "type": "string", - "description": "For internal use, helps distinguish ads from one another" - }, - "body_markdown": { - "type": "string", - "description": "The text (in markdown) of the ad (required)" - }, - "approved": { - "type": "boolean", - "description": "Ad must be both published and approved to be in rotation" - }, - "published": { - "type": "boolean", - "description": "Ad must be both published and approved to be in rotation" - }, - "organization_id": { - "type": "integer", - "description": "Identifies the organization to which the ad belongs" - }, - "display_to": { - "type": "string", - "enum": [ - "all", - "logged_in", - "logged_out" - ], - "default": "all", - "description": "Potentially limits visitors to whom the ad is visible" - }, - "type_of": { - "type": "string", - "enum": [ - "in_house", - "community", - "external" - ], - "default": "in_house", - "description": "Types of the billboards:\nin_house (created by admins),\ncommunity (created by an entity, appears on entity's content),\nexternal ( created by an entity, or a non-entity, can appear everywhere)\n" - }, - "placement_area": { - "type": "string", - "enum": [ - "sidebar_left", - "sidebar_left_2", - "sidebar_right", - "post_sidebar", - "post_comments" - ], - "description": "Identifies which area of site layout the ad can appear in" - }, - "tag_list": { - "type": "string", - "description": "Tags on which this ad can be displayed (blank is all/any tags)" - }, - "article_exclude_ids": { - "type": "string", - "description": "Articles this ad should *not* appear (blank is all/any article), comma-separated list of integer Article IDs" - }, - "creator_id": { - "type": "integer", - "description": "Identifies the user who created the ad." - } - }, - "required": [ - "name", - "body_markdown", - "placement_area" - ] + "items": { + "$ref": "#/components/schemas/DisplayAd" + } } } } @@ -1337,16 +1192,14 @@ "/api/display_ads/{id}": { "get": { "summary": "display ad", - "tags": [ - "display ads" - ], + "tags": ["display ads"], "description": "This endpoint allows the client to retrieve a single display ad, via its id.", "parameters": [ { "name": "id", "in": "path", "required": true, - "description": "The ID of the user to unpublish.", + "description": "The ID of the display ad.", "schema": { "type": "integer", "format": "int32", @@ -1361,24 +1214,24 @@ "content": { "application/json": { "example": { - "id": 936, + "id": 155, "approved": false, "body_markdown": "Hello _hey_ Hey hey 9", "cached_tag_list": "", "clicks_count": 0, - "created_at": "2023-03-30T13:20:22.034+05:30", + "created_at": "2023-03-31T20:15:45.866+10:00", "creator_id": null, "display_to": "all", "exclude_article_ids": "", "impressions_count": 0, - "name": "Display Ad 936", - "organization_id": 1032, + "name": "Display Ad 155", + "organization_id": 440, "placement_area": "sidebar_left", "processed_html": "

Hello hey Hey hey 9

", "published": false, "success_rate": 0.0, "type_of": "in_house", - "updated_at": "2023-03-30T13:20:22.037+05:30", + "updated_at": "2023-03-31T20:15:45.877+10:00", "tag_list": "" } } @@ -1410,16 +1263,14 @@ }, "put": { "summary": "display ads", - "tags": [ - "display ads" - ], + "tags": ["display ads"], "description": "This endpoint allows the client to update the attributes of a single display ad, via its id.", "parameters": [ { "name": "id", "in": "path", "required": true, - "description": "The ID of the user to unpublish.", + "description": "The ID of the display ad.", "schema": { "type": "integer", "format": "int32", @@ -1438,21 +1289,27 @@ "body_markdown": "Hello _hey_ Hey hey 10", "creator_id": null, "display_to": "all", - "name": "Display Ad 937", - "organization_id": 1033, + "name": "Display Ad 156", + "organization_id": 441, "placement_area": "sidebar_left", "published": false, "type_of": "in_house", "exclude_article_ids": "", "processed_html": "

Hello hey Hey hey 10

", "cached_tag_list": "", - "id": 937, + "id": 156, "clicks_count": 0, - "created_at": "2023-03-30T13:20:22.200+05:30", + "created_at": "2023-03-31T20:15:46.046+10:00", "impressions_count": 0, "success_rate": 0.0, - "updated_at": "2023-03-30T13:20:22.203+05:30", + "updated_at": "2023-03-31T20:15:46.048+10:00", "tag_list": "" + }, + "schema": { + "type": "object", + "items": { + "$ref": "#/components/schemas/DisplayAd" + } } } } @@ -1485,62 +1342,9 @@ "application/json": { "schema": { "type": "object", - "properties": { - "name": { - "type": "string", - "description": "For internal use, helps distinguish ads from one another" - }, - "body_markdown": { - "type": "string", - "description": "The text (in markdown) of the ad (required)" - }, - "approved": { - "type": "boolean", - "description": "Ad must be both published and approved to be in rotation" - }, - "published": { - "type": "boolean", - "description": "Ad must be both published and approved to be in rotation" - }, - "organization_id": { - "type": "integer", - "description": "Identifies the organization to which the ad belongs, required for 'community' type ads" - }, - "display_to": { - "type": "string", - "enum": [ - "all", - "logged_in", - "logged_out" - ], - "default": "all", - "description": "Potentially limits visitors to whom the ad is visible" - }, - "placement_area": { - "type": "string", - "enum": [ - "sidebar_left", - "sidebar_left_2", - "sidebar_right", - "post_sidebar", - "post_comments" - ], - "description": "Identifies which area of site layout the ad can appear in" - }, - "tag_list": { - "type": "string", - "description": "Tags on which this ad can be displayed (blank is all/any tags)" - }, - "creator_id": { - "type": "integer", - "description": "Identifies the user who created the ad." - } - }, - "required": [ - "name", - "body_markdown", - "placement_area" - ] + "items": { + "$ref": "#/components/schemas/DisplayAd" + } } } } @@ -1550,16 +1354,14 @@ "/api/display_ads/{id}/unpublish": { "put": { "summary": "unpublish", - "tags": [ - "display ads" - ], + "tags": ["display ads"], "description": "This endpoint allows the client to remove a display ad from rotation by un-publishing it.", "parameters": [ { "name": "id", "in": "path", "required": true, - "description": "The ID of the user to unpublish.", + "description": "The ID of the display ad to unpublish.", "schema": { "type": "integer", "format": "int32", @@ -1600,10 +1402,7 @@ "/api/follows/tags": { "get": { "summary": "Followed Tags", - "tags": [ - "followed_tags", - "tags" - ], + "tags": ["followed_tags", "tags"], "description": "This endpoint allows the client to retrieve a list of the tags they follow.", "operationId": "getFollowedTags", "responses": { @@ -1624,12 +1423,12 @@ "application/json": { "example": [ { - "id": 2051, + "id": 1532, "name": "tag3", "points": 1.0 }, { - "id": 2052, + "id": 1533, "name": "tag4", "points": 1.0 } @@ -1649,9 +1448,7 @@ "/api/followers/users": { "get": { "summary": "Followers", - "tags": [ - "followers" - ], + "tags": ["followers"], "description": "This endpoint allows the client to retrieve a list of the followers they have.\n \"Followers\" are users that are following other users on the website.\n It supports pagination, each page will contain 80 followers by default.", "operationId": "getFollowers", "parameters": [ @@ -1680,23 +1477,23 @@ "example": [ { "type_of": "user_follower", - "id": 27, - "created_at": "2023-03-30T07:50:22Z", - "user_id": 1195, - "name": "Irvin \"Francesco\" \\:/ Bruen", + "id": 48, + "created_at": "2023-03-31T10:15:46Z", + "user_id": 2030, + "name": "Ismael \"Kristopher\" \\:/ Wilderman", "path": "/username435", "username": "username435", - "profile_image": "/uploads/user/profile_image/1195/dd7acac2-e6a8-431b-a72b-7431a6eac64c.jpeg" + "profile_image": "/uploads/user/profile_image/2030/9f061a65-46b5-4d5a-90c8-ccd152274a43.jpeg" }, { "type_of": "user_follower", - "id": 26, - "created_at": "2023-03-30T07:50:22Z", - "user_id": 1193, - "name": "Babette \"Trey\" \\:/ Dickens", + "id": 47, + "created_at": "2023-03-31T10:15:46Z", + "user_id": 2028, + "name": "Merrie \"Jamaal\" \\:/ Quigley", "path": "/username433", "username": "username433", - "profile_image": "/uploads/user/profile_image/1193/f66a0475-6b4c-4144-bddb-4b0d7a486c02.jpeg" + "profile_image": "/uploads/user/profile_image/2028/c70fafc0-b2f2-4bbd-8dfa-49af1b2a6fa9.jpeg" } ], "schema": { @@ -1753,12 +1550,8 @@ "/api/organizations/{username}": { "get": { "summary": "An organization", - "tags": [ - "organizations" - ], - "security": [ - - ], + "tags": ["organizations"], + "security": [], "description": "This endpoint allows the client to retrieve a single organization by their username", "operationId": "getOrganization", "parameters": [ @@ -1778,19 +1571,19 @@ "application/json": { "example": { "type_of": "organization", - "id": 1038, + "id": 446, "username": "org77", - "name": "Frami-Sauer", - "summary": "Gluten-free jean shorts bushwick franzen mixtape.", - "twitter_username": "org65", - "github_username": "org3603", - "url": "http://flatley.com/jan", + "name": "Kutch-Runolfsson", + "summary": "Humblebrag lo-fi viral shoreditch 90's salvia. Narwhal retro artisan fingerstache letterpress.", + "twitter_username": "org9929", + "github_username": "org2206", + "url": "http://conn.co/elias", "location": null, "tech_stack": null, "tag_line": null, "story": null, - "joined_at": "2023-03-30T07:50:22Z", - "profile_image": "/uploads/organization/profile_image/1038/b764d03f-c6cb-4523-b518-ab359021452c.png" + "joined_at": "2023-03-31T10:15:46Z", + "profile_image": "/uploads/organization/profile_image/446/eb20262e-00ff-47ee-a38f-dedbb4fa7c26.png" }, "schema": { "type": "object", @@ -1818,13 +1611,8 @@ "/api/organizations/{username}/users": { "get": { "summary": "Organization's users", - "tags": [ - "organizations", - "users" - ], - "security": [ - - ], + "tags": ["organizations", "users"], + "security": [], "description": "This endpoint allows the client to retrieve a list of users belonging to the organization\n\nIt supports pagination, each page will contain `30` users by default.", "operationId": "getOrgUsers", "parameters": [ @@ -1851,29 +1639,29 @@ "example": [ { "type_of": "user", - "id": 1205, + "id": 2040, "username": "username445", - "name": "Lola \"Martina\" \\:/ Lang", + "name": "Randell \"Dorthey\" \\:/ Leannon", "twitter_username": "twitter445", "github_username": "github445", "summary": null, "location": null, "website_url": null, - "joined_at": "Mar 30, 2023", - "profile_image": "/uploads/user/profile_image/1205/5b35efd1-afa4-4399-acc0-fb19eb033327.jpeg" + "joined_at": "Mar 31, 2023", + "profile_image": "/uploads/user/profile_image/2040/bb9ca150-a1ea-4cf8-a655-1068ded85422.jpeg" }, { "type_of": "user", - "id": 1206, + "id": 2041, "username": "username446", - "name": "Courtney \"Stefan\" \\:/ Schuster", + "name": "Seema \"Latisha\" \\:/ Jenkins", "twitter_username": "twitter446", "github_username": "github446", "summary": null, "location": null, "website_url": null, - "joined_at": "Mar 30, 2023", - "profile_image": "/uploads/user/profile_image/1206/7c2b85ca-80da-49a8-a544-a3e545fef640.jpeg" + "joined_at": "Mar 31, 2023", + "profile_image": "/uploads/user/profile_image/2041/a1027ff0-8703-47b0-86e5-6c3b17e38dac.jpeg" } ], "schema": { @@ -1902,13 +1690,8 @@ "/api/organizations/{username}/articles": { "get": { "summary": "Organization's Articles", - "tags": [ - "organizations", - "articles" - ], - "security": [ - - ], + "tags": ["organizations", "articles"], + "security": [], "description": "This endpoint allows the client to retrieve a list of Articles belonging to the organization\n\nIt supports pagination, each page will contain `30` users by default.", "operationId": "getOrgArticles", "parameters": [ @@ -1935,49 +1718,45 @@ "example": [ { "type_of": "article", - "id": 513, - "title": "Tirra Lirra by the River195", - "description": "Tumblr forage thundercats art party salvia everyday. Sartorial church-key selfies keytar cred....", - "readable_publish_date": "Mar 30", - "slug": "tirra-lirra-by-the-river195-27j3", - "path": "/org81/tirra-lirra-by-the-river195-27j3", - "url": "http://localhost:3000/org81/tirra-lirra-by-the-river195-27j3", + "id": 811, + "title": "A Swiftly Tilting Planet195", + "description": "Sustainable tacos deep v diy. Banjo austin salvia fanny pack tumblr semiotics wes anderson...", + "readable_publish_date": "Mar 31", + "slug": "a-swiftly-tilting-planet195-481o", + "path": "/org81/a-swiftly-tilting-planet195-481o", + "url": "http://localhost:3000/org81/a-swiftly-tilting-planet195-481o", "comments_count": 0, "public_reactions_count": 0, "collection_id": null, - "published_timestamp": "2023-03-30T07:50:23Z", + "published_timestamp": "2023-03-31T10:15:47Z", "positive_reactions_count": 0, - "cover_image": "http://localhost:3000/assets/37-94b286825ffd9f2b47c9842cf4f262b7c89e789797eba40196bc14b5c2359e75.png", - "social_image": "http://localhost:3000/assets/37-94b286825ffd9f2b47c9842cf4f262b7c89e789797eba40196bc14b5c2359e75.png", - "canonical_url": "http://localhost:3000/org81/tirra-lirra-by-the-river195-27j3", - "created_at": "2023-03-30T07:50:23Z", + "cover_image": "http://localhost:3000/assets/2-1a96ae446ded018b65b215cce3aecc40a00e701642da521fdd6edd3c593ff6c1.png", + "social_image": "http://localhost:3000/assets/2-1a96ae446ded018b65b215cce3aecc40a00e701642da521fdd6edd3c593ff6c1.png", + "canonical_url": "http://localhost:3000/org81/a-swiftly-tilting-planet195-481o", + "created_at": "2023-03-31T10:15:47Z", "edited_at": null, "crossposted_at": null, - "published_at": "2023-03-30T07:50:23Z", - "last_comment_at": "2023-03-30T07:50:23Z", + "published_at": "2023-03-31T10:15:47Z", + "last_comment_at": "2023-03-31T10:15:47Z", "reading_time_minutes": 1, - "tag_list": [ - "javascript", - "html", - "discuss" - ], + "tag_list": ["javascript", "html", "discuss"], "tags": "javascript, html, discuss", "user": { - "name": "Randall \"Larisa\" \\:/ Will", + "name": "Juan \"Bernetta\" \\:/ Hills", "username": "username453", "twitter_username": "twitter453", "github_username": "github453", - "user_id": 1213, + "user_id": 2048, "website_url": null, - "profile_image": "/uploads/user/profile_image/1213/15de4f8e-2b27-4bab-b936-a2538be7a7fd.jpeg", - "profile_image_90": "/uploads/user/profile_image/1213/15de4f8e-2b27-4bab-b936-a2538be7a7fd.jpeg" + "profile_image": "/uploads/user/profile_image/2048/b23eda92-6fd9-423d-8edf-ec37ce4367d1.jpeg", + "profile_image_90": "/uploads/user/profile_image/2048/b23eda92-6fd9-423d-8edf-ec37ce4367d1.jpeg" }, "organization": { - "name": "Schaefer LLC", + "name": "Feest Group", "username": "org81", "slug": "org81", - "profile_image": "/uploads/organization/profile_image/1042/622cd5f5-59ab-4416-8322-2bf104d4187f.png", - "profile_image_90": "/uploads/organization/profile_image/1042/622cd5f5-59ab-4416-8322-2bf104d4187f.png" + "profile_image": "/uploads/organization/profile_image/450/f2c535aa-66f0-43bb-8cd7-ad5f01107892.png", + "profile_image_90": "/uploads/organization/profile_image/450/f2c535aa-66f0-43bb-8cd7-ad5f01107892.png" } } ], @@ -2007,12 +1786,8 @@ "/api/pages": { "get": { "summary": "show details for all pages", - "security": [ - - ], - "tags": [ - "pages" - ], + "security": [], + "tags": ["pages"], "description": "This endpoint allows the client to retrieve details for all Page objects.", "responses": { "200": { @@ -2021,16 +1796,16 @@ "application/json": { "example": [ { - "id": 26, - "title": "Beneath the Bleeding", - "slug": "push-shock", - "description": "Atque reiciendis ut quaerat.", + "id": 51, + "title": "Bury My Heart at Wounded Knee", + "slug": "message-branch", + "description": "Eos vero delectus autem.", "is_top_level_path": false, "landing_page": false, "body_html": null, "body_json": null, - "body_markdown": "Dolores officia ab accusamus.", - "processed_html": "

Dolores officia ab accusamus.

\n\n", + "body_markdown": "Ut voluptas dignissimos eligendi.", + "processed_html": "

Ut voluptas dignissimos eligendi.

\n\n", "social_image": { "url": null }, @@ -2050,20 +1825,16 @@ }, "post": { "summary": "pages", - "tags": [ - "pages" - ], + "tags": ["pages"], "description": "This endpoint allows the client to create a new page.", - "parameters": [ - - ], + "parameters": [], "responses": { "200": { "description": "successful", "content": { "application/json": { "example": { - "id": 28, + "id": 53, "title": "Example Page", "slug": "example1", "description": "a new page", @@ -2167,12 +1938,8 @@ "/api/pages/{id}": { "get": { "summary": "show details for a page", - "security": [ - - ], - "tags": [ - "pages" - ], + "security": [], + "tags": ["pages"], "description": "This endpoint allows the client to retrieve details for a single Page object, specified by ID.", "parameters": [ { @@ -2194,16 +1961,16 @@ "content": { "application/json": { "example": { - "id": 31, - "title": "Pale Kings and Princes", - "slug": "thirsty_highway", - "description": "Libero molestiae eligendi cupiditate.", + "id": 56, + "title": "The Doors of Perception", + "slug": "bless_polish", + "description": "Facilis vel omnis dolorem.", "is_top_level_path": false, "landing_page": false, "body_html": null, "body_json": null, - "body_markdown": "Consequatur accusantium perspiciatis illo.", - "processed_html": "

Consequatur accusantium perspiciatis illo.

\n\n", + "body_markdown": "Eum et aliquid beatae.", + "processed_html": "

Eum et aliquid beatae.

\n\n", "social_image": { "url": null }, @@ -2219,9 +1986,7 @@ }, "put": { "summary": "update details for a page", - "tags": [ - "pages" - ], + "tags": ["pages"], "description": "This endpoint allows the client to retrieve details for a single Page object, specified by ID.", "parameters": [ { @@ -2243,16 +2008,16 @@ "content": { "application/json": { "example": { - "id": 32, + "id": 57, "title": "New Title", - "slug": "seller-ample", - "description": "Similique qui voluptates autem.", + "slug": "award_corpse", + "description": "Velit reprehenderit aut reiciendis.", "is_top_level_path": false, "landing_page": false, "body_html": null, "body_json": null, - "body_markdown": "Enim ex optio maxime.", - "processed_html": "

Enim ex optio maxime.

\n\n", + "body_markdown": "Doloremque et culpa et.", + "processed_html": "

Doloremque et culpa et.

\n\n", "social_image": { "url": null }, @@ -2280,16 +2045,16 @@ "content": { "application/json": { "example": { - "id": 34, - "title": "The Curious Incident of the Dog in the Night-Time", - "slug": "minister_appointment", - "description": "Est nulla enim dolorum.", + "id": 59, + "title": "All Passion Spent", + "slug": "nursery-award", + "description": "Optio et corrupti cupiditate.", "is_top_level_path": false, "landing_page": false, "body_html": null, "body_json": null, - "body_markdown": "Quia voluptate labore blanditiis.", - "processed_html": "

Corporis sequi doloremque minima.

\n\n", + "body_markdown": "Consectetur autem aut quia.", + "processed_html": "

Voluptas dolorem est voluptas.

\n\n", "social_image": { "url": null }, @@ -2311,9 +2076,7 @@ }, "delete": { "summary": "remove a page", - "tags": [ - "pages" - ], + "tags": ["pages"], "description": "This endpoint allows the client to delete a single Page object, specified by ID.", "parameters": [ { @@ -2335,16 +2098,16 @@ "content": { "application/json": { "example": { - "id": 35, - "title": "Great Work of Time", - "slug": "wear_ambiguous", - "description": "Aliquid sunt laborum nihil.", + "id": 60, + "title": "The Torment of Others", + "slug": "rung_whole", + "description": "Amet quae est velit.", "is_top_level_path": false, "landing_page": false, "body_html": null, "body_json": null, - "body_markdown": "Quibusdam est et laborum.", - "processed_html": "

Quibusdam est et laborum.

\n\n", + "body_markdown": "Facilis nulla quas placeat.", + "processed_html": "

Facilis nulla quas placeat.

\n\n", "social_image": { "url": null }, @@ -2389,12 +2152,8 @@ "/api/podcast_episodes": { "get": { "summary": "Podcast Episodes", - "security": [ - - ], - "tags": [ - "podcast_episodes" - ], + "security": [], + "tags": ["podcast_episodes"], "description": "This endpoint allows the client to retrieve a list of podcast episodes.\n \"Podcast episodes\" are episodes belonging to podcasts.\n It will only return active (reachable) podcast episodes that belong to published podcasts available on the platform, ordered by descending publication date.\n It supports pagination, each page will contain 30 articles by default.", "operationId": "getPodcastEpisodes", "parameters": [ @@ -2424,14 +2183,14 @@ { "type_of": "podcast_episodes", "class_name": "PodcastEpisode", - "id": 26, + "id": 48, "path": "/codenewbie/slug-4", - "title": "26", - "image_url": "/uploads/podcast/image/21/b10865d4-188b-47ae-a577-ff15471b9fef.jpeg", + "title": "12", + "image_url": "/uploads/podcast/image/38/ffca133b-b726-4c11-b7d8-6168d3943b91.jpeg", "podcast": { - "title": "Chocolate St", + "title": "Delirium Noctorum", "slug": "codenewbie", - "image_url": "/uploads/podcast/image/21/b10865d4-188b-47ae-a577-ff15471b9fef.jpeg" + "image_url": "/uploads/podcast/image/38/ffca133b-b726-4c11-b7d8-6168d3943b91.jpeg" } } ], @@ -2461,9 +2220,7 @@ "/api/profile_images/{username}": { "get": { "summary": "A Users or organizations profile image", - "tags": [ - "profile images" - ], + "tags": ["profile images"], "description": "This endpoint allows the client to retrieve a user or organization profile image information by its\n corresponding username.", "operationId": "getProfileImage", "parameters": [ @@ -2486,8 +2243,8 @@ "example": { "type_of": "profile_image", "image_of": "user", - "profile_image": "/uploads/user/profile_image/1228/7dbcd107-d779-4a4c-b827-eefe1f45c76a.jpeg", - "profile_image_90": "/uploads/user/profile_image/1228/7dbcd107-d779-4a4c-b827-eefe1f45c76a.jpeg" + "profile_image": "/uploads/user/profile_image/2063/521253a8-86f9-4d9a-8b47-f70610c01798.jpeg", + "profile_image_90": "/uploads/user/profile_image/2063/521253a8-86f9-4d9a-8b47-f70610c01798.jpeg" }, "schema": { "type": "object", @@ -2515,9 +2272,7 @@ "/api/reactions/toggle": { "post": { "summary": "toggle reaction", - "tags": [ - "reactions" - ], + "tags": ["reactions"], "description": "This endpoint allows the client to toggle the user's reaction to a specified reactable (eg, Article, Comment, or User). For examples:\n * \"Like\"ing an Article will create a new \"like\" Reaction from the user for that Articles\n * \"Like\"ing that Article a second time will remove the \"like\" from the user", "parameters": [ { @@ -2550,11 +2305,7 @@ "required": true, "schema": { "type": "string", - "enum": [ - "Comment", - "Article", - "User" - ] + "enum": ["Comment", "Article", "User"] } } ], @@ -2566,8 +2317,8 @@ "example": { "result": "create", "category": "like", - "id": 15, - "reactable_id": 515, + "id": 29, + "reactable_id": 813, "reactable_type": "Article" } } @@ -2590,9 +2341,7 @@ "/api/reactions": { "post": { "summary": "create reaction", - "tags": [ - "reactions" - ], + "tags": ["reactions"], "description": "This endpoint allows the client to create a reaction to a specified reactable (eg, Article, Comment, or User). For examples:\n * \"Like\"ing an Article will create a new \"like\" Reaction from the user for that Articles\n * \"Like\"ing that Article a second time will return the previous \"like\"", "parameters": [ { @@ -2625,11 +2374,7 @@ "required": true, "schema": { "type": "string", - "enum": [ - "Comment", - "Article", - "User" - ] + "enum": ["Comment", "Article", "User"] } } ], @@ -2641,8 +2386,8 @@ "example": { "result": "none", "category": "like", - "id": 17, - "reactable_id": 517, + "id": 31, + "reactable_id": 815, "reactable_type": "Article" } } @@ -2665,9 +2410,7 @@ "/api/readinglist": { "get": { "summary": "Readinglist", - "tags": [ - "readinglist" - ], + "tags": ["readinglist"], "description": "This endpoint allows the client to retrieve a list of articles that were saved to a Users readinglist.\n It supports pagination, each page will contain `30` articles by default", "operationId": "getReadinglist", "parameters": [ @@ -2694,9 +2437,7 @@ "description": "A list of articles in the users readinglist", "content": { "application/json": { - "example": [ - - ], + "example": [], "schema": { "type": "array", "items": { @@ -2712,12 +2453,8 @@ "/api/tags": { "get": { "summary": "Tags", - "tags": [ - "tags" - ], - "security": [ - - ], + "tags": ["tags"], + "security": [], "description": "This endpoint allows the client to retrieve a list of tags that can be used to tag articles.\n\nIt will return tags ordered by popularity.\n\nIt supports pagination, each page will contain 10 tags by default.", "operationId": "getTags", "parameters": [ @@ -2735,20 +2472,20 @@ "application/json": { "example": [ { - "id": 2085, - "name": "tag7", + "id": 1564, + "name": "tag5", "bg_color_hex": null, "text_color_hex": null }, { - "id": 2084, + "id": 1565, "name": "tag6", "bg_color_hex": null, "text_color_hex": null }, { - "id": 2083, - "name": "tag5", + "id": 1566, + "name": "tag7", "bg_color_hex": null, "text_color_hex": null } @@ -2768,9 +2505,7 @@ "/api/users/me": { "get": { "summary": "The authenticated user", - "tags": [ - "users" - ], + "tags": ["users"], "description": "This endpoint allows the client to retrieve information about the authenticated user", "operationId": "getUserMe", "responses": { @@ -2780,16 +2515,16 @@ "application/json": { "example": { "type_of": "user", - "id": 1240, + "id": 2075, "username": "username480", - "name": "Javier \"Dwight\" \\:/ Hand", + "name": "Miles \"George\" \\:/ Miller", "twitter_username": "twitter480", "github_username": "github480", "summary": null, "location": null, "website_url": null, - "joined_at": "Mar 30, 2023", - "profile_image": "/uploads/user/profile_image/1240/b9dc6f0b-8622-4e53-9b0f-3fe093b1fa0f.jpeg" + "joined_at": "Mar 31, 2023", + "profile_image": "/uploads/user/profile_image/2075/6df02453-8478-44e1-bd35-a7b735c7b23b.jpeg" }, "schema": { "type": "object", @@ -2817,9 +2552,7 @@ "/api/users/{id}": { "get": { "summary": "A User", - "tags": [ - "users" - ], + "tags": ["users"], "description": "This endpoint allows the client to retrieve a single user, either by id\nor by the user's username.\n\nFor complete documentation, see the v0 API docs: https://developers.forem.com/api/v0#tag/users/operation/getUser", "operationId": "getUser", "parameters": [ @@ -2852,9 +2585,7 @@ "/api/users/{id}/unpublish": { "put": { "summary": "Unpublish a User's Articles and Comments", - "tags": [ - "users" - ], + "tags": ["users"], "description": "This endpoint allows the client to unpublish all of the articles and\ncomments created by a user.\n\nThe user associated with the API key must have any 'admin' or 'moderator' role.\n\nThis specified user's articles and comments will be unpublished and will no longer be\nvisible to the public. They will remain in the database and will set back to draft status\non the specified user's dashboard. Any notifications associated with the specified user's\narticles and comments will be deleted.\n\nNote this endpoint unpublishes articles and comments asychronously: it will return a 204 NO CONTENT\nstatus code immediately, but the articles and comments will not be unpublished until the\nrequest is completed on the server.", "operationId": "unpublishUser", "parameters": [ @@ -2903,9 +2634,7 @@ "/api/users/{id}/suspend": { "put": { "summary": "Suspend a User", - "tags": [ - "users" - ], + "tags": ["users"], "description": "This endpoint allows the client to suspend a user.\n\nThe user associated with the API key must have any 'admin' or 'moderator' role.\n\nThis specified user will be assigned the 'suspended' role. Suspending a user will stop the\nuser from posting new posts and comments. It doesn't delete any of the user's content, just\nprevents them from creating new content while suspended. Users are not notified of their suspension\nin the UI, so if you want them to know about this, you must notify them.", "operationId": "suspendUser", "parameters": [ @@ -2954,14 +2683,10 @@ "/api/admin/users": { "post": { "summary": "Invite a User", - "tags": [ - "users" - ], + "tags": ["users"], "description": "This endpoint allows the client to trigger an invitation to the provided email address.\n\n It requires a token from a user with `super_admin` privileges.", "operationId": "postAdminUsersCreate", - "parameters": [ - - ], + "parameters": [], "responses": { "200": { "description": "Successful" @@ -3003,13 +2728,8 @@ "/api/videos": { "get": { "summary": "Articles with a video", - "tags": [ - "videos", - "articles" - ], - "security": [ - - ], + "tags": ["videos", "articles"], + "security": [], "description": "This endpoint allows the client to retrieve a list of articles that are uploaded with a video.\n\nIt will only return published video articles ordered by descending popularity.\n\nIt supports pagination, each page will contain 24 articles by default.", "operationId": "videos", "parameters": [ @@ -3028,28 +2748,28 @@ "example": [ { "type_of": "video_article", - "id": 519, - "path": "/username499/alone-on-a-wide-wide-sea201-2jja", + "id": 818, + "path": "/username500/great-work-of-time202-2k54", "cloudinary_video_url": "https://dw71fyauz7yz9.cloudfront.net/video-upload__1e42eb0bab4abb3c63baeb5e8bdfe69f/thumbs-video-upload__1e42eb0bab4abb3c63baeb5e8bdfe69f-00001.png", - "title": "Alone on a Wide, Wide Sea201", - "user_id": 1260, + "title": "Great Work of Time202", + "user_id": 2096, "video_duration_in_minutes": "00:00", "video_source_url": "https://dw71fyauz7yz9.cloudfront.net/video-upload__1e42eb0bab4abb3c63baeb5e8bdfe69f/video-upload__1e42eb0bab4abb3c63baeb5e8bdfe69f.m3u8", "user": { - "name": "Lane \"Ed\" \\:/ Erdman" + "name": "Jann \"Cory\" \\:/ Wintheiser" } }, { "type_of": "video_article", - "id": 520, - "path": "/username500/great-work-of-time202-289k", + "id": 817, + "path": "/username499/consider-phlebas201-1534", "cloudinary_video_url": "https://dw71fyauz7yz9.cloudfront.net/video-upload__1e42eb0bab4abb3c63baeb5e8bdfe69f/thumbs-video-upload__1e42eb0bab4abb3c63baeb5e8bdfe69f-00001.png", - "title": "Great Work of Time202", - "user_id": 1261, + "title": "Consider Phlebas201", + "user_id": 2095, "video_duration_in_minutes": "00:00", "video_source_url": "https://dw71fyauz7yz9.cloudfront.net/video-upload__1e42eb0bab4abb3c63baeb5e8bdfe69f/video-upload__1e42eb0bab4abb3c63baeb5e8bdfe69f.m3u8", "user": { - "name": "Willy \"Sabrina\" \\:/ MacGyver" + "name": "Racquel \"Juli\" \\:/ Nikolaus" } } ], @@ -3074,9 +2794,7 @@ ], "security": [ { - "api-key": [ - - ] + "api-key": [] } ], "components": { @@ -3471,11 +3189,7 @@ "format": "float" } }, - "required": [ - "id", - "name", - "points" - ] + "required": ["id", "name", "points"] }, "Tag": { "description": "Representation of a tag", @@ -3545,12 +3259,7 @@ "description": "Controls what kind of layout the page is rendered in" } }, - "required": [ - "title", - "slug", - "description", - "template" - ] + "required": ["title", "slug", "description", "template"] }, "PodcastEpisodeIndex": { "description": "Representation of a podcast episode returned in a list", @@ -3765,7 +3474,76 @@ "nullable": true } } + }, + "DisplayAd": { + "description": "A Display Ad, aka Billboard, aka Widget", + "type": "object", + "properties": { + "id": { + "type": "integer", + "description": "The ID of the Display Ad" + }, + "name": { + "type": "string", + "description": "For internal use, helps distinguish ads from one another" + }, + "body_markdown": { + "type": "string", + "description": "The text (in markdown) of the ad (required)" + }, + "approved": { + "type": "boolean", + "description": "Ad must be both published and approved to be in rotation" + }, + "published": { + "type": "boolean", + "description": "Ad must be both published and approved to be in rotation" + }, + "organization_id": { + "type": "integer", + "description": "Identifies the organization to which the ad belongs", + "nullable": true + }, + "creator_id": { + "type": "integer", + "description": "Identifies the user who created the ad.", + "nullable": true + }, + "placement_area": { + "type": "string", + "enum": [ + "sidebar_left", + "sidebar_left_2", + "sidebar_right", + "post_sidebar", + "post_comments" + ], + "description": "Identifies which area of site layout the ad can appear in" + }, + "tag_list": { + "type": "string", + "description": "Tags on which this ad can be displayed (blank is all/any tags)" + }, + "article_exclude_ids": { + "type": "string", + "nullable": true, + "description": "Articles this ad should *not* appear on (blank means no articles are disallowed, and this ad can appear next to any/all articles). Comma-separated list of integer Article IDs" + }, + "display_to": { + "type": "string", + "enum": ["all", "logged_in", "logged_out"], + "default": "all", + "description": "Potentially limits visitors to whom the ad is visible" + }, + "type_of": { + "type": "string", + "enum": ["in_house", "community", "external"], + "default": "in_house", + "description": "Types of the billboards:\nin_house (created by admins),\ncommunity (created by an entity, appears on entity's content),\nexternal ( created by an entity, or a non-entity, can appear everywhere)\n" + } + }, + "required": ["name", "body_markdown", "placement_area"] } } } -} \ No newline at end of file +}