From bb525ff641c89a1021def1289f3e427e90ff366d Mon Sep 17 00:00:00 2001 From: Rafael Carvalho Date: Sat, 27 Jun 2026 15:38:17 -0300 Subject: [PATCH 01/10] refactor(#46): saikuro de app/helpers < 10 --- app/helpers/application_helper.rb_cyclo.html | 82 ++++++++++++++++++ app/helpers/dashboards_helper.rb_cyclo.html | 82 ++++++++++++++++++ app/helpers/sessions_helper.rb_cyclo.html | 82 ++++++++++++++++++ index_cyclo.html | 89 ++++++++++++++++++++ 4 files changed, 335 insertions(+) create mode 100644 app/helpers/application_helper.rb_cyclo.html create mode 100644 app/helpers/dashboards_helper.rb_cyclo.html create mode 100644 app/helpers/sessions_helper.rb_cyclo.html create mode 100644 index_cyclo.html diff --git a/app/helpers/application_helper.rb_cyclo.html b/app/helpers/application_helper.rb_cyclo.html new file mode 100644 index 0000000000..df3cdb9f91 --- /dev/null +++ b/app/helpers/application_helper.rb_cyclo.html @@ -0,0 +1,82 @@ +Cyclometric Complexity + + +
+

Class : ApplicationHelper

+
Total Complexity: 0
+
Total Lines: 2
+ + +
MethodComplexity# Lines
+
+ + \ No newline at end of file diff --git a/app/helpers/dashboards_helper.rb_cyclo.html b/app/helpers/dashboards_helper.rb_cyclo.html new file mode 100644 index 0000000000..0dcaa5568b --- /dev/null +++ b/app/helpers/dashboards_helper.rb_cyclo.html @@ -0,0 +1,82 @@ +Cyclometric Complexity + + +
+

Class : DashboardsHelper

+
Total Complexity: 0
+
Total Lines: 2
+ + +
MethodComplexity# Lines
+
+ + \ No newline at end of file diff --git a/app/helpers/sessions_helper.rb_cyclo.html b/app/helpers/sessions_helper.rb_cyclo.html new file mode 100644 index 0000000000..79ffcd7473 --- /dev/null +++ b/app/helpers/sessions_helper.rb_cyclo.html @@ -0,0 +1,82 @@ +Cyclometric Complexity + + +
+

Class : SessionsHelper

+
Total Complexity: 0
+
Total Lines: 2
+ + +
MethodComplexity# Lines
+
+ + \ No newline at end of file diff --git a/index_cyclo.html b/index_cyclo.html new file mode 100644 index 0000000000..aff7a1ca7a --- /dev/null +++ b/index_cyclo.html @@ -0,0 +1,89 @@ +Index for cyclomatic complexity + + + +

Index for cyclomatic complexity

+ +
+

Analyzed Files

+ + \ No newline at end of file From c0aa88f9ba28e5122813c5c8d1ad49761dfb96de Mon Sep 17 00:00:00 2001 From: Rafael Carvalho Date: Sat, 27 Jun 2026 19:41:10 -0300 Subject: [PATCH 02/10] chore(#46): atualiza schema com tabelas de envio_formularios e respostas --- .../envio_formularios_controller.rb | 79 +++++++ app/views/envio_formularios/new.html.erb | 35 +++ db/schema.rb | 213 ++++++++++++------ .../responder_formulario_steps.rb | 188 ++++++++++++++++ 4 files changed, 448 insertions(+), 67 deletions(-) create mode 100644 app/controllers/envio_formularios_controller.rb create mode 100644 app/views/envio_formularios/new.html.erb create mode 100644 features/step_definitions/responder_formulario_steps.rb diff --git a/app/controllers/envio_formularios_controller.rb b/app/controllers/envio_formularios_controller.rb new file mode 100644 index 0000000000..4f321608e4 --- /dev/null +++ b/app/controllers/envio_formularios_controller.rb @@ -0,0 +1,79 @@ +class EnvioFormulariosController < ApplicationController + before_action :exigir_discente! + before_action :set_formulario + + def new + if discente_atual&.ja_respondeu?(@formulario) + redirect_to minha_resposta_formulario_path(@formulario), + notice: "Este formulário já foi respondido" + return + end + + @questoes = @formulario.questoes.includes(questao_template: :opcao_questoes) + end + + def create + return redirect_to formularios_path, alert: "Este formulário já foi respondido" if discente_atual&.ja_respondeu?(@formulario) + + respostas_params = params[:respostas] || {} + questoes = @formulario.questoes + erro = mensagem_erro_validacao(questoes, respostas_params) + + return render_erro_validacao(questoes, erro) if erro + + salvar_envio(questoes, respostas_params) + rescue ActiveRecord::RecordInvalid => e + render_erro_salvamento(e.message) + end + + private + + def set_formulario + @formulario = Formulario.find(params[:formulario_id] || params[:id]) + rescue ActiveRecord::RecordNotFound + redirect_to formularios_path, alert: "Formulário não encontrado." + end + + def mensagem_erro_validacao(questoes, respostas_params) + return "Todos os campos obrigatórios devem ser preenchidos" if campos_vazios?(questoes, respostas_params) + return "Por favor, insira um valor válido entre 1 e 5" if valores_invalidos?(questoes, respostas_params) + end + + def campos_vazios?(questoes, respostas_params) + questoes.any? { |q| respostas_params[q.id.to_s].blank? } + end + + def valores_invalidos?(questoes, respostas_params) + questoes.any? do |q| + valor = respostas_params[q.id.to_s].to_s.strip + numerico = Integer(valor, exception: false) + numerico && (numerico < 1 || numerico > 5) + end + end + + def render_erro_validacao(questoes, mensagem) + @questoes = questoes.includes(questao_template: :opcao_questoes) + flash.now[:alert] = mensagem + render :new, status: :unprocessable_entity + end + + def render_erro_salvamento(mensagem) + @questoes = @formulario.questoes.includes(questao_template: :opcao_questoes) + flash.now[:alert] = mensagem + render :new, status: :unprocessable_entity + end + + def salvar_envio(questoes, respostas_params) + envio = EnvioFormulario.new(formulario: @formulario, discente: discente_atual) + + EnvioFormulario.transaction do + envio.save! + questoes.each do |questao| + conteudo = respostas_params[questao.id.to_s].to_s.strip + Resposta.create!(envio_formulario: envio, questao: questao, conteudo: conteudo) + end + end + + redirect_to formularios_path, notice: "Avaliação enviada com sucesso" + end +end diff --git a/app/views/envio_formularios/new.html.erb b/app/views/envio_formularios/new.html.erb new file mode 100644 index 0000000000..b1fd7fdf23 --- /dev/null +++ b/app/views/envio_formularios/new.html.erb @@ -0,0 +1,35 @@ +<% content_for :title, "Responder: #{@formulario.titulo}" %> + + + +

<%= @formulario.titulo %>

+ +<%= form_with url: envio_formularios_path(formulario_id: @formulario.id), method: :post, data: { turbo: false } do |f| %> + <%= hidden_field_tag :formulario_id, @formulario.id %> + + <% @questoes.each_with_index do |questao, i| %> +
+

<%= i + 1 %>. <%= questao.enunciado %>

+ + <% if questao.aberta? %> + <%= text_area_tag "respostas[#{questao.id}]", nil, + placeholder: "Sua resposta...", + required: true, + rows: 3 %> + <% else %> + <% questao.opcao_questoes.each do |opcao| %> + + <% end %> + <% end %> +
+ <% end %> + + <%= submit_tag "Enviar avaliação", class: "btn btn-primary" %> +<% end %> diff --git a/db/schema.rb b/db/schema.rb index 966a18701c..1ef9a25ba0 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -12,107 +12,186 @@ ActiveRecord::Schema[8.1].define(version: 2026_06_16_231812) do - create_table "admins", force: :cascade do |t| + # ── Autenticação (sprint 2) ───────────────────────────────────────────────── + create_table "users", force: :cascade do |t| + t.string "email", null: false + t.string "matricula", null: false + t.string "nome", null: false + t.string "password_digest" + t.string "perfil", null: false + t.boolean "primeiro_acesso", default: true, null: false + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index ["email"], name: "index_users_on_email", unique: true + t.index ["matricula"], name: "index_users_on_matricula", unique: true + end + + # ── Modelo original BDD (sprint 1) ───────────────────────────────────────── + create_table "usuarios", force: :cascade do |t| + t.string "login", null: false + t.string "password_digest", null: false + t.string "email", null: false + t.string "nome", null: false + t.integer "perfil", null: false, default: 0 + t.boolean "primeiro_acesso", null: false, default: true + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index ["login"], name: "index_usuarios_on_login", unique: true + t.index ["email"], name: "index_usuarios_on_email", unique: true + end + + # ── Estrutura organizacional ──────────────────────────────────────────────── + create_table "departamentos", force: :cascade do |t| + t.string "nome", null: false t.datetime "created_at", null: false - t.integer "departamento_id", null: false t.datetime "updated_at", null: false - t.integer "user_id", null: false + t.index ["nome"], name: "index_departamentos_on_nome", unique: true + end + + create_table "admins", force: :cascade do |t| + t.integer "user_id", null: false + t.integer "departamento_id", null: false + t.datetime "created_at", null: false + t.datetime "updated_at", null: false t.index ["departamento_id"], name: "index_admins_on_departamento_id" t.index ["user_id", "departamento_id"], name: "index_admins_on_user_id_and_departamento_id", unique: true t.index ["user_id"], name: "index_admins_on_user_id" end - create_table "departamentos", force: :cascade do |t| + create_table "disciplinas", force: :cascade do |t| + t.string "codigo", null: false + t.string "nome", null: false t.datetime "created_at", null: false - t.string "nome", null: false t.datetime "updated_at", null: false - t.index ["nome"], name: "index_departamentos_on_nome", unique: true + t.index ["codigo"], name: "index_disciplinas_on_codigo", unique: true end - create_table "templates", force: :cascade do |t| + create_table "docentes", force: :cascade do |t| + t.integer "usuario_id", null: false + t.integer "departamento_id", null: false + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + end + + create_table "discentes", force: :cascade do |t| + t.integer "usuario_id", null: false + t.string "matricula", null: false + t.string "curso", null: false t.datetime "created_at", null: false - t.string "nome", null: false - t.string "semestre", null: false t.datetime "updated_at", null: false - t.integer "user_id", null: false - t.index ["user_id"], name: "index_templates_on_user_id" + t.index ["matricula"], name: "index_discentes_on_matricula", unique: true end create_table "turmas", force: :cascade do |t| - t.string "codigo", null: false - t.datetime "created_at", null: false - t.integer "departamento_id", null: false - t.string "nome", null: false - t.datetime "updated_at", null: false + t.string "codigo", null: false + t.string "nome", null: false + t.string "semestre" + t.string "horario" + t.integer "departamento_id", null: false + t.integer "disciplina_id" + t.integer "docente_id" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false t.index ["departamento_id"], name: "index_turmas_on_departamento_id" end + create_table "matriculas", force: :cascade do |t| + t.integer "discente_id", null: false + t.integer "turma_id", null: false + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index ["discente_id", "turma_id"], name: "index_matriculas_on_discente_id_and_turma_id", unique: true + end - create_table "dado_users", force: :cascade do |t| + # ── Templates e formulários ───────────────────────────────────────────────── + create_table "templates", force: :cascade do |t| + t.string "titulo", null: false + t.text "descricao" + t.integer "docente_id", null: false t.datetime "created_at", null: false - t.string "curso" - t.string "email" - t.string "formacao" - t.string "matricula" - t.string "nome" - t.string "ocupacao" t.datetime "updated_at", null: false - t.string "usuario" end - create_table "discentes", force: :cascade do |t| - t.datetime "created_at", null: false - t.string "curso" - t.string "email" - t.string "formacao" - t.string "matricula" - t.string "nome" - t.string "ocupacao" - t.integer "turma_id", null: false - t.datetime "updated_at", null: false - t.string "usuario" - t.index ["turma_id"], name: "index_discentes_on_turma_id" + create_table "questao_templates", force: :cascade do |t| + t.text "enunciado", null: false + t.integer "tipo", null: false, default: 0 + t.integer "template_id", null: false + t.datetime "created_at", null: false + t.datetime "updated_at", null: false end - create_table "docentes", force: :cascade do |t| - t.datetime "created_at", null: false - t.string "departamento" - t.string "email" - t.string "formacao" - t.string "nome" - t.string "ocupacao" - t.string "turma" - t.datetime "updated_at", null: false - t.string "usuario" + create_table "opcao_questoes", force: :cascade do |t| + t.string "texto", null: false + t.integer "questao_template_id", null: false + t.datetime "created_at", null: false + t.datetime "updated_at", null: false end - create_table "turmas", force: :cascade do |t| - t.string "codigo" - t.datetime "created_at", null: false - t.string "semestre" - t.string "turma" - t.datetime "updated_at", null: false + create_table "formularios", force: :cascade do |t| + t.string "titulo", null: false + t.datetime "prazo" + t.integer "turma_id", null: false + t.integer "template_id", null: false + t.datetime "created_at", null: false + t.datetime "updated_at", null: false end + create_table "questoes", force: :cascade do |t| + t.text "enunciado", null: false + t.integer "tipo", null: false, default: 0 + t.integer "formulario_id", null: false + t.integer "questao_template_id", null: false + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + end + create_table "envio_formularios", force: :cascade do |t| + t.integer "formulario_id", null: false + t.integer "discente_id", null: false + t.datetime "enviado_em" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index ["formulario_id", "discente_id"], name: "index_envio_formularios_on_formulario_id_and_discente_id", unique: true + end - create_table "users", force: :cascade do |t| + create_table "respostas", force: :cascade do |t| + t.text "conteudo", null: false + t.integer "envio_formulario_id", null: false + t.integer "questao_id", null: false + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + end + + # ── Dados importados SIGAA ────────────────────────────────────────────────── + create_table "dado_users", force: :cascade do |t| + t.string "curso" + t.string "email" + t.string "formacao" + t.string "matricula" + t.string "nome" + t.string "ocupacao" + t.string "usuario" t.datetime "created_at", null: false - t.string "email", null: false - t.string "matricula", null: false - t.string "nome", null: false - t.string "password_digest" - t.string "perfil", null: false - t.boolean "primeiro_acesso", default: true, null: false t.datetime "updated_at", null: false - t.index ["email"], name: "index_users_on_email", unique: true - t.index ["matricula"], name: "index_users_on_matricula", unique: true end - add_foreign_key "admins", "departamentos" - add_foreign_key "admins", "users" - add_foreign_key "templates", "users" - add_foreign_key "turmas", "departamentos" - - add_foreign_key "discentes", "turmas" + add_foreign_key "admins", "departamentos", column: "departamento_id" + add_foreign_key "admins", "users", column: "user_id" + add_foreign_key "docentes", "usuarios", column: "usuario_id" + add_foreign_key "docentes", "departamentos", column: "departamento_id" + add_foreign_key "discentes", "usuarios", column: "usuario_id" + add_foreign_key "turmas", "departamentos", column: "departamento_id" + add_foreign_key "matriculas", "discentes", column: "discente_id" + add_foreign_key "matriculas", "turmas", column: "turma_id" + add_foreign_key "templates", "docentes", column: "docente_id" + add_foreign_key "questao_templates", "templates", column: "template_id" + add_foreign_key "opcao_questoes", "questao_templates", column: "questao_template_id" + add_foreign_key "formularios", "turmas", column: "turma_id" + add_foreign_key "formularios", "templates", column: "template_id" + add_foreign_key "questoes", "formularios", column: "formulario_id" + add_foreign_key "questoes", "questao_templates", column: "questao_template_id" + add_foreign_key "envio_formularios", "formularios", column: "formulario_id" + add_foreign_key "envio_formularios", "discentes", column: "discente_id" + add_foreign_key "respostas", "envio_formularios", column: "envio_formulario_id" + add_foreign_key "respostas", "questoes", column: "questao_id" end diff --git a/features/step_definitions/responder_formulario_steps.rb b/features/step_definitions/responder_formulario_steps.rb new file mode 100644 index 0000000000..df26ed89ac --- /dev/null +++ b/features/step_definitions/responder_formulario_steps.rb @@ -0,0 +1,188 @@ +require 'securerandom' + +SENHA_DISCENTE_RESP = "senha123".freeze + +# ─── Helpers ────────────────────────────────────────────────────────────────── + +def fazer_login_discente_resp(email) + visit login_path + fill_in "E-mail ou matrícula", with: email + fill_in "Senha", with: SENHA_DISCENTE_RESP + click_button "Entrar" +end + +def parsear_turma_str(turma_str) + partes = turma_str.split(" - ", 2).map(&:strip) + { codigo: partes[0], nome: partes[1] || partes[0] } +end + +def criar_grafo_formulario(turma_str) + dados = parsear_turma_str(turma_str) + + @departamento = Departamento.create!(nome: "Dept BDD #{SecureRandom.hex(4)}") + + # Docente para o Template (modelo original BDD) + usuario_docente = Usuario.create!( + login: "docente_#{SecureRandom.hex(4)}", + email: "docente_#{SecureRandom.hex(4)}@camaar.com", + nome: "Docente BDD", + perfil: :docente, + password: SENHA_DISCENTE_RESP + ) + @docente = Docente.create!(usuario: usuario_docente, departamento: @departamento) + + # Turma com schema Team B (departamento + codigo + nome) + @turma = Turma.create!( + codigo: dados[:codigo], + nome: dados[:nome], + departamento: @departamento + ) + + # Discente (modelo original BDD: belongs_to :usuario, has_many :matriculas) + usuario_discente = Usuario.create!( + login: "discente_#{SecureRandom.hex(4)}", + email: "discente_#{SecureRandom.hex(4)}@camaar.com", + nome: "Discente BDD", + perfil: :discente, + password: SENHA_DISCENTE_RESP + ) + @discente = Discente.create!( + usuario: usuario_discente, + matricula: SecureRandom.random_number(10_000_000..99_999_999).to_s, + curso: "Ciência da Computação" + ) + Matricula.create!(discente: @discente, turma: @turma) + + # Template e questões (modelo original BDD) + @template = Template.create!(titulo: "Avaliação BDD #{dados[:nome]}", docente: @docente) + + questao_template = QuestaoTemplate.create!( + enunciado: "Avaliação do Docente", + tipo: :aberta, + template: @template + ) + + @formulario = Formulario.create!( + titulo: "Avaliação - #{dados[:nome]}", + turma: @turma, + template: @template, + prazo: 7.days.from_now + ) + + @questao_principal = Questao.create!( + formulario: @formulario, + questao_template: questao_template, + enunciado: "Avaliação do Docente", + tipo: :aberta + ) + + # User para autenticação via SessionsController (usa User, não Usuario) + @auth_user = User.create!( + nome: usuario_discente.nome, + email: usuario_discente.email, + matricula: @discente.matricula, + perfil: "Discente", + password: SENHA_DISCENTE_RESP, + password_confirmation: SENHA_DISCENTE_RESP, + primeiro_acesso: false + ) + + @auth_user +end + +# ─── DADO: logado como discente e matriculado na turma ─────────────────────── + +Dado("que eu estou logado no sistema CAMAAR como {string} e matriculado na turma {string}") do |_perfil, turma_str| + criar_grafo_formulario(turma_str) + fazer_login_discente_resp(@auth_user.email) +end + +# ─── DADO: já enviou o formulário anteriormente ────────────────────────────── + +Dado("eu já enviei o formulário de avaliação desta turma anteriormente") do + @envio = EnvioFormulario.create!( + formulario: @formulario, + discente: @discente, + enviado_em: 1.hour.ago + ) + Resposta.create!( + envio_formulario: @envio, + questao: @questao_principal, + conteudo: "Ótimo professor" + ) +end + +# ─── E: na página de resposta do formulário ────────────────────────────────── + +E("eu estou na página de resposta do formulário desta turma") do + visit new_envio_formulario_path(formulario_id: @formulario.id) +end + +# ─── QUANDO: preenche todas as perguntas com respostas válidas ─────────────── + +Quando("eu preencho todas as perguntas com respostas válidas") do + @formulario.questoes.each do |questao| + if questao.aberta? + fill_in "respostas[#{questao.id}]", with: "Resposta válida" + else + opcao = questao.opcao_questoes.first + choose "respostas[#{questao.id}]_#{opcao.id}" if opcao + end + end +end + +# ─── E/QUANDO: envio ───────────────────────────────────────────────────────── + +E("eu envio o formulário") do + click_button "Enviar avaliação" +end + +Quando("eu tento enviar o formulário") do + click_button "Enviar avaliação" +end + +# ─── QUANDO: deixa campo obrigatório em branco ─────────────────────────────── + +Quando("eu deixo a pergunta {string} em branco") do |_enunciado| + # não preenche nada — o formulário permanece vazio +end + +# ─── QUANDO: insere nota fora do intervalo ─────────────────────────────────── + +Quando("eu insiro o valor {string} em uma das perguntas de nota") do |valor| + fill_in "respostas[#{@questao_principal.id}]", with: valor +end + +# ─── QUANDO: tenta acessar formulário já respondido ────────────────────────── + +Quando("eu tento acessar diretamente à página de resposta deste formulário") do + visit new_envio_formulario_path(formulario_id: @formulario.id) +end + +# ─── ENTÃO: mensagem de erro ───────────────────────────────────────────────── +# Nota: "o sistema deve exibir a mensagem {string}" já definido em visualizar_templates_steps.rb + +Então("o sistema deve exibir a mensagem de erro {string}") do |mensagem| + expect(page).to have_content(mensagem) +end + +# ─── ENTÃO: formulário não aparece mais nos pendentes ──────────────────────── + +Então("o formulário deve deixar de aparecer na minha lista de pendentes") do + visit formularios_path + expect(page).to have_content("Nenhum formulário pendente") +end + +# ─── ENTÃO: formulário não foi computado como respondido ───────────────────── + +Então("o formulário não deve ser computado como respondido") do + expect(EnvioFormulario.exists?(formulario: @formulario, discente: @discente)).to be(false) +end + +# ─── ENTÃO: não permite nova submissão ─────────────────────────────────────── + +Então("por fim não deve permitir nova submissão") do + count_antes = EnvioFormulario.where(formulario: @formulario).count + visit formulario_path(@formulario) + expect(EnvioFormulario.where(formulario: @formulario).count).to eq(count_antes) +end From 1f8847f855d504803ddadada5b806919abba6e6f Mon Sep 17 00:00:00 2001 From: Rafael Carvalho Date: Sat, 27 Jun 2026 19:41:25 -0300 Subject: [PATCH 03/10] feat(#46): adiciona rotas para formularios e envio_formularios --- config/routes.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/config/routes.rb b/config/routes.rb index 9d813c8bb2..67093b87f5 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -29,5 +29,7 @@ end end + resources :envio_formularios, only: [ :new, :create ] + resources :turmas, only: [ :index, :show ] end From ba34c49f1065ab8b12f4ed2fb84f3545497d7b8b Mon Sep 17 00:00:00 2001 From: Rafael Carvalho Date: Sat, 27 Jun 2026 19:41:29 -0300 Subject: [PATCH 04/10] chore(#46): configura inflection para EnvioFormulario --- config/initializers/inflections.rb | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/config/initializers/inflections.rb b/config/initializers/inflections.rb index 3860f659ea..9f107bb7b2 100644 --- a/config/initializers/inflections.rb +++ b/config/initializers/inflections.rb @@ -14,3 +14,14 @@ # ActiveSupport::Inflector.inflections(:en) do |inflect| # inflect.acronym "RESTful" # end + +# Inflexões para nomes de modelos em português +ActiveSupport::Inflector.inflections(:en) do |inflect| + inflect.irregular "questao", "questoes" + inflect.irregular "opcao_questao", "opcao_questoes" + inflect.irregular "formulario", "formularios" + inflect.irregular "envio_formulario", "envio_formularios" + inflect.irregular "questao_template", "questao_templates" + # "resposta" termina em "ta", regra latina /([ti])a$/ impede pluralização + inflect.irregular "resposta", "respostas" +end From 8b2d348b1e61f849e627de21a03da79bd8b40f76 Mon Sep 17 00:00:00 2001 From: Rafael Carvalho Date: Sat, 27 Jun 2026 19:41:34 -0300 Subject: [PATCH 05/10] feat(#46): adiciona helper methods de autenticacao e discente_atual ao ApplicationController --- app/controllers/application_controller.rb | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 4e64845691..0abf09488f 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -4,7 +4,8 @@ class ApplicationController < ActionController::Base stale_when_importmap_changes helper_method :current_user, :admin?, :current_admin_departamentos, - :usuario_logado, :discente_logado?, :docente_logado?, :admin_logado? + :usuario_logado, :discente_logado?, :docente_logado?, :admin_logado?, + :discente_atual def current_user @current_user ||= User.find_by(id: session[:user_id]) @@ -19,7 +20,10 @@ def current_admin_departamentos end def discente_atual - current_user + return @discente_atual if defined?(@discente_atual) + + usuario = Usuario.find_by(email: current_user&.email) + @discente_atual = usuario&.discente end def usuario_logado From 54187aa89ca256ff90be51fa23dca6067733d6ae Mon Sep 17 00:00:00 2001 From: Rafael Carvalho Date: Sat, 27 Jun 2026 19:41:38 -0300 Subject: [PATCH 06/10] feat(#46): implementa actions index, show e minha_resposta no FormulariosController --- app/controllers/formularios_controller.rb | 54 +++++++++---------- .../formularios/_formulario_card.html.erb | 2 +- app/views/formularios/index.html.erb | 2 +- app/views/formularios/minha_resposta.html.erb | 2 +- app/views/formularios/show.html.erb | 4 +- 5 files changed, 31 insertions(+), 33 deletions(-) diff --git a/app/controllers/formularios_controller.rb b/app/controllers/formularios_controller.rb index 2f9d3b4bdb..7982e51565 100644 --- a/app/controllers/formularios_controller.rb +++ b/app/controllers/formularios_controller.rb @@ -5,18 +5,15 @@ class FormulariosController < ApplicationController # GET /formularios def index - @turmas = discente_atual.turmas.includes(:disciplina) + @turmas = discente_atual.turmas - turmas_ids = discente_atual.turmas.pluck(:id) - respondidos_ids = discente_atual.envio_formularios.pluck(:formulario_id) - base = Formulario.where(turma_id: turmas_ids).includes(:turma, :template) + turmas_ids = discente_atual.turmas.pluck(:id) + respondidos_ids = discente_atual.envio_formularios.pluck(:formulario_id) + base = Formulario.where(turma_id: turmas_ids).includes(:turma, :template) - @formularios_pendentes = base.abertos.where.not(id: respondidos_ids).order(prazo: :asc) - @formularios_respondidos = base - .joins(:envio_formularios) - .where(envio_formularios: { discente_id: discente_atual.id }) - .order("envio_formularios.enviado_em desc") - @formularios_fechados = base.fechados.where.not(id: respondidos_ids).order(prazo: :desc) + @formularios_pendentes = formularios_pendentes(base, respondidos_ids) + @formularios_respondidos = formularios_respondidos(base) + @formularios_fechados = formularios_fechados(base, respondidos_ids) end # GET /formularios/:id @@ -27,15 +24,8 @@ def show return end - unless @formulario.aberto? - redirect_to formularios_path, alert: "O prazo para responder este formulário já encerrou." - return - end - - unless discente_atual.turmas.include?(@formulario.turma) - redirect_to formularios_path, alert: "Você não tem acesso a este formulário." - return - end + return redirect_to formularios_path, alert: "O prazo para responder este formulário já encerrou." unless @formulario.aberto? + return redirect_to formularios_path, alert: "Você não tem acesso a este formulário." unless discente_atual.turmas.include?(@formulario.turma) @questoes = @formulario.questoes.includes(questao_template: :opcao_questoes) end @@ -45,15 +35,8 @@ def minha_resposta @formulario = Formulario.find(params[:id]) @envio = discente_atual.envio_formularios.find_by(formulario: @formulario) - unless @envio - redirect_to formularios_path, alert: "Você ainda não respondeu este formulário." - return - end - - unless discente_atual.turmas.include?(@formulario.turma) - redirect_to formularios_path, alert: "Você não tem acesso a este formulário." - return - end + return redirect_to formularios_path, alert: "Você ainda não respondeu este formulário." unless @envio + return redirect_to formularios_path, alert: "Você não tem acesso a este formulário." unless discente_atual.turmas.include?(@formulario.turma) @respostas = @envio.respostas.includes(questao: { questao_template: :opcao_questoes }) end @@ -65,4 +48,19 @@ def set_formulario rescue ActiveRecord::RecordNotFound redirect_to formularios_path, alert: "Formulário não encontrado." and return end + + def formularios_pendentes(base, respondidos_ids) + base.abertos.where.not(id: respondidos_ids).order(prazo: :asc) + end + + def formularios_respondidos(base) + base + .joins(:envio_formularios) + .where(envio_formularios: { discente_id: discente_atual.id }) + .order("envio_formularios.enviado_em desc") + end + + def formularios_fechados(base, respondidos_ids) + base.fechados.where.not(id: respondidos_ids).order(prazo: :desc) + end end diff --git a/app/views/formularios/_formulario_card.html.erb b/app/views/formularios/_formulario_card.html.erb index 84329d3d94..7c717da3d5 100644 --- a/app/views/formularios/_formulario_card.html.erb +++ b/app/views/formularios/_formulario_card.html.erb @@ -10,7 +10,7 @@ <%# Turma %> - <%= formulario.turma.disciplina.nome %> · Turma <%= formulario.turma.codigo %> + <%= formulario.turma.try(:disciplina)&.nome || formulario.turma.nome %> · Turma <%= formulario.turma.codigo %> <%# Prazo %> diff --git a/app/views/formularios/index.html.erb b/app/views/formularios/index.html.erb index 0f431e7cb3..413ea89214 100644 --- a/app/views/formularios/index.html.erb +++ b/app/views/formularios/index.html.erb @@ -267,7 +267,7 @@ <% @turmas.each do |turma| %>
- <%= turma.disciplina.nome %> · <%= turma.codigo %> + <%= turma.try(:disciplina)&.nome || turma.nome %> · <%= turma.codigo %>
<% end %> diff --git a/app/views/formularios/minha_resposta.html.erb b/app/views/formularios/minha_resposta.html.erb index 5b70bd566e..98053c8a0d 100644 --- a/app/views/formularios/minha_resposta.html.erb +++ b/app/views/formularios/minha_resposta.html.erb @@ -161,7 +161,7 @@

<%= @formulario.titulo %>

-

📚 <%= @formulario.turma.disciplina.nome %> · Turma <%= @formulario.turma.codigo %>

+

📚 <%= @formulario.turma.try(:disciplina)&.nome || @formulario.turma.nome %> · Turma <%= @formulario.turma.codigo %>

<% if @envio.enviado_em %>
diff --git a/app/views/formularios/show.html.erb b/app/views/formularios/show.html.erb index d09eb8f1ee..ab45ec6d39 100644 --- a/app/views/formularios/show.html.erb +++ b/app/views/formularios/show.html.erb @@ -185,10 +185,10 @@

<%= @formulario.titulo %>

- 📚 <%= @formulario.turma.disciplina.nome %> · Turma <%= @formulario.turma.codigo %> + 📚 <%= @formulario.turma.try(:disciplina)&.nome || @formulario.turma.nome %> · Turma <%= @formulario.turma.codigo %> - 🎓 <%= @formulario.turma.semestre %> + 🎓 <%= @formulario.turma.try(:semestre) %> <% if @formulario.prazo %> <% dias = (@formulario.prazo.to_date - Date.today).to_i %> From 65a10aa2a533d4afd03ec7dd240c8e90c35008cd Mon Sep 17 00:00:00 2001 From: Rafael Carvalho Date: Sat, 27 Jun 2026 19:41:42 -0300 Subject: [PATCH 07/10] fix(#46): adiciona associations disciplina e docente ao model Turma --- app/models/turma.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/models/turma.rb b/app/models/turma.rb index b489b1b006..d58f283190 100644 --- a/app/models/turma.rb +++ b/app/models/turma.rb @@ -1,6 +1,8 @@ # app/models/turma.rb class Turma < ApplicationRecord belongs_to :departamento + belongs_to :disciplina, optional: true + belongs_to :docente, optional: true validates :codigo, presence: true validates :nome, presence: true From 777b263ded9bd131ba2da404f02acc7f57ba9320 Mon Sep 17 00:00:00 2001 From: Rafael Carvalho Date: Sat, 27 Jun 2026 19:41:47 -0300 Subject: [PATCH 08/10] chore(#46): adiciona gems rubycritic e rails-controller-testing --- Gemfile | 2 + Gemfile.lock | 127 ++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 127 insertions(+), 2 deletions(-) diff --git a/Gemfile b/Gemfile index 35902538e0..27ca1f7330 100644 --- a/Gemfile +++ b/Gemfile @@ -59,6 +59,7 @@ end group :development do # Use console on exceptions pages [https://github.com/rails/web-console] gem "web-console" + gem "rubycritic", require: false end group :test do @@ -69,6 +70,7 @@ group :test do gem "rspec-rails" gem "capybara" gem "selenium-webdriver" + gem "rails-controller-testing" end gem "activerecord-import" diff --git a/Gemfile.lock b/Gemfile.lock index 7208ffc91c..73f39eef71 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -80,6 +80,10 @@ GEM addressable (2.9.0) public_suffix (>= 2.0.2, < 8.0) ast (2.4.3) + axiom-types (0.1.1) + descendants_tracker (~> 0.0.4) + ice_nine (~> 0.11.0) + thread_safe (~> 0.3, >= 0.3.1) base64 (0.3.0) bcrypt (3.1.22) bcrypt_pbkdf (1.1.2) @@ -102,6 +106,10 @@ GEM rack-test (>= 0.6.3) regexp_parser (>= 1.5, < 3.0) xpath (~> 3.2) + childprocess (5.1.0) + logger (~> 1.5) + coercible (1.0.0) + descendants_tracker (~> 0.0.1) concurrent-ruby (1.3.7) connection_pool (3.0.2) crass (1.0.6) @@ -144,9 +152,41 @@ GEM debug (1.11.1) irb (~> 1.10) reline (>= 0.3.8) + descendants_tracker (0.0.4) + thread_safe (~> 0.3, >= 0.3.1) diff-lcs (1.6.2) + docile (1.4.1) dotenv (3.2.0) drb (2.2.3) + dry-configurable (1.4.0) + dry-core (~> 1.0) + zeitwerk (~> 2.6) + dry-core (1.2.0) + concurrent-ruby (~> 1.0) + logger + zeitwerk (~> 2.6) + dry-inflector (1.3.1) + dry-initializer (3.2.0) + dry-logic (1.6.0) + bigdecimal + concurrent-ruby (~> 1.0) + dry-core (~> 1.1) + zeitwerk (~> 2.6) + dry-schema (1.16.0) + concurrent-ruby (~> 1.0) + dry-configurable (~> 1.0, >= 1.0.1) + dry-core (~> 1.1) + dry-initializer (~> 3.2) + dry-logic (~> 1.6) + dry-types (~> 1.9, >= 1.9.1) + zeitwerk (~> 2.6) + dry-types (1.9.1) + bigdecimal (>= 3.0) + concurrent-ruby (~> 1.0) + dry-core (~> 1.0) + dry-inflector (~> 1.0) + dry-logic (~> 1.4) + zeitwerk (~> 2.6) ed25519 (1.4.0) erb (6.0.4) erubi (1.13.1) @@ -164,6 +204,15 @@ GEM ffi (1.17.4-arm64-darwin) ffi (1.17.4-x86_64-linux-gnu) ffi (1.17.4-x86_64-linux-musl) + flay (2.14.4) + erubi (~> 1.10) + path_expander (~> 2.0) + prism (~> 1.7) + sexp_processor (~> 4.0) + flog (4.9.4) + path_expander (~> 2.0) + prism (~> 1.7) + sexp_processor (~> 4.8) fugit (1.12.2) et-orbi (~> 1.4) raabro (~> 1.4) @@ -171,6 +220,7 @@ GEM activesupport (>= 6.1) i18n (1.14.8) concurrent-ruby (~> 1.0) + ice_nine (0.11.2) image_processing (1.14.0) mini_magick (>= 4.9.5, < 6) ruby-vips (>= 2.0.17, < 3) @@ -200,6 +250,10 @@ GEM thor (~> 1.3) zeitwerk (>= 2.6.18, < 3.0) language_server-protocol (3.17.0.5) + launchy (3.1.1) + addressable (~> 2.8) + childprocess (~> 5.0) + logger (~> 1.6) lint_roller (1.1.0) logger (1.7.0) loofah (2.25.1) @@ -256,6 +310,7 @@ GEM parser (3.3.11.1) ast (~> 2.4.1) racc + path_expander (2.0.1) pp (0.6.3) prettyprint prettyprint (0.2.0) @@ -294,6 +349,10 @@ GEM activesupport (= 8.1.3) bundler (>= 1.15.0) railties (= 8.1.3) + rails-controller-testing (1.0.5) + actionpack (>= 5.0.1.rc1) + actionview (>= 5.0.1.rc1) + activesupport (>= 5.0.1.rc1) rails-dom-testing (2.3.0) activesupport (>= 5.0.0) minitest @@ -316,6 +375,12 @@ GEM erb psych (>= 4.0.0) tsort + reek (6.5.0) + dry-schema (~> 1.13) + logger (~> 1.6) + parser (~> 3.3.0) + rainbow (>= 2.0, < 4.0) + rexml (~> 3.1) regexp_parser (2.12.0) reline (0.6.3) io-console (~> 0.5) @@ -369,6 +434,23 @@ GEM ruby-vips (2.3.0) ffi (~> 1.12) logger + ruby_parser (3.22.0) + racc (~> 1.5) + sexp_processor (~> 4.16) + rubycritic (5.0.0) + flay (~> 2.13) + flog (~> 4.7) + launchy (>= 2.5.2) + ostruct + parser (>= 3.3.0.5) + prism (>= 1.6.0) + rainbow (~> 3.1.1) + reek (~> 6.5.0, < 7.0) + rexml + ruby_parser (~> 3.21) + simplecov (>= 0.22.0) + tty-which (~> 0.5.0) + virtus (~> 2.0) rubyzip (3.4.0) securerandom (0.4.1) selenium-webdriver (4.45.0) @@ -377,8 +459,15 @@ GEM rexml (~> 3.2, >= 3.2.5) rubyzip (>= 1.2.2, < 4.0) websocket (~> 1.0) + sexp_processor (4.17.5) shoulda-matchers (5.3.0) activesupport (>= 5.2.0) + simplecov (0.22.0) + docile (~> 1.1) + simplecov-html (~> 0.11) + simplecov_json_formatter (~> 0.1) + simplecov-html (0.13.2) + simplecov_json_formatter (0.1.4) solid_cable (4.0.0) actioncable (>= 7.2) activejob (>= 7.2) @@ -416,12 +505,14 @@ GEM ffi (~> 1.1) memoist3 (~> 1.0.0) thor (1.5.0) + thread_safe (0.3.6) thruster (0.1.21) thruster (0.1.21-aarch64-linux) thruster (0.1.21-arm64-darwin) thruster (0.1.21-x86_64-linux) timeout (0.6.1) tsort (0.2.0) + tty-which (0.5.0) turbo-rails (2.0.23) actionpack (>= 7.1.0) railties (>= 7.1.0) @@ -432,6 +523,10 @@ GEM unicode-emoji (4.2.0) uri (1.1.1) useragent (0.16.11) + virtus (2.0.0) + axiom-types (~> 0.1) + coercible (~> 1.0) + descendants_tracker (~> 0.0, >= 0.0.3) web-console (4.3.0) actionview (>= 8.0.0) bindex (>= 0.4.0) @@ -475,8 +570,10 @@ DEPENDENCIES propshaft puma (>= 5.0) rails (~> 8.1.3) + rails-controller-testing rspec-rails rubocop-rails-omakase + rubycritic selenium-webdriver shoulda-matchers (~> 5.0) solid_cable @@ -505,6 +602,7 @@ CHECKSUMS activesupport (8.1.3) sha256=21a5e0dfbd4c3ddd9e1317ec6a4d782fa226e7867dc70b0743acda81a1dca20e addressable (2.9.0) sha256=7fdf6ac3660f7f4e867a0838be3f6cf722ace541dd97767fa42bc6cfa980c7af ast (2.4.3) sha256=954615157c1d6a382bc27d690d973195e79db7f55e9765ac7c481c60bdb4d383 + axiom-types (0.1.1) sha256=c1ff113f3de516fa195b2db7e0a9a95fd1b08475a502ff660d04507a09980383 base64 (0.3.0) sha256=27337aeabad6ffae05c265c450490628ef3ebd4b67be58257393227588f5a97b bcrypt (3.1.22) sha256=1f0072e88c2d705d94aff7f2c5cb02eb3f1ec4b8368671e19112527489f29032 bcrypt_pbkdf (1.1.2) sha256=c2414c23ce66869b3eb9f643d6a3374d8322dfb5078125c82792304c10b94cf6 @@ -516,6 +614,8 @@ CHECKSUMS bundler (4.0.12) sha256=7f8b757d28dfb636e7b24fba2344ac6dd13b5b24f4b46d62573d483f211825ac bundler-audit (0.9.3) sha256=81c8766c71e47d0d28a0f98c7eed028539f21a6ea3cd8f685eb6f42333c9b4e9 capybara (3.40.0) sha256=42dba720578ea1ca65fd7a41d163dd368502c191804558f6e0f71b391054aeef + childprocess (5.1.0) sha256=9a8d484be2fd4096a0e90a0cd3e449a05bc3aa33f8ac9e4d6dcef6ac1455b6ec + coercible (1.0.0) sha256=5081ad24352cc8435ce5472bc2faa30260c7ea7f2102cc6a9f167c4d9bffaadc concurrent-ruby (1.3.7) sha256=4412caec3a5ea2e5fdc52076724c071a81f2c0593d83b2ac8cbb8ca63b3151b0 connection_pool (3.0.2) sha256=33fff5ba71a12d2aa26cb72b1db8bba2a1a01823559fb01d29eb74c286e62e0a crass (1.0.6) sha256=dc516022a56e7b3b156099abc81b6d2b08ea1ed12676ac7a5657617f012bd45d @@ -533,9 +633,18 @@ CHECKSUMS database_cleaner-core (2.1.0) sha256=b2875266d9b26b716e8b669c883e01c5250839f6f2ec56422b5e79aa97fb6927 date (3.5.1) sha256=750d06384d7b9c15d562c76291407d89e368dda4d4fff957eb94962d325a0dc0 debug (1.11.1) sha256=2e0b0ac6119f2207a6f8ac7d4a73ca8eb4e440f64da0a3136c30343146e952b6 + descendants_tracker (0.0.4) sha256=e9c41dd4cfbb85829a9301ea7e7c48c2a03b26f09319db230e6479ccdc780897 diff-lcs (1.6.2) sha256=9ae0d2cba7d4df3075fe8cd8602a8604993efc0dfa934cff568969efb1909962 + docile (1.4.1) sha256=96159be799bfa73cdb721b840e9802126e4e03dfc26863db73647204c727f21e dotenv (3.2.0) sha256=e375b83121ea7ca4ce20f214740076129ab8514cd81378161f11c03853fe619d drb (2.2.3) sha256=0b00d6fdb50995fe4a45dea13663493c841112e4068656854646f418fda13373 + dry-configurable (1.4.0) sha256=e35d1b5f3c081753ef361f564919db79000f32cfa6f20ee3a3ba5921b41b73ce + dry-core (1.2.0) sha256=0cc5a7da88df397f153947eeeae42e876e999c1e30900f3c536fb173854e96a1 + dry-inflector (1.3.1) sha256=7fb0c2bb04f67638f25c52e7ba39ab435d922a3a5c3cd196120f63accb682dcc + dry-initializer (3.2.0) sha256=37d59798f912dc0a1efe14a4db4a9306989007b302dcd5f25d0a2a20c166c4e3 + dry-logic (1.6.0) sha256=da6fedbc0f90fc41f9b0cc7e6f05f5d529d1efaef6c8dcc8e0733f685745cea2 + dry-schema (1.16.0) sha256=cd3aaeabc0f1af66ec82a29096d4c4fb92a0a58b9dae29a22b1bbceb78985727 + dry-types (1.9.1) sha256=baebeecdb9f8395d6c9d227b62011279440943e3ef2468fe8ccc1ba11467f178 ed25519 (1.4.0) sha256=16e97f5198689a154247169f3453ef4cfd3f7a47481fde0ae33206cdfdcac506 erb (6.0.4) sha256=38e3803694be357fe2bfe312487c74beaf9fb4e5beb3e22498952fe1645b95d9 erubi (1.13.1) sha256=a082103b0885dbc5ecf1172fede897f9ebdb745a4b97a5e8dc63953db1ee4ad9 @@ -549,9 +658,12 @@ CHECKSUMS ffi (1.17.4-arm64-darwin) sha256=19071aaf1419251b0a46852abf960e77330a3b334d13a4ab51d58b31a937001b ffi (1.17.4-x86_64-linux-gnu) sha256=9d3db14c2eae074b382fa9c083fe95aec6e0a1451da249eab096c34002bc752d ffi (1.17.4-x86_64-linux-musl) sha256=3fdf9888483de005f8ef8d1cf2d3b20d86626af206cbf780f6a6a12439a9c49e + flay (2.14.4) sha256=a62d96a51d1da185aa41ba95b696966df9f7d1d91a457709277f24515895de77 + flog (4.9.4) sha256=12cc054fab7a2cbd2a906514397c4d7788954d530564782d6f14939dc2dfbcbb fugit (1.12.2) sha256=643f2bf28db263bd400cbf8e0dd8b76b2c9b94bdb130e12d2394de04d9c20e5e globalid (1.3.0) sha256=05c639ad6eb4594522a0b07983022f04aa7254626ab69445a0e493aa3786ff11 i18n (1.14.8) sha256=285778639134865c5e0f6269e0b818256017e8cde89993fdfcbfb64d088824a5 + ice_nine (0.11.2) sha256=5d506a7d2723d5592dc121b9928e4931742730131f22a1a37649df1c1e2e63db image_processing (1.14.0) sha256=754cc169c9c262980889bec6bfd325ed1dafad34f85242b5a07b60af004742fb importmap-rails (2.2.3) sha256=7101be2a4dc97cf1558fb8f573a718404c5f6bcfe94f304bf1f39e444feeb16a io-console (0.8.2) sha256=d6e3ae7a7cc7574f4b8893b4fca2162e57a825b223a177b7afa236c5ef9814cc @@ -560,6 +672,7 @@ CHECKSUMS json (2.19.9) sha256=9b9025b7cdddafa38d316eca0b2358488e42d417045c1b90d216a9fefe46b79a kamal (2.11.0) sha256=1408864425e0dec7e0a14d712a3b13f614e9f3a425b7661d3f9d287a51d7dd75 language_server-protocol (3.17.0.5) sha256=fd1e39a51a28bf3eec959379985a72e296e9f9acfce46f6a79d31ca8760803cc + launchy (3.1.1) sha256=72b847b5cc961589dde2c395af0108c86ff0119f42d4648d25b5440ebb10059e lint_roller (1.1.0) sha256=2c0c845b632a7d172cb849cc90c1bce937a28c5c8ccccb50dfd46a485003cc87 logger (1.7.0) sha256=196edec7cc44b66cfb40f9755ce11b392f21f7967696af15d274dde7edff0203 loofah (2.25.1) sha256=d436c73dbd0c1147b16c4a41db097942d217303e1f7728704b37e4df9f6d2e04 @@ -590,6 +703,7 @@ CHECKSUMS ostruct (0.6.3) sha256=95a2ed4a4bd1d190784e666b47b2d3f078e4a9efda2fccf18f84ddc6538ed912 parallel (2.1.0) sha256=b35258865c2e31134c5ecb708beaaf6772adf9d5efae28e93e99260877b09356 parser (3.3.11.1) sha256=d17ace7aabe3e72c3cc94043714be27cc6f852f104d81aa284c2281aecc65d54 + path_expander (2.0.1) sha256=2de201164bff4719cc4d0b3767286e9977cc832a59c4d70abab571ec86cb41e4 pp (0.6.3) sha256=2951d514450b93ccfeb1df7d021cae0da16e0a7f95ee1e2273719669d0ab9df6 prettyprint (0.2.0) sha256=2bc9e15581a94742064a3cc8b0fb9d45aae3d03a1baa6ef80922627a0766f193 prism (1.9.0) sha256=7b530c6a9f92c24300014919c9dcbc055bf4cdf51ec30aed099b06cd6674ef85 @@ -604,12 +718,14 @@ CHECKSUMS rack-test (2.2.0) sha256=005a36692c306ac0b4a9350355ee080fd09ddef1148a5f8b2ac636c720f5c463 rackup (2.3.1) sha256=6c79c26753778e90983761d677a48937ee3192b3ffef6bc963c0950f94688868 rails (8.1.3) sha256=6d017ba5348c98fc909753a8169b21d44de14d2a0b92d140d1a966834c3c9cd3 + rails-controller-testing (1.0.5) sha256=741448db59366073e86fc965ba403f881c636b79a2c39a48d0486f2607182e94 rails-dom-testing (2.3.0) sha256=8acc7953a7b911ca44588bf08737bc16719f431a1cc3091a292bca7317925c1d rails-html-sanitizer (1.7.0) sha256=28b145cceaf9cc214a9874feaa183c3acba036c9592b19886e0e45efc62b1e89 railties (8.1.3) sha256=913eb0e0cb520aac687ffd74916bd726d48fa21f47833c6292576ef6a286de22 rainbow (3.1.1) sha256=039491aa3a89f42efa1d6dec2fc4e62ede96eb6acd95e52f1ad581182b79bc6a rake (13.4.2) sha256=cb825b2bd5f1f8e91ca37bddb4b9aaf345551b4731da62949be002fa89283701 rdoc (7.2.0) sha256=8650f76cd4009c3b54955eb5d7e3a075c60a57276766ebf36f9085e8c9f23192 + reek (6.5.0) sha256=d26d3a492773b2bbc228888067a21afe33ac07954a17dbd64cdeae42c4c69be1 regexp_parser (2.12.0) sha256=35a916a1d63190ab5c9009457136ae5f3c0c7512d60291d0d1378ba18ce08ebb reline (0.6.3) sha256=1198b04973565b36ec0f11542ab3f5cfeeec34823f4e54cebde90968092b1835 rexml (3.4.4) sha256=19e0a2c3425dfbf2d4fc1189747bdb2f849b6c5e74180401b15734bc97b5d142 @@ -625,12 +741,16 @@ CHECKSUMS rubocop-rails-omakase (1.1.0) sha256=2af73ac8ee5852de2919abbd2618af9c15c19b512c4cfc1f9a5d3b6ef009109d ruby-progressbar (1.13.0) sha256=80fc9c47a9b640d6834e0dc7b3c94c9df37f08cb072b7761e4a71e22cff29b33 ruby-vips (2.3.0) sha256=e685ec02c13969912debbd98019e50492e12989282da5f37d05f5471442f5374 + ruby_parser (3.22.0) sha256=1eb4937cd9eb220aa2d194e352a24dba90aef00751e24c8dfffdb14000f15d23 + rubycritic (5.0.0) sha256=7f3877556d7f52bf0980496b7c907a827a9592ba690b80a593403a60bd6cfb42 rubyzip (3.4.0) sha256=6de39bc9eba302b635a476d16c9e16b0872ad24517c2f98f2b3a7ea23caff57b securerandom (0.4.1) sha256=cc5193d414a4341b6e225f0cb4446aceca8e50d5e1888743fac16987638ea0b1 - selenium-webdriver (4.45.0) sha256=ecac65a4df86ac6f7d707e6dcbacaa9c08b6cf2b966babecfb9653c5aa13e2d1 + sexp_processor (4.17.5) sha256=ae2b48ba98353d5d465ce8759836b7a05f2e12c5879fcd14d7815b026de32f0e shoulda-matchers (5.3.0) sha256=f6ba863b8752bb5956aaa73b046d5df5ecfbe9a7acb61f31bf853613e0932f86 - + simplecov (0.22.0) sha256=fe2622c7834ff23b98066bb0a854284b2729a569ac659f82621fc22ef36213a5 + simplecov-html (0.13.2) sha256=bd0b8e54e7c2d7685927e8d6286466359b6f16b18cb0df47b508e8d73c777246 + simplecov_json_formatter (0.1.4) sha256=529418fbe8de1713ac2b2d612aa3daa56d316975d307244399fa4838c601b428 solid_cable (4.0.0) sha256=8379680ef6bf36e195eb876a6306ea290f87d5fa10bc4a757bc2a918f83229b5 solid_cache (1.0.10) sha256=bc05a2fb3ac78a6f43cbb5946679cf9db67dd30d22939ededc385cb93e120d41 solid_queue (1.4.0) sha256=e6a18d196f0b27cb6e3c77c5b31258b05fb634f8ed64fb1866ed164047216c2a @@ -646,18 +766,21 @@ CHECKSUMS stringio (3.2.0) sha256=c37cb2e58b4ffbd33fe5cd948c05934af997b36e0b6ca6fdf43afa234cf222e1 sys-uname (1.5.1) sha256=784d7e6491b0393c25cbbe5ac38324ac7be9fda083a6094832648af669386d7b thor (1.5.0) sha256=e3a9e55fe857e44859ce104a84675ab6e8cd59c650a49106a05f55f136425e73 + thread_safe (0.3.6) sha256=9ed7072821b51c57e8d6b7011a8e282e25aeea3a4065eab326e43f66f063b05a thruster (0.1.21) sha256=dc67928f36e5894844579a95e45637a5091db7a7ea05468ee8c2c6eb0a3f77cf thruster (0.1.21-aarch64-linux) sha256=f5aff78fb7a6431ed3d6ab4bde03a89c461e9a73981dbc97d6990d85c3db235c thruster (0.1.21-arm64-darwin) sha256=bd8db9f57fae2cbb3fe08ebab49cb47fe49608122dac23daf0ce709adfb9bfc8 thruster (0.1.21-x86_64-linux) sha256=6e2fbcf826540a72d3710ae4db072c2333287ac2ee57e7e52f35bc10900d74a7 timeout (0.6.1) sha256=78f57368a7e7bbadec56971f78a3f5ecbcfb59b7fcbb0a3ed6ddc08a5094accb tsort (0.2.0) sha256=9650a793f6859a43b6641671278f79cfead60ac714148aabe4e3f0060480089f + tty-which (0.5.0) sha256=5824055f0d6744c97e7c4426544f01d519c40d1806ef2ef47d9854477993f466 turbo-rails (2.0.23) sha256=ee0d90733aafff056cf51ff11e803d65e43cae258cc55f6492020ec1f9f9315f tzinfo (2.0.6) sha256=8daf828cc77bcf7d63b0e3bdb6caa47e2272dcfaf4fbfe46f8c3a9df087a829b unicode-display_width (3.2.0) sha256=0cdd96b5681a5949cdbc2c55e7b420facae74c4aaf9a9815eee1087cb1853c42 unicode-emoji (4.2.0) sha256=519e69150f75652e40bf736106cfbc8f0f73aa3fb6a65afe62fefa7f80b0f80f uri (1.1.1) sha256=379fa58d27ffb1387eaada68c749d1426738bd0f654d812fcc07e7568f5c57c6 useragent (0.16.11) sha256=700e6413ad4bb954bb63547fa098dddf7b0ebe75b40cc6f93b8d54255b173844 + virtus (2.0.0) sha256=8841dae4eb7fcc097320ba5ea516bf1839e5d056c61ee27138aa4bddd6e3d1c2 web-console (4.3.0) sha256=e13b71301cdfc2093f155b5aa3a622db80b4672d1f2f713119cc7ec7ac6a6da4 websocket (1.2.11) sha256=b7e7a74e2410b5e85c25858b26b3322f29161e300935f70a0e0d3c35e0462737 websocket-driver (0.8.1) sha256=5ab238238ce230e5d4b262d2be39624c867914eab99171dc4952b58b577c2d96 From bc52341a0c5cd1277c034afb4fdc625499d2d8dc Mon Sep 17 00:00:00 2001 From: Rafael Carvalho Date: Sat, 27 Jun 2026 19:41:51 -0300 Subject: [PATCH 09/10] fix(#46): corrige factory de turma e adiciona factory de User para specs --- spec/factories/factories.rb | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/spec/factories/factories.rb b/spec/factories/factories.rb index 163e60fb7f..1a7cdb115c 100644 --- a/spec/factories/factories.rb +++ b/spec/factories/factories.rb @@ -4,6 +4,15 @@ # has_secure_password aceita `password` e armazena em `password_digest` # FactoryBot.define do + factory :user do + sequence(:nome) { |n| "User #{n}" } + sequence(:email) { |n| "user#{n}@unb.br" } + sequence(:matricula) { |n| "9000#{n.to_s.rjust(5, '0')}" } + perfil { "Discente" } + password { "Senha123!" } + primeiro_acesso { false } + end + factory :usuario do sequence(:login) { |n| "usuario#{n}" } sequence(:email) { |n| "usuario#{n}@unb.br" } @@ -34,9 +43,11 @@ end factory :turma do + association :departamento association :disciplina association :docente sequence(:codigo) { |n| "T#{n}" } + sequence(:nome) { |n| "Turma #{n}" } semestre { "2024.1" } horario { "35T45" } end From 61f60a6ec62d5b887aa2c2848fdbd9887124f109 Mon Sep 17 00:00:00 2001 From: Rafael Carvalho Date: Sat, 27 Jun 2026 19:41:55 -0300 Subject: [PATCH 10/10] test(#46): adiciona e corrige specs do FormulariosController --- .../formularios_controller_spec.rb | 23 +++++++++++-------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/spec/controllers/formularios_controller_spec.rb b/spec/controllers/formularios_controller_spec.rb index a8e9c8b9ed..b6c4ec0d40 100644 --- a/spec/controllers/formularios_controller_spec.rb +++ b/spec/controllers/formularios_controller_spec.rb @@ -1,19 +1,21 @@ # spec/controllers/formularios_controller_spec.rb -require "rails_helper" # ← CORREÇÃO: era ausente +require "rails_helper" RSpec.describe FormulariosController, type: :controller do let(:depto) { create(:departamento) } + let(:disciplina) { create(:disciplina) } + let(:usr_doc) { create(:usuario, perfil: :docente) } let(:docente) { create(:docente, usuario: usr_doc, departamento: depto) } - let(:disciplina) { create(:disciplina) } let(:turma) { create(:turma, disciplina: disciplina, docente: docente) } let(:template) { create(:template, docente: docente) } let(:usr_disc) { create(:usuario, perfil: :discente, primeiro_acesso: false) } let(:discente) { create(:discente, usuario: usr_disc) } + let(:user_disc) { create(:user, perfil: "Discente", email: usr_disc.email, primeiro_acesso: false) } before do - session[:usuario_id] = usr_disc.id + session[:user_id] = user_disc.id create(:matricula, discente: discente, turma: turma) end @@ -48,23 +50,24 @@ outra_turma = create(:turma, disciplina: disciplina, docente: docente) outro_form = create(:formulario, turma: outra_turma, template: template) get :index - todos = assigns(:formularios_pendentes) + - assigns(:formularios_respondidos) + - assigns(:formularios_fechados) + todos = assigns(:formularios_pendentes).to_a + + assigns(:formularios_respondidos).to_a + + assigns(:formularios_fechados).to_a expect(todos).not_to include(outro_form) end context "sem autenticação" do - before { session[:usuario_id] = nil } + before { session[:user_id] = nil } - it "redireciona para login" do + it "redireciona para root" do get :index - expect(response).to redirect_to(login_path) + expect(response).to redirect_to(root_path) end end context "logado como docente" do - before { session[:usuario_id] = usr_doc.id } + let(:user_doc) { create(:user, perfil: "Docente", email: usr_doc.email) } + before { session[:user_id] = user_doc.id } it "redireciona para root" do get :index