Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cria endpoint para solicitação de participação em projetos #85

Merged
merged 11 commits into from
Feb 7, 2024
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
93 changes: 92 additions & 1 deletion api_doc.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ Retorno esperado:

---

## 1. Mudar status de um convite para cancelado
## 2. Mudar status de um convite para cancelado

### Endpoint

Expand Down Expand Up @@ -100,6 +100,97 @@ Erro para objeto não encontrado (Status: 404)

---

## 3 Criar solicitação para participação em projetos

### Endpoint

```shell
POST /api/v1/proposals
```

#### Corpo da requisição:

A requisição requer o ID de um projeto existente na plataforma Cola?Bora!, o ID válido de um perfil da Portfoliorrr e uma mensagem opcional.

```json
{
"proposal":
{
"project_id": 1,
"profile_id": 3,
"email": "user@email.com",
"message": "Gostaria de participar do projeto!",
}
}
```

<br>

Retorno esperado caso a requisição seja bem sucedida. (Status: 201)

```json
{
"data":
{
"proposal_id": 1
}
}
```

<br>



### Erros tratados

Retorno caso o projeto não exista na plataforma Cola?Bora!. (Status: 404)

```json
{
"errors": ["Projeto não encontrado"]
}
```

Erros de ID de Perfil (Status: 409)

```json
// ID de perfil em branco
{
"errors": ["ID de perfil não pode ficar em branco", "ID de Perfil não é um número"]
}

// ID de perfil menor ou igual a zero
{
"errors": ["ID de Perfil deve ser maior ou igual a 1"]
}
```

Erros de Solicitação (Status: 409)

```json
// Usuário já tem solicitação pendente para o projeto
{
"errors": ["Usuário já tem solicitação pendente para o projeto"]
}

// Usuário já é colaborador do projeto
{
"errors": ["Usuário já faz parte deste projeto"]
}
```

Erro interno de servidor (Status: 500)

Retorno esperado:

```json
{
"errors": ["Erro interno de servidor."]
}
```

---

## Observações Gerais
- Todos os endpoints retornam dados no formato JSON.
- Em caso de sucesso, a resposta terá o código 200.
Expand Down
27 changes: 27 additions & 0 deletions app/controllers/api/v1/proposals_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
module Api
module V1
class ProposalsController < Api::V1::ApiController
before_action :set_project, only: %i[create]

def create
proposal = @project.proposals.new(proposal_params)

return render json: { data: { proposal_id: proposal.id } }, status: :created if proposal.save

render json: { errors: proposal.errors.full_messages }, status: :conflict
end

private

def set_project
@project = Project.find(params[:proposal][:project_id])
rescue ActiveRecord::RecordNotFound
render json: { errors: I18n.t('.missing_project') }, status: :not_found
end

def proposal_params
params.require(:proposal).permit(:profile_id, :message, :email)
end
end
end
end
1 change: 1 addition & 0 deletions app/models/project.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ class Project < ApplicationRecord
has_many :documents, dependent: :destroy
has_many :meetings, dependent: :destroy
has_many :project_job_categories, dependent: :destroy
has_many :proposals, dependent: :destroy

validates :title, :description, :category, presence: true

Expand Down
29 changes: 29 additions & 0 deletions app/models/proposal.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
class Proposal < ApplicationRecord
belongs_to :project

validates :profile_id, :email, presence: true
validates :profile_id, numericality: { greater_than_or_equal_to: 1 }
validate :validate_participation, :validate_pending_proposal

enum status: {
pending: 1,
accepted: 5,
declined: 10,
cancelled: 15
}

private

def validate_participation
participation = UserRole.joins(:user).find_by(user: { email: }, project_id:)&.active

errors.add :base, I18n.t(:user_already_member_error) unless participation.nil?
end

def validate_pending_proposal
proposal = Proposal.find_by(profile_id:, project_id:)
return unless proposal&.pending?

