Add new GraphQL types for budget investments

- added 2 new types
- modified the models to get data through graphQL
- modified the corresponding spec
- also testing that hidden comments do not show up
- modified comments specs bc now it returns comments on budget
  investments
This commit is contained in:
cyrillefr
2024-06-06 13:11:56 +02:00
committed by Javi Martín
parent 5a45049273
commit 5ec6337d47
10 changed files with 133 additions and 6 deletions

View File

@@ -0,0 +1,13 @@
module Types
class BudgetInvestmentType < Types::BaseObject
field :id, ID, null: false
field :public_author, Types::UserType, null: true
field :price, GraphQL::Types::BigInt, null: true
field :feasibility, String, null: true
field :title, String, null: true
field :description, String, null: true
field :location, String, null: true
field :comments, Types::CommentType.connection_type, null: true
field :comments_count, Integer, null: true
end
end

View File

@@ -0,0 +1,19 @@
module Types
class BudgetType < Types::BaseObject
field :id, ID, null: false
field :name, String, null: true
field :phase, String, null: true
field :investments, Types::BudgetInvestmentType.connection_type, "Returns all investments", null: false
field :investment, Types::BudgetInvestmentType, null: false do
argument :id, ID, required: true, default_value: false
end
def investments
Budget::Investment.public_for_api
end
def investment(id:)
Budget::Investment.find(id)
end
end
end

View File

@@ -1,5 +1,10 @@
module Types module Types
class QueryType < Types::BaseObject class QueryType < Types::BaseObject
field :budgets, Types::BudgetType.connection_type, "Returns all budgets", null: false
field :budget, Types::BudgetType, "Returns budget for ID", null: false do
argument :id, ID, required: true, default_value: false
end
field :comments, Types::CommentType.connection_type, "Returns all comments", null: false field :comments, Types::CommentType.connection_type, "Returns all comments", null: false
field :comment, Types::CommentType, "Returns comment for ID", null: false do field :comment, Types::CommentType, "Returns comment for ID", null: false do
argument :id, ID, required: true, default_value: false argument :id, ID, required: true, default_value: false
@@ -47,6 +52,14 @@ module Types
argument :id, ID, required: true, default_value: false argument :id, ID, required: true, default_value: false
end end
def budgets
Budget.public_for_api
end
def budget(id:)
Budget.find(id)
end
def comments def comments
Comment.public_for_api Comment.public_for_api
end end

View File

@@ -58,6 +58,7 @@ class Budget < ApplicationRecord
scope :balloting, -> { where(phase: "balloting") } scope :balloting, -> { where(phase: "balloting") }
scope :reviewing_ballots, -> { where(phase: "reviewing_ballots") } scope :reviewing_ballots, -> { where(phase: "reviewing_ballots") }
scope :finished, -> { where(phase: "finished") } scope :finished, -> { where(phase: "finished") }
scope :public_for_api, -> { published }
class << self; undef :open; end class << self; undef :open; end
scope :open, -> { where.not(phase: "finished") } scope :open, -> { where.not(phase: "finished") }

View File

@@ -13,6 +13,7 @@ class Budget
include Mappable include Mappable
include Documentable include Documentable
include SDG::Relatable include SDG::Relatable
include HasPublicAuthor
acts_as_taggable_on :valuation_tags acts_as_taggable_on :valuation_tags
acts_as_votable acts_as_votable
@@ -111,6 +112,7 @@ class Budget
end end
scope :for_render, -> { includes(:heading) } scope :for_render, -> { includes(:heading) }
scope :public_for_api, -> { where(budget: Budget.public_for_api) }
def self.by_valuator(valuator_id) def self.by_valuator(valuator_id)
where(budget_valuator_assignments: { valuator_id: valuator_id }).joins(:valuator_assignments) where(budget_valuator_assignments: { valuator_id: valuator_id }).joins(:valuator_assignments)

View File

@@ -38,7 +38,10 @@ class Comment < ApplicationRecord
scope :sort_by_flags, -> { order(flags_count: :desc, updated_at: :desc) } scope :sort_by_flags, -> { order(flags_count: :desc, updated_at: :desc) }
scope :public_for_api, -> do scope :public_for_api, -> do
not_valuations not_valuations
.where(commentable: [Debate.public_for_api, Proposal.public_for_api, Poll.public_for_api]) .where(commentable: [Debate.public_for_api,
Proposal.public_for_api,
Poll.public_for_api,
Budget::Investment.public_for_api])
end end
scope :sort_by_most_voted, -> { order(confidence_score: :desc, created_at: :desc) } scope :sort_by_most_voted, -> { order(confidence_score: :desc, created_at: :desc) }

View File

@@ -130,6 +130,8 @@ The models are the following:
| `User` | Users | | `User` | Users |
| `Debate` | Debates | | `Debate` | Debates |
| `Proposal` | Proposals | | `Proposal` | Proposals |
| `Budget` | Participatory budgets |
| `Budget::Investment` | Budget investments |
| `Comment` | Comments on debates, proposals and other comments | | `Comment` | Comments on debates, proposals and other comments |
| `Geozone` | Geozones (districts) | | `Geozone` | Geozones (districts) |
| `ProposalNotification` | Notifications related to proposals | | `ProposalNotification` | Notifications related to proposals |

View File

