✂️✂️✂️ Part 2: Remove Sponsorship (#18522)

* feat: remove initializeSponsorshipVisibility and related code

* feat: remove sponsorships from sidebar

* feat: remove sponsorships from the admin - route, controller, view, spec

* feat: remove the admin menu item

* feat: remove the i8n for admin sponsors controller

* feat: sponsorship decorator was not being used anywhere

* feat: sponsorship slack messenger was not being used anywhere

* feat: remove the sponsorship_headline that gets configures on the admin

* feat: remove the /sponsors page

* feat: remove renedring of single_sponsor partial and associated partials

* feat: remove the navigation link rake task for sponsors

* feat: remove sponsorship from tags

* feat: remove i8n constants used

* remove sponsor references in text to the privacy page

* feat: remove the sponsorship detail from the organization page

* feat: remove the sponsors css that was used for app/views/pages/sponsors.html.erb

* feat: remove the sponsorship i8n that was used in the slack messengers

* feat: swap out the decorators to use Article as an example

* feat: remove spec to show sponsors on home page

* feat: update the specs to use Article Decorator instead of the Sponsorship Decorator

* fix: use direct and not all

* fix: remove tests for tag sponsorship

* fix: remove organization sponsorship test

* feat: remove more i8n

* remove unused css from app/views/organizations/_sidebar_additional.html.erb

* feat: remove sponsorship relationship from tag and organization

* remove seed

* feat: remove all Sponsor related specs

* feat: remove model, associated i8n and specs

* feat: remove sponsor from navbar

* feat: add a guard clause if we're unable to constantinize the purchase_type

* feat; remove sponsorship related tests

* feat: remove sponsorship relationship

* feat: remov especs related to sponsorship

* feat: remove tag sponsorship validation

* feat: remove the sponsorship factory
This commit is contained in:
Ridhwana 2022-10-04 19:02:44 +02:00 committed by GitHub
parent b4afd5ee14
commit 36f5d168d8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
20 changed files with 6 additions and 336 deletions

View file

@ -278,29 +278,8 @@
}
}
}
// Sidebar sponsors
.sidebar-sponsor {
color: var(--card-color-tertiary);
img {
width: 100%;
max-width: 140px;
margin-bottom: var(--su-2);
}
}
// Todo: Not really sure what that is.. some sort of sponsorship widget...
.sidebar-sponsorship-level {
text-align: center;
font-weight: bold;
width: calc(100% - 6px);
padding: 26px 0px;
border-radius: 3px;
margin-bottom: 10px;
font-family: $helvetica-condensed;
font-stretch: condensed;
background: var(--card-secondary-bg);
}
.crayons-sponsorship-article {
margin-bottom: 10px;

View file

@ -29,7 +29,6 @@ class Organization < ApplicationRecord
has_many :notifications, dependent: :delete_all
has_many :organization_memberships, dependent: :delete_all
has_many :profile_pins, as: :profile, inverse_of: :profile, dependent: :destroy
has_many :sponsorships, dependent: :destroy
has_many :unspent_credits, -> { where spent: false }, class_name: "Credit", inverse_of: :organization
has_many :users, through: :organization_memberships

View file

@ -1,57 +0,0 @@
class Sponsorship < ApplicationRecord
LEVELS = %w[gold silver bronze tag media devrel].freeze
METAL_LEVELS = %w[gold silver bronze].freeze
STATUSES = %w[none pending live].freeze
SPONSORABLE_TYPES = %w[Tag ActsAsTaggableOn::Tag].freeze
# media has no fixed amount of credits
CREDITS = {
gold: 6_000,
silver: 500,
bronze: 100,
tag: 300,
devrel: 500
}.with_indifferent_access.freeze
belongs_to :user
belongs_to :organization, inverse_of: :sponsorships
belongs_to :sponsorable, polymorphic: true, optional: true
validates :level, presence: true, inclusion: { in: LEVELS }
validates :status, presence: true, inclusion: { in: STATUSES }
validates :url, url: { allow_blank: true, no_local: true, schemes: %w[http https] }
validates :featured_number, presence: true
validates :sponsorable_type, inclusion: {
in: SPONSORABLE_TYPES,
allow_blank: true,
message: I18n.t("models.sponsorship.invalid_type")
}
validate :validate_tag_uniqueness, if: proc { level.to_s == "tag" }
validate :validate_level_uniqueness, if: proc { METAL_LEVELS.include?(level) }
LEVELS.each do |level|
scope level, -> { where(level: level) }
end
scope :live, -> { where(status: :live) }
scope :pending, -> { where(status: :pending) }
scope :unexpired, -> { where("expires_at > ?", Time.current) }
private
def validate_tag_uniqueness
return unless self.class.where(sponsorable: sponsorable, level: :tag)
.exists?(["expires_at > ? AND id != ?", Time.current, id.to_i])
errors.add(:level, I18n.t("models.sponsorship.already_sponsored"))
end
def validate_level_uniqueness
return unless self.class.where(organization: organization)
.exists?(["level IN (?) AND expires_at > ? AND id != ?", METAL_LEVELS, Time.current, id.to_i])
levels = METAL_LEVELS.map { |l| I18n.t("models.sponsorship.level.#{l}") }.to_sentence(locale: I18n.locale)
errors.add(:level, I18n.t("models.sponsorship.only_one_level", levels: levels))
end
end

View file

@ -2,8 +2,7 @@
# define what we mean when we "tag" something.
#
# These tags can be arbitrary or supported (e.g. `tag.supported ==
# true`). We allow for sponsorship of tags (see `belongs_to
# :sponsorship`). Some tags have moderators. These tags can create a
# true`). Some tags have moderators. These tags can create a
# defacto "sub-community" within a Forem.
#
# Sometimes we need to consolidate tags (e.g. rubyonrails and rails).
@ -39,8 +38,6 @@ class Tag < ActsAsTaggableOn::Tag
has_many :articles, through: :taggings, source: :taggable, source_type: "Article"
has_one :sponsorship, as: :sponsorable, inverse_of: :sponsorable, dependent: :destroy
mount_uploader :profile_image, ProfileImageUploader
mount_uploader :social_image, ProfileImageUploader

View file

@ -110,7 +110,6 @@ class User < ApplicationRecord
has_many :subscribers, through: :source_authored_user_subscriptions, dependent: :destroy
has_many :tweets, dependent: :nullify
has_many :devices, dependent: :delete_all
has_many :sponsorships, dependent: :delete_all
mount_uploader :profile_image, ProfileImageUploader

View file

@ -54,6 +54,9 @@ module Credits
credits_purchases_by_type = credits_purchases_with_purchase.select do |row|
row.purchase_type == purchase_type
end
next unless purchase_type.constantize
purchase_set = purchase_type.constantize.where(id: credits_purchases_by_type.map(&:purchase_id))
credits_purchases_by_type.each do |credit_purchase|
purchase = purchase_set.detect { |set| set.id == credit_purchase.purchase_id }

View file

@ -95,14 +95,6 @@ en:
the_community_mascot: The community mascot
user_experience:
message: 'must be be a 3 or 6 character hex (starting with #)'
sponsorship:
invalid_type: is not a sponsorable type
already_sponsored: The tag is already sponsored
only_one_level: You can have only one sponsorship of %{levels}
level:
gold: gold
silver: silver
bronze: bronze
tag:
alias_for: alias_for must refer to an existing tag
tag_adjustment:

View file

@ -95,14 +95,6 @@ fr:
the_community_mascot: The community mascot
user_experience:
message: 'must be be a 3 or 6 character hex (starting with #)'
sponsorship:
invalid_type: is not a sponsorable type
already_sponsored: The tag is already sponsored
only_one_level: You can have only one sponsorship of %{levels}
level:
gold: gold
silver: silver
bronze: bronze
tag:
alias_for: alias_for must refer to an existing tag
tag_adjustment:

View file

@ -39,7 +39,6 @@ en:
Podcasts: Podcasts
Privacy Policy: Privacy Policy
Reading List: Reading List
Sponsors: Sponsors
Tags: Tags
Terms of use: Terms of use
Videos: Videos

View file

@ -39,7 +39,6 @@ fr:
Podcasts: Podcasts
Privacy Policy: Privacy Policy
Reading List: Reading List
Sponsors: Sponsors
Tags: Tags
Terms of use: Terms of use
Videos: Videos

View file

@ -577,20 +577,6 @@ Faker::Config.locale = loc
##############################################################################
seeder.create_if_none(Sponsorship) do
organizations = Organization.take(3)
organizations.each do |organization|
Sponsorship.create!(
organization: organization,
user: User.order(Arel.sql("RANDOM()")).first,
level: "silver",
blurb_html: Faker::Hacker.say_something_smart,
)
end
end
##############################################################################
seeder.create_if_none(NavigationLink) do
Rake::Task["navigation_links:update"].invoke
end

View file

@ -1,7 +0,0 @@
FactoryBot.define do
factory :sponsorship do
user
organization
level { "bronze" }
end
end

View file

@ -15,7 +15,6 @@ RSpec.describe Organization, type: :model do
it { is_expected.to have_many(:notifications).dependent(:delete_all) }
it { is_expected.to have_many(:organization_memberships).dependent(:delete_all) }
it { is_expected.to have_many(:profile_pins).dependent(:destroy) }
it { is_expected.to have_many(:sponsorships).dependent(:destroy) }
it { is_expected.to have_many(:unspent_credits).class_name("Credit") }
it { is_expected.to have_many(:users).through(:organization_memberships) }
@ -256,7 +255,7 @@ RSpec.describe Organization, type: :model do
# Create an organization and article, verify the article has cached the initial profile
# image of the organization.
original_org = create(:organization, profile_image: File.open(Rails.root.join("app/assets/images/1.png")))
original_org = create(:organization, profile_image: Rails.root.join("app/assets/images/1.png").open)
article = create(:article, organization: original_org)
expect(article.cached_organization.profile_image_url).to eq(original_org.profile_image_url)

View file

@ -1,120 +0,0 @@
require "rails_helper"
RSpec.describe Sponsorship, type: :model do
describe "constants" do
it "has the correct values for constants" do
expect(Sponsorship::LEVELS).to eq(%w[gold silver bronze tag media devrel])
expect(Sponsorship::METAL_LEVELS).to eq(%w[gold silver bronze])
expect(Sponsorship::STATUSES).to eq(%w[none pending live])
expected_credits = { gold: 6000, silver: 500, bronze: 100, tag: 300, devrel: 500 }.with_indifferent_access
expect(Sponsorship::CREDITS).to eq(expected_credits)
end
end
describe "#url" do
let(:sponsorship) { build(:sponsorship) }
it "accepts a blank url" do
sponsorship.url = ""
expect(sponsorship).to be_valid
end
it "accepts a HTTP url" do
sponsorship.url = "http://example.com"
expect(sponsorship).to be_valid
end
it "accepts a HTTPS url" do
sponsorship.url = "https://example.com"
expect(sponsorship).to be_valid
end
it "does not accept an invalid url" do
sponsorship.url = "example.com"
expect(sponsorship).not_to be_valid
end
end
describe "validations" do
let(:user) { create(:user, :org_member) }
let(:org) { user.organizations.first }
describe "builtin validations" do
it { is_expected.to belong_to(:organization).inverse_of(:sponsorships) }
it { is_expected.to belong_to(:sponsorable).optional }
it { is_expected.to belong_to(:user) }
it { is_expected.to have_db_index(%i[sponsorable_id sponsorable_type]) }
it { is_expected.to have_db_index(:level) }
it { is_expected.to have_db_index(:status) }
it { is_expected.to validate_inclusion_of(:level).in_array(Sponsorship::LEVELS) }
it { is_expected.to validate_inclusion_of(:status).in_array(Sponsorship::STATUSES) }
it { is_expected.to validate_presence_of(:level) }
it { is_expected.to validate_presence_of(:status) }
it { is_expected.not_to allow_values(nil).for(:featured_number) }
it { is_expected.to allow_values(nil).for(:expires_at) }
end
it "forbids an org to have multiple 'expiring' (bronze-silver-gold) sponsorships" do
create(:sponsorship, level: :gold, organization: org, expires_at: 2.days.from_now)
bronze_sponsorship = build(:sponsorship, level: :bronze, organization: org)
expect(bronze_sponsorship).not_to be_valid
expect(bronze_sponsorship.errors[:level]).to be_present
end
it "allows to create a new sponsorship for the same org if the previous one is expired" do
create(:sponsorship, expires_at: 1.day.ago, user: user, organization: org, level: :bronze)
bronze_sponsorship = build(:sponsorship, level: :bronze, user: user, organization: org)
expect(bronze_sponsorship).to be_valid
end
it "allows to create a new sponsorship for the same level for another org" do
create(:sponsorship, level: :gold, organization: org, expires_at: 2.days.from_now)
other_org = create(:organization)
gold_sponsorship = build(:sponsorship, level: :gold, organization: other_org)
expect(gold_sponsorship).to be_valid
end
context "when tag sponsorships" do
let(:python) { create(:tag, name: "python") }
let(:ruby) { create(:tag, name: "ruby") }
it "allows an org to have multiple tag sponsorships on different tags" do
create(:sponsorship, level: :tag, organization: org, expires_at: 2.days.from_now, sponsorable: python)
tag_sponsorship = build(:sponsorship, level: :tag, organization: org, sponsorable: ruby)
expect(tag_sponsorship).to be_valid
end
it "allows to create a new tag sponsorship if the previous one is expired" do
create(:sponsorship, user: user, organization: org, expires_at: 1.day.ago, level: :tag, sponsorable: ruby)
ruby_sponsorship = build(:sponsorship, user: user, organization: org, level: :tag, sponsorable: ruby)
expect(ruby_sponsorship).to be_valid
end
it "forbids an org to have multiple active tag sponsorships on the same tag" do
tag = create(:tag, name: "python")
create(:sponsorship, level: :tag, organization: org, sponsorable: tag, expires_at: 2.days.from_now)
tag_sponsorship = build(:sponsorship, level: :tag, organization: org, sponsorable: tag)
expect(tag_sponsorship).not_to be_valid
expect(tag_sponsorship.errors[:level]).to be_present
end
it "forbids different orgs to have active sponsorships on the same tag" do
other_org = create(:organization)
create(:sponsorship, level: :tag, organization: org, sponsorable: python, expires_at: 2.days.from_now)
tag_sponsorship = build(:sponsorship, level: :tag, organization: other_org, sponsorable: python)
expect(tag_sponsorship).not_to be_valid
expect(tag_sponsorship.errors[:level]).to be_present
end
it "ensures sponsorable_type is loadable when present" do
sponsorship = build(:sponsorship, user: user, organization: org, sponsorable_type: "Unsponsorable")
expect(sponsorship).not_to be_valid
expect(sponsorship.errors[:sponsorable_type]).to include("is not a sponsorable type")
end
end
end
end

View file

@ -14,8 +14,6 @@ RSpec.describe Tag, type: :model do
subject { tag }
it { is_expected.to belong_to(:badge).optional }
it { is_expected.to have_one(:sponsorship).inverse_of(:sponsorable).dependent(:destroy) }
it { is_expected.to validate_length_of(:name).is_at_most(30) }
it { is_expected.to validate_presence_of(:category) }

View file

@ -43,49 +43,6 @@ RSpec.describe "Credits", type: :request do
expect(response.body).to include(listing.title)
end
it "does not show sponsorship purchases to org members" do
org = org_member.organizations.first
sponsorship = create(:sponsorship, organization: org, user: org_admin)
purchase_params = { organization: org, purchase_type: sponsorship.class.name, purchase_id: sponsorship.id }
create(:credit, params.merge(purchase_params))
sign_in org_member
get credits_path
expect(response.body).to include("Purchase history")
expect(response.body).not_to include("Sponsorship")
expect(response.body).not_to include(sponsorship.level)
end
it "shows sponsorship purchases to org admins" do
org = org_admin.organizations.first
sponsorship = create(:sponsorship, organization: org, user: org_admin)
purchase_params = { organization: org, purchase_type: sponsorship.class.name, purchase_id: sponsorship.id }
create(:credit, params.merge(purchase_params))
sign_in org_admin
get credits_path
expect(response.body).to include("Purchase history")
expect(response.body).to include("Sponsorship")
expect(response.body).to include(sponsorship.level.titleize)
end
it "shows tag sponsorship purchases to org admins" do
org = org_admin.organizations.first
tag = create(:tag)
sponsorship = create(:sponsorship, organization: org, user: org_admin, level: :tag, sponsorable: tag)
purchase_params = { organization: org, purchase_type: sponsorship.class.name, purchase_id: sponsorship.id }
create(:credit, params.merge(purchase_params))
sign_in org_admin
get credits_path
expect(response.body).to include("Purchase history")
expect(response.body).to include("Sponsorship")
expect(response.body).to include(tag.name)
end
it "shows unattributed purchases" do
purchase_params = { user: user }
create(:credit, params.merge(purchase_params))

View file

@ -20,18 +20,6 @@ RSpec.describe "Stories::TaggedArticlesIndex", type: :request do
create(:article, tags: tag.name, score: 5)
end
def create_live_sponsor(org, tag)
create(
:sponsorship,
level: :tag,
blurb_html: "<p>Oh Yeah!!!</p>",
status: "live",
organization: org,
sponsorable: tag,
expires_at: 30.days.from_now,
)
end
context "with caching headers" do
it "renders page and sets proper headers", :aggregate_failures do
get "/t/#{tag.name}"
@ -114,16 +102,6 @@ RSpec.describe "Stories::TaggedArticlesIndex", type: :request do
expect(response).to have_http_status(:moved_permanently)
end
it "does not render sponsor if not live" do
sponsorship = create(
:sponsorship, level: :tag, tagline: "Oh Yeah!!!", status: "pending", organization: org, sponsorable: tag
)
get "/t/#{tag.name}"
expect(response.body).not_to include("is sponsored by")
expect(response.body).not_to include(sponsorship.tagline)
end
it "shows meta keywords if set" do
allow(Settings::General).to receive(:meta_keywords).and_return({ tag: "software engineering, ruby" })
get "/t/#{tag.name}"

View file

@ -122,11 +122,6 @@ RSpec.describe "UserProfiles", type: :request do
expect(response.body).to include user.profile_image_url
end
it "renders no sponsors if not sponsor" do
get organization.path
expect(response.body).not_to include "Gold Community Sponsor"
end
it "renders organization name properly encoded" do
organization.update(name: "Org & < ' \" 1")
get organization.path

View file

@ -5,7 +5,6 @@ RSpec.describe Credits::Ledger, type: :service do
let(:org) { create(:organization) }
let(:user_listing) { create(:listing, user: user) }
let(:org_listing) { create(:listing, organization: org) }
let(:sponsorship) { create(:sponsorship, user: user, organization: org) }
def buy(purchaser, purchase, cost)
params = {
@ -47,13 +46,4 @@ RSpec.describe Credits::Ledger, type: :service do
items = described_class.call(user)[[Organization.name, org.id]]
expect(items).to be_nil
end
it "returns sponsorships purchases" do
create(:organization_membership, user_id: user.id, organization_id: org.id, type_of_user: "admin")
buy(org, sponsorship, 3)
items = described_class.call(user)[[Organization.name, org.id]]
expect(items.length).to be(1)
item = items.first
expect(item.purchase.is_a?(Sponsorship)).to be(true)
end
end

View file

@ -21,14 +21,6 @@ RSpec.describe Users::Delete, type: :service do
expect(cache_bust).to have_received(:call).with("/#{user.username}")
end
it "deletes user's sponsorships" do
create(:sponsorship, user: user)
expect do
described_class.call(user)
end.to change(Sponsorship, :count).by(-1)
end
it "deletes user's follows" do
create(:follow, follower: user)
create(:follow, followable: user)