errors.add :base, I18n.t(:user_has_pending_proposals)
end
end
3 changes: 2 additions & 1 deletion config/locales/general.pt-BR.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,5 @@ pt-BR:
profile: Perfil de %{name}
profile_not_available: Perfil não disponível
save: Salvar
model_description: Descrição do %{model}
model_description: Descrição do %{model}
missing_project: Projeto não encontrado
13 changes: 13 additions & 0 deletions config/locales/models/proposals.pt-BR.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
pt-BR:
activerecord:
model:
proposal:
one: Solicitação
other: Solicitações
attributes:
proposal:
profile_id: ID de Perfil
project: Projeto
email: E-mail
user_already_member_error: Usuário já faz parte deste projeto
user_has_pending_proposals: Usuário já tem solicitação pendente para o projeto
1 change: 1 addition & 0 deletions config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
namespace :v1 do
resources :projects, only: %i[index]
resources :invitations, only: %i[index update]
resources :proposals, only: %i[create]
end
end
end
12 changes: 12 additions & 0 deletions db/migrate/20240205204518_create_proposals.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
class CreateProposals < ActiveRecord::Migration[7.1]
def change
create_table :proposals do |t|
t.references :project, null: false, foreign_key: true
t.integer :status, default: 1
t.text :message
t.integer :profile_id, null: false

t.timestamps
end
end
end
5 changes: 5 additions & 0 deletions db/migrate/20240206194424_add_email_to_proposal.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class AddEmailToProposal < ActiveRecord::Migration[7.1]
def change
add_column :proposals, :email, :string, null: false
end
end
14 changes: 13 additions & 1 deletion db/schema.rb

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 9 additions & 0 deletions spec/factories/proposals.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
FactoryBot.define do
factory :proposal do
project
status { :pending }
message { 'Mensagem padrão' }
sequence(:profile_id) { |n| n }
sequence(:email) { |n| "proposer#{n}@email.com" }
end
end
65 changes: 65 additions & 0 deletions spec/models/proposal_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
require 'rails_helper'

RSpec.describe Proposal, type: :model do
context '#valid?' do
it 'falso se projeto não existe' do
proposal = Proposal.new(project_id: 999)

expect(proposal).not_to be_valid
expect(proposal.errors).to include :project
expect(proposal.errors.full_messages).to include 'Projeto é obrigatório(a)'
end

it 'falso se id de projeto for vazio' do
proposal = Proposal.new(project_id: '')

expect(proposal).not_to be_valid
expect(proposal.errors).to include :project
expect(proposal.errors.full_messages).to include 'Projeto é obrigatório(a)'
end

it 'falso se email for vazio' do
proposal = Proposal.new(email: '')

expect(proposal).not_to be_valid
expect(proposal.errors).to include :email
expect(proposal.errors.full_messages).to include 'E-mail não pode ficar em branco'
end

it 'falso se id de perfil for vazio' do
proposal = Proposal.new(profile_id: '')

expect(proposal).not_to be_valid
expect(proposal.errors).to include :profile_id
expect(proposal.errors.full_messages).to include 'ID de Perfil não pode ficar em branco'
end

it 'falso se id de perfil igual ou menor que zero' do
proposal = Proposal.new(profile_id: -1)

expect(proposal).not_to be_valid
expect(proposal.errors).to include :profile_id
expect(proposal.errors.full_messages).to include 'ID de Perfil deve ser maior ou igual a 1'
end

it 'verdadeiro se mensagem estiver em branco' do
proposal = Proposal.new(message: '')

proposal.valid?

expect(proposal.errors).not_to include :message
end

it 'verdadeiro se os parâmetros são válidos' do
project = create :project
proposal = Proposal.new(
profile_id: 5,
project:,
message: 'Me aceita',
email: 'proposal@email.com'
)

expect(proposal).to be_valid
end
end
end
Loading
Loading