@@ -130,6 +130,8 @@ La lista de modelos es la siguiente:
| `User` | Usuarios | | `User` | Usuarios |
| `Debate` | Debates | | `Debate` | Debates |
| `Proposal` | Propuestas | | `Proposal` | Propuestas |
| `Budget` | Presupuestos participativos |
| `Budget::Investment` | Proyectos de gasto |
| `Comment` | Comentarios en debates, propuestas y otros comentarios | | `Comment` | Comentarios en debates, propuestas y otros comentarios |
| `Geozone` | Geozonas (distritos) | | `Geozone` | Geozonas (distritos) |
| `ProposalNotification` | Notificaciones asociadas a propuestas | | `ProposalNotification` | Notificaciones asociadas a propuestas |

View File

@@ -193,6 +193,17 @@ describe "Consul Schema" do
end end
end end
describe "Budgets" do
it "does not include unpublished budgets" do
create(:budget, :drafting, name: "Draft")
response = execute("{ budgets { edges { node { name } } } }")
received_names = extract_fields(response, "budgets", "name")
expect(received_names).to eq []
end
end
describe "Debates" do describe "Debates" do
it "does not include hidden debates" do it "does not include hidden debates" do
create(:debate, title: "Visible") create(:debate, title: "Visible")
@@ -252,16 +263,17 @@ describe "Consul Schema" do
end end
describe "Comments" do describe "Comments" do
it "only returns comments from proposals, debates and polls" do it "only returns comments from proposals, debates, polls and Budget::Investment" do
create(:comment, commentable: create(:proposal)) create(:comment, commentable: create(:proposal))
create(:comment, commentable: create(:debate)) create(:comment, commentable: create(:debate))
create(:comment, commentable: create(:poll)) create(:comment, commentable: create(:poll))
build(:comment, commentable: create(:budget_investment)).save!(skip_validation: true) create(:comment, commentable: create(:topic))
create(:comment, commentable: create(:budget_investment))
response = execute("{ comments { edges { node { commentable_type } } } }") response = execute("{ comments { edges { node { commentable_type } } } }")
received_commentables = extract_fields(response, "comments", "commentable_type") received_commentables = extract_fields(response, "comments", "commentable_type")
expect(received_commentables).to match_array ["Proposal", "Debate", "Poll"] expect(received_commentables).to match_array ["Proposal", "Debate", "Poll", "Budget::Investment"]
end end
it "displays comments of authors even if public activity is set to false" do it "displays comments of authors even if public activity is set to false" do
@@ -336,6 +348,19 @@ describe "Consul Schema" do
expect(received_comments).to match_array ["I can see the poll"] expect(received_comments).to match_array ["I can see the poll"]
end end
it "does not include comments from hidden investments" do
visible_investment = create(:budget_investment)
hidden_investment = create(:budget_investment, :hidden)
create(:comment, commentable: visible_investment, body: "I can see the investment")
create(:comment, commentable: hidden_investment, body: "This investment is hidden!")
response = execute("{ comments { edges { node { body } } } }")
received_comments = extract_fields(response, "comments", "body")
expect(received_comments).to match_array ["I can see the investment"]
end
it "does not include comments of debates that are not public" do it "does not include comments of debates that are not public" do
not_public_debate = create(:debate, :hidden) not_public_debate = create(:debate, :hidden)
not_public_debate_comment = create(:comment, commentable: not_public_debate) not_public_debate_comment = create(:comment, commentable: not_public_debate)
@@ -369,6 +394,16 @@ describe "Consul Schema" do
expect(received_comments).not_to include(not_public_poll_comment.body) expect(received_comments).not_to include(not_public_poll_comment.body)
end end
it "does not include comments of investments that are not public" do
investment = create(:budget_investment, budget: create(:budget, :drafting))
not_public_investment_comment = create(:comment, commentable: investment)
response = execute("{ comments { edges { node { body } } } }")
received_comments = extract_fields(response, "comments", "body")
expect(received_comments).not_to include(not_public_investment_comment.body)
end
it "only links public comments" do it "only links public comments" do
user = create(:administrator).user user = create(:administrator).user
create(:comment, author: user, body: "Public") create(:comment, author: user, body: "Public")
@@ -642,4 +677,35 @@ describe "Consul Schema" do
expect(Time.zone.parse(received_timestamps.first)).to eq Time.zone.parse("2017-12-31 9:00:00") expect(Time.zone.parse(received_timestamps.first)).to eq Time.zone.parse("2017-12-31 9:00:00")
end end
end end
describe "Budget investment" do
it "does not include hidden comments" do
budget = create(:budget)
investment = create(:budget_investment, budget: budget)
create(:comment, commentable: investment, body: "Visible")
create(:comment, :hidden, commentable: investment, body: "Hidden")
query = <<~GRAPHQL
{
budget(id: #{budget.id}) {
investment(id: #{investment.id}) {
comments {
edges {
node {
body
}
}
}
}
}
}
GRAPHQL
response = execute(query)
received_bodies = extract_fields(response, "budget.investment.comments", "body")
expect(received_bodies).to eq ["Visible"]
end
end
end end

View File

@@ -175,8 +175,14 @@ describe Comment do
expect(Comment.public_for_api).to be_empty expect(Comment.public_for_api).to be_empty
end end
it "does not return comments on elements which are not debates or proposals" do it "returns comments on budget investments" do
create(:comment, commentable: create(:budget_investment)) comment = create(:comment, commentable: create(:budget_investment))
expect(Comment.public_for_api).to eq [comment]
end
it "does not return comments on elements which are not debates, proposals or budget investments" do
create(:comment, commentable: create(:topic))
expect(Comment.public_for_api).to be_empty expect(Comment.public_for_api).to be_empty
end end