From d0738bea3102a76bff56609b1d8f12f80a0d4bf6 Mon Sep 17 00:00:00 2001 From: bg! <99600828+bg1777@users.noreply.github.com> Date: Wed, 5 Nov 2025 20:44:41 -0300 Subject: [PATCH 01/16] Update README with team member information Added team member names and IDs to README. --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index 9d7fe1bf53..07a95d0c24 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,7 @@ # CAMAAR Sistema para avaliação de atividades acadêmicas remotas do CIC + +Integrantes Grupo 10: +- Bernardo Gomes Rodrigues (231034190) +- Isaac Silva (231025216) +- Maria Carolina Burgum Abreu Jorge (231013547) From cd8bf69963bbbf9a82d0bec62c1d2fa4af7d65f4 Mon Sep 17 00:00:00 2001 From: Maria Carolina Date: Thu, 13 Nov 2025 09:10:27 -0300 Subject: [PATCH 02/16] chore: inicializa o projeto ruby on rails --- .dockerignore | 51 ++ .gitattributes | 9 + .github/dependabot.yml | 12 + .github/workflows/ci.yml | 90 ++++ .gitignore | 34 ++ .kamal/hooks/docker-setup.sample | 3 + .kamal/hooks/post-app-boot.sample | 3 + .kamal/hooks/post-deploy.sample | 14 + .kamal/hooks/post-proxy-reboot.sample | 3 + .kamal/hooks/pre-app-boot.sample | 3 + .kamal/hooks/pre-build.sample | 51 ++ .kamal/hooks/pre-connect.sample | 47 ++ .kamal/hooks/pre-deploy.sample | 122 +++++ .kamal/hooks/pre-proxy-reboot.sample | 3 + .kamal/secrets | 17 + .rubocop.yml | 8 + .ruby-version | 1 + Dockerfile | 72 +++ Gemfile | 66 +++ Gemfile.lock | 437 ++++++++++++++++++ README.md | 2 +- Rakefile | 6 + app/assets/images/.keep | 0 app/assets/stylesheets/application.css | 10 + app/controllers/application_controller.rb | 4 + app/controllers/concerns/.keep | 0 app/helpers/application_helper.rb | 2 + app/javascript/application.js | 3 + app/javascript/controllers/application.js | 9 + .../controllers/hello_controller.js | 7 + app/javascript/controllers/index.js | 4 + app/jobs/application_job.rb | 7 + app/mailers/application_mailer.rb | 4 + app/models/application_record.rb | 3 + app/models/concerns/.keep | 0 app/views/layouts/application.html.erb | 28 ++ app/views/layouts/mailer.html.erb | 13 + app/views/layouts/mailer.text.erb | 1 + app/views/pwa/manifest.json.erb | 22 + app/views/pwa/service-worker.js | 26 ++ bin/brakeman | 7 + bin/bundle | 109 +++++ bin/cucumber | 11 + bin/dev | 2 + bin/docker-entrypoint | 14 + bin/importmap | 4 + bin/jobs | 6 + bin/kamal | 27 ++ bin/rails | 4 + bin/rake | 4 + bin/rubocop | 8 + bin/setup | 34 ++ bin/thrust | 5 + config.ru | 6 + config/application.rb | 27 ++ config/boot.rb | 4 + config/cable.yml | 17 + config/cache.yml | 16 + config/credentials.yml.enc | 1 + config/cucumber.yml | 8 + config/database.yml | 41 ++ config/deploy.yml | 116 +++++ config/environment.rb | 5 + config/environments/development.rb | 76 +++ config/environments/production.rb | 90 ++++ config/environments/test.rb | 57 +++ config/importmap.rb | 7 + config/initializers/assets.rb | 7 + .../initializers/content_security_policy.rb | 25 + .../initializers/filter_parameter_logging.rb | 8 + config/initializers/inflections.rb | 16 + config/locales/en.yml | 31 ++ config/puma.rb | 41 ++ config/queue.yml | 18 + config/recurring.yml | 15 + config/routes.rb | 14 + config/storage.yml | 34 ++ db/cable_schema.rb | 11 + db/cache_schema.rb | 12 + db/queue_schema.rb | 129 ++++++ db/seeds.rb | 9 + features/importar_dados_sigaa.feature | 24 + features/step_definitions/.keep | 0 features/support/env.rb | 53 +++ lib/tasks/.keep | 0 lib/tasks/cucumber.rake | 69 +++ log/.keep | 0 public/400.html | 114 +++++ public/404.html | 114 +++++ public/406-unsupported-browser.html | 114 +++++ public/422.html | 114 +++++ public/500.html | 114 +++++ public/icon.png | Bin 0 -> 4166 bytes public/icon.svg | 3 + public/robots.txt | 1 + script/.keep | 0 storage/.keep | 0 test/application_system_test_case.rb | 5 + test/controllers/.keep | 0 test/fixtures/files/.keep | 0 test/helpers/.keep | 0 test/integration/.keep | 0 test/mailers/.keep | 0 test/models/.keep | 0 test/system/.keep | 0 test/test_helper.rb | 15 + tmp/.keep | 0 tmp/pids/.keep | 0 tmp/storage/.keep | 0 vendor/.keep | 0 vendor/javascript/.keep | 0 111 files changed, 3012 insertions(+), 1 deletion(-) create mode 100644 .dockerignore create mode 100644 .gitattributes create mode 100644 .github/dependabot.yml create mode 100644 .github/workflows/ci.yml create mode 100644 .gitignore create mode 100644 .kamal/hooks/docker-setup.sample create mode 100644 .kamal/hooks/post-app-boot.sample create mode 100644 .kamal/hooks/post-deploy.sample create mode 100644 .kamal/hooks/post-proxy-reboot.sample create mode 100644 .kamal/hooks/pre-app-boot.sample create mode 100644 .kamal/hooks/pre-build.sample create mode 100644 .kamal/hooks/pre-connect.sample create mode 100644 .kamal/hooks/pre-deploy.sample create mode 100644 .kamal/hooks/pre-proxy-reboot.sample create mode 100644 .kamal/secrets create mode 100644 .rubocop.yml create mode 100644 .ruby-version create mode 100644 Dockerfile create mode 100644 Gemfile create mode 100644 Gemfile.lock create mode 100644 Rakefile create mode 100644 app/assets/images/.keep create mode 100644 app/assets/stylesheets/application.css create mode 100644 app/controllers/application_controller.rb create mode 100644 app/controllers/concerns/.keep create mode 100644 app/helpers/application_helper.rb create mode 100644 app/javascript/application.js create mode 100644 app/javascript/controllers/application.js create mode 100644 app/javascript/controllers/hello_controller.js create mode 100644 app/javascript/controllers/index.js create mode 100644 app/jobs/application_job.rb create mode 100644 app/mailers/application_mailer.rb create mode 100644 app/models/application_record.rb create mode 100644 app/models/concerns/.keep create mode 100644 app/views/layouts/application.html.erb create mode 100644 app/views/layouts/mailer.html.erb create mode 100644 app/views/layouts/mailer.text.erb create mode 100644 app/views/pwa/manifest.json.erb create mode 100644 app/views/pwa/service-worker.js create mode 100644 bin/brakeman create mode 100644 bin/bundle create mode 100644 bin/cucumber create mode 100644 bin/dev create mode 100644 bin/docker-entrypoint create mode 100644 bin/importmap create mode 100644 bin/jobs create mode 100644 bin/kamal create mode 100644 bin/rails create mode 100644 bin/rake create mode 100644 bin/rubocop create mode 100644 bin/setup create mode 100644 bin/thrust create mode 100644 config.ru create mode 100644 config/application.rb create mode 100644 config/boot.rb create mode 100644 config/cable.yml create mode 100644 config/cache.yml create mode 100644 config/credentials.yml.enc create mode 100644 config/cucumber.yml create mode 100644 config/database.yml create mode 100644 config/deploy.yml create mode 100644 config/environment.rb create mode 100644 config/environments/development.rb create mode 100644 config/environments/production.rb create mode 100644 config/environments/test.rb create mode 100644 config/importmap.rb create mode 100644 config/initializers/assets.rb create mode 100644 config/initializers/content_security_policy.rb create mode 100644 config/initializers/filter_parameter_logging.rb create mode 100644 config/initializers/inflections.rb create mode 100644 config/locales/en.yml create mode 100644 config/puma.rb create mode 100644 config/queue.yml create mode 100644 config/recurring.yml create mode 100644 config/routes.rb create mode 100644 config/storage.yml create mode 100644 db/cable_schema.rb create mode 100644 db/cache_schema.rb create mode 100644 db/queue_schema.rb create mode 100644 db/seeds.rb create mode 100644 features/importar_dados_sigaa.feature create mode 100644 features/step_definitions/.keep create mode 100644 features/support/env.rb create mode 100644 lib/tasks/.keep create mode 100644 lib/tasks/cucumber.rake create mode 100644 log/.keep create mode 100644 public/400.html create mode 100644 public/404.html create mode 100644 public/406-unsupported-browser.html create mode 100644 public/422.html create mode 100644 public/500.html create mode 100644 public/icon.png create mode 100644 public/icon.svg create mode 100644 public/robots.txt create mode 100644 script/.keep create mode 100644 storage/.keep create mode 100644 test/application_system_test_case.rb create mode 100644 test/controllers/.keep create mode 100644 test/fixtures/files/.keep create mode 100644 test/helpers/.keep create mode 100644 test/integration/.keep create mode 100644 test/mailers/.keep create mode 100644 test/models/.keep create mode 100644 test/system/.keep create mode 100644 test/test_helper.rb create mode 100644 tmp/.keep create mode 100644 tmp/pids/.keep create mode 100644 tmp/storage/.keep create mode 100644 vendor/.keep create mode 100644 vendor/javascript/.keep diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000000..325bfc036d --- /dev/null +++ b/.dockerignore @@ -0,0 +1,51 @@ +# See https://docs.docker.com/engine/reference/builder/#dockerignore-file for more about ignoring files. + +# Ignore git directory. +/.git/ +/.gitignore + +# Ignore bundler config. +/.bundle + +# Ignore all environment files. +/.env* + +# Ignore all default key files. +/config/master.key +/config/credentials/*.key + +# Ignore all logfiles and tempfiles. +/log/* +/tmp/* +!/log/.keep +!/tmp/.keep + +# Ignore pidfiles, but keep the directory. +/tmp/pids/* +!/tmp/pids/.keep + +# Ignore storage (uploaded files in development and any SQLite databases). +/storage/* +!/storage/.keep +/tmp/storage/* +!/tmp/storage/.keep + +# Ignore assets. +/node_modules/ +/app/assets/builds/* +!/app/assets/builds/.keep +/public/assets + +# Ignore CI service files. +/.github + +# Ignore Kamal files. +/config/deploy*.yml +/.kamal + +# Ignore development files +/.devcontainer + +# Ignore Docker-related files +/.dockerignore +/Dockerfile* diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000000..8dc4323435 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,9 @@ +# See https://git-scm.com/docs/gitattributes for more about git attribute files. + +# Mark the database schema as having been generated. +db/schema.rb linguist-generated + +# Mark any vendored files as having been vendored. +vendor/* linguist-vendored +config/credentials/*.yml.enc diff=rails_credentials +config/credentials.yml.enc diff=rails_credentials diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000000..f0527e6be1 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,12 @@ +version: 2 +updates: +- package-ecosystem: bundler + directory: "/" + schedule: + interval: daily + open-pull-requests-limit: 10 +- package-ecosystem: github-actions + directory: "/" + schedule: + interval: daily + open-pull-requests-limit: 10 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000000..7b7c0c59b3 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,90 @@ +name: CI + +on: + pull_request: + push: + branches: [ main ] + +jobs: + scan_ruby: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Ruby + uses: ruby/setup-ruby@v1 + with: + ruby-version: .ruby-version + bundler-cache: true + + - name: Scan for common Rails security vulnerabilities using static analysis + run: bin/brakeman --no-pager + + scan_js: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Ruby + uses: ruby/setup-ruby@v1 + with: + ruby-version: .ruby-version + bundler-cache: true + + - name: Scan for security vulnerabilities in JavaScript dependencies + run: bin/importmap audit + + lint: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Ruby + uses: ruby/setup-ruby@v1 + with: + ruby-version: .ruby-version + bundler-cache: true + + - name: Lint code for consistent style + run: bin/rubocop -f github + + test: + runs-on: ubuntu-latest + + # services: + # redis: + # image: redis + # ports: + # - 6379:6379 + # options: --health-cmd "redis-cli ping" --health-interval 10s --health-timeout 5s --health-retries 5 + steps: + - name: Install packages + run: sudo apt-get update && sudo apt-get install --no-install-recommends -y build-essential git libyaml-dev pkg-config google-chrome-stable + + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Ruby + uses: ruby/setup-ruby@v1 + with: + ruby-version: .ruby-version + bundler-cache: true + + - name: Run tests + env: + RAILS_ENV: test + # REDIS_URL: redis://localhost:6379/0 + run: bin/rails db:test:prepare test test:system + + - name: Keep screenshots from failed system tests + uses: actions/upload-artifact@v4 + if: failure() + with: + name: screenshots + path: ${{ github.workspace }}/tmp/screenshots + if-no-files-found: ignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000..f92525ca5e --- /dev/null +++ b/.gitignore @@ -0,0 +1,34 @@ +# See https://help.github.com/articles/ignoring-files for more about ignoring files. +# +# Temporary files generated by your text editor or operating system +# belong in git's global ignore instead: +# `$XDG_CONFIG_HOME/git/ignore` or `~/.config/git/ignore` + +# Ignore bundler config. +/.bundle + +# Ignore all environment files. +/.env* + +# Ignore all logfiles and tempfiles. +/log/* +/tmp/* +!/log/.keep +!/tmp/.keep + +# Ignore pidfiles, but keep the directory. +/tmp/pids/* +!/tmp/pids/ +!/tmp/pids/.keep + +# Ignore storage (uploaded files in development and any SQLite databases). +/storage/* +!/storage/.keep +/tmp/storage/* +!/tmp/storage/ +!/tmp/storage/.keep + +/public/assets + +# Ignore master key for decrypting credentials and more. +/config/master.key diff --git a/.kamal/hooks/docker-setup.sample b/.kamal/hooks/docker-setup.sample new file mode 100644 index 0000000000..2fb07d7d7a --- /dev/null +++ b/.kamal/hooks/docker-setup.sample @@ -0,0 +1,3 @@ +#!/bin/sh + +echo "Docker set up on $KAMAL_HOSTS..." diff --git a/.kamal/hooks/post-app-boot.sample b/.kamal/hooks/post-app-boot.sample new file mode 100644 index 0000000000..70f9c4bc95 --- /dev/null +++ b/.kamal/hooks/post-app-boot.sample @@ -0,0 +1,3 @@ +#!/bin/sh + +echo "Booted app version $KAMAL_VERSION on $KAMAL_HOSTS..." diff --git a/.kamal/hooks/post-deploy.sample b/.kamal/hooks/post-deploy.sample new file mode 100644 index 0000000000..fd364c2a77 --- /dev/null +++ b/.kamal/hooks/post-deploy.sample @@ -0,0 +1,14 @@ +#!/bin/sh + +# A sample post-deploy hook +# +# These environment variables are available: +# KAMAL_RECORDED_AT +# KAMAL_PERFORMER +# KAMAL_VERSION +# KAMAL_HOSTS +# KAMAL_ROLES (if set) +# KAMAL_DESTINATION (if set) +# KAMAL_RUNTIME + +echo "$KAMAL_PERFORMER deployed $KAMAL_VERSION to $KAMAL_DESTINATION in $KAMAL_RUNTIME seconds" diff --git a/.kamal/hooks/post-proxy-reboot.sample b/.kamal/hooks/post-proxy-reboot.sample new file mode 100644 index 0000000000..1435a677f2 --- /dev/null +++ b/.kamal/hooks/post-proxy-reboot.sample @@ -0,0 +1,3 @@ +#!/bin/sh + +echo "Rebooted kamal-proxy on $KAMAL_HOSTS" diff --git a/.kamal/hooks/pre-app-boot.sample b/.kamal/hooks/pre-app-boot.sample new file mode 100644 index 0000000000..45f7355045 --- /dev/null +++ b/.kamal/hooks/pre-app-boot.sample @@ -0,0 +1,3 @@ +#!/bin/sh + +echo "Booting app version $KAMAL_VERSION on $KAMAL_HOSTS..." diff --git a/.kamal/hooks/pre-build.sample b/.kamal/hooks/pre-build.sample new file mode 100644 index 0000000000..c5a55678b2 --- /dev/null +++ b/.kamal/hooks/pre-build.sample @@ -0,0 +1,51 @@ +#!/bin/sh + +# A sample pre-build hook +# +# Checks: +# 1. We have a clean checkout +# 2. A remote is configured +# 3. The branch has been pushed to the remote +# 4. The version we are deploying matches the remote +# +# These environment variables are available: +# KAMAL_RECORDED_AT +# KAMAL_PERFORMER +# KAMAL_VERSION +# KAMAL_HOSTS +# KAMAL_ROLES (if set) +# KAMAL_DESTINATION (if set) + +if [ -n "$(git status --porcelain)" ]; then + echo "Git checkout is not clean, aborting..." >&2 + git status --porcelain >&2 + exit 1 +fi + +first_remote=$(git remote) + +if [ -z "$first_remote" ]; then + echo "No git remote set, aborting..." >&2 + exit 1 +fi + +current_branch=$(git branch --show-current) + +if [ -z "$current_branch" ]; then + echo "Not on a git branch, aborting..." >&2 + exit 1 +fi + +remote_head=$(git ls-remote $first_remote --tags $current_branch | cut -f1) + +if [ -z "$remote_head" ]; then + echo "Branch not pushed to remote, aborting..." >&2 + exit 1 +fi + +if [ "$KAMAL_VERSION" != "$remote_head" ]; then + echo "Version ($KAMAL_VERSION) does not match remote HEAD ($remote_head), aborting..." >&2 + exit 1 +fi + +exit 0 diff --git a/.kamal/hooks/pre-connect.sample b/.kamal/hooks/pre-connect.sample new file mode 100644 index 0000000000..77744bdca8 --- /dev/null +++ b/.kamal/hooks/pre-connect.sample @@ -0,0 +1,47 @@ +#!/usr/bin/env ruby + +# A sample pre-connect check +# +# Warms DNS before connecting to hosts in parallel +# +# These environment variables are available: +# KAMAL_RECORDED_AT +# KAMAL_PERFORMER +# KAMAL_VERSION +# KAMAL_HOSTS +# KAMAL_ROLES (if set) +# KAMAL_DESTINATION (if set) +# KAMAL_RUNTIME + +hosts = ENV["KAMAL_HOSTS"].split(",") +results = nil +max = 3 + +elapsed = Benchmark.realtime do + results = hosts.map do |host| + Thread.new do + tries = 1 + + begin + Socket.getaddrinfo(host, 0, Socket::AF_UNSPEC, Socket::SOCK_STREAM, nil, Socket::AI_CANONNAME) + rescue SocketError + if tries < max + puts "Retrying DNS warmup: #{host}" + tries += 1 + sleep rand + retry + else + puts "DNS warmup failed: #{host}" + host + end + end + + tries + end + end.map(&:value) +end + +retries = results.sum - hosts.size +nopes = results.count { |r| r == max } + +puts "Prewarmed %d DNS lookups in %.2f sec: %d retries, %d failures" % [ hosts.size, elapsed, retries, nopes ] diff --git a/.kamal/hooks/pre-deploy.sample b/.kamal/hooks/pre-deploy.sample new file mode 100644 index 0000000000..05b3055b72 --- /dev/null +++ b/.kamal/hooks/pre-deploy.sample @@ -0,0 +1,122 @@ +#!/usr/bin/env ruby + +# A sample pre-deploy hook +# +# Checks the Github status of the build, waiting for a pending build to complete for up to 720 seconds. +# +# Fails unless the combined status is "success" +# +# These environment variables are available: +# KAMAL_RECORDED_AT +# KAMAL_PERFORMER +# KAMAL_VERSION +# KAMAL_HOSTS +# KAMAL_COMMAND +# KAMAL_SUBCOMMAND +# KAMAL_ROLES (if set) +# KAMAL_DESTINATION (if set) + +# Only check the build status for production deployments +if ENV["KAMAL_COMMAND"] == "rollback" || ENV["KAMAL_DESTINATION"] != "production" + exit 0 +end + +require "bundler/inline" + +# true = install gems so this is fast on repeat invocations +gemfile(true, quiet: true) do + source "https://rubygems.org" + + gem "octokit" + gem "faraday-retry" +end + +MAX_ATTEMPTS = 72 +ATTEMPTS_GAP = 10 + +def exit_with_error(message) + $stderr.puts message + exit 1 +end + +class GithubStatusChecks + attr_reader :remote_url, :git_sha, :github_client, :combined_status + + def initialize + @remote_url = github_repo_from_remote_url + @git_sha = `git rev-parse HEAD`.strip + @github_client = Octokit::Client.new(access_token: ENV["GITHUB_TOKEN"]) + refresh! + end + + def refresh! + @combined_status = github_client.combined_status(remote_url, git_sha) + end + + def state + combined_status[:state] + end + + def first_status_url + first_status = combined_status[:statuses].find { |status| status[:state] == state } + first_status && first_status[:target_url] + end + + def complete_count + combined_status[:statuses].count { |status| status[:state] != "pending"} + end + + def total_count + combined_status[:statuses].count + end + + def current_status + if total_count > 0 + "Completed #{complete_count}/#{total_count} checks, see #{first_status_url} ..." + else + "Build not started..." + end + end + + private + def github_repo_from_remote_url + url = `git config --get remote.origin.url`.strip.delete_suffix(".git") + if url.start_with?("https://github.com/") + url.delete_prefix("https://github.com/") + elsif url.start_with?("git@github.com:") + url.delete_prefix("git@github.com:") + else + url + end + end +end + + +$stdout.sync = true + +begin + puts "Checking build status..." + + attempts = 0 + checks = GithubStatusChecks.new + + loop do + case checks.state + when "success" + puts "Checks passed, see #{checks.first_status_url}" + exit 0 + when "failure" + exit_with_error "Checks failed, see #{checks.first_status_url}" + when "pending" + attempts += 1 + end + + exit_with_error "Checks are still pending, gave up after #{MAX_ATTEMPTS * ATTEMPTS_GAP} seconds" if attempts == MAX_ATTEMPTS + + puts checks.current_status + sleep(ATTEMPTS_GAP) + checks.refresh! + end +rescue Octokit::NotFound + exit_with_error "Build status could not be found" +end diff --git a/.kamal/hooks/pre-proxy-reboot.sample b/.kamal/hooks/pre-proxy-reboot.sample new file mode 100644 index 0000000000..061f8059e6 --- /dev/null +++ b/.kamal/hooks/pre-proxy-reboot.sample @@ -0,0 +1,3 @@ +#!/bin/sh + +echo "Rebooting kamal-proxy on $KAMAL_HOSTS..." diff --git a/.kamal/secrets b/.kamal/secrets new file mode 100644 index 0000000000..9a771a3985 --- /dev/null +++ b/.kamal/secrets @@ -0,0 +1,17 @@ +# Secrets defined here are available for reference under registry/password, env/secret, builder/secrets, +# and accessories/*/env/secret in config/deploy.yml. All secrets should be pulled from either +# password manager, ENV, or a file. DO NOT ENTER RAW CREDENTIALS HERE! This file needs to be safe for git. + +# Example of extracting secrets from 1password (or another compatible pw manager) +# SECRETS=$(kamal secrets fetch --adapter 1password --account your-account --from Vault/Item KAMAL_REGISTRY_PASSWORD RAILS_MASTER_KEY) +# KAMAL_REGISTRY_PASSWORD=$(kamal secrets extract KAMAL_REGISTRY_PASSWORD ${SECRETS}) +# RAILS_MASTER_KEY=$(kamal secrets extract RAILS_MASTER_KEY ${SECRETS}) + +# Use a GITHUB_TOKEN if private repositories are needed for the image +# GITHUB_TOKEN=$(gh config get -h github.com oauth_token) + +# Grab the registry password from ENV +KAMAL_REGISTRY_PASSWORD=$KAMAL_REGISTRY_PASSWORD + +# Improve security by using a password manager. Never check config/master.key into git! +RAILS_MASTER_KEY=$(cat config/master.key) diff --git a/.rubocop.yml b/.rubocop.yml new file mode 100644 index 0000000000..f9d86d4a54 --- /dev/null +++ b/.rubocop.yml @@ -0,0 +1,8 @@ +# Omakase Ruby styling for Rails +inherit_gem: { rubocop-rails-omakase: rubocop.yml } + +# Overwrite or add rules to create your own house style +# +# # Use `[a, [b, c]]` not `[ a, [ b, c ] ]` +# Layout/SpaceInsideArrayLiteralBrackets: +# Enabled: false diff --git a/.ruby-version b/.ruby-version new file mode 100644 index 0000000000..fdeaef88f6 --- /dev/null +++ b/.ruby-version @@ -0,0 +1 @@ +ruby-3.4.7 diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000000..44381516b7 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,72 @@ +# syntax=docker/dockerfile:1 +# check=error=true + +# This Dockerfile is designed for production, not development. Use with Kamal or build'n'run by hand: +# docker build -t projeto_camaar . +# docker run -d -p 80:80 -e RAILS_MASTER_KEY= --name projeto_camaar projeto_camaar + +# For a containerized dev environment, see Dev Containers: https://guides.rubyonrails.org/getting_started_with_devcontainer.html + +# Make sure RUBY_VERSION matches the Ruby version in .ruby-version +ARG RUBY_VERSION=3.4.7 +FROM docker.io/library/ruby:$RUBY_VERSION-slim AS base + +# Rails app lives here +WORKDIR /rails + +# Install base packages +RUN apt-get update -qq && \ + apt-get install --no-install-recommends -y curl libjemalloc2 libvips sqlite3 && \ + rm -rf /var/lib/apt/lists /var/cache/apt/archives + +# Set production environment +ENV RAILS_ENV="production" \ + BUNDLE_DEPLOYMENT="1" \ + BUNDLE_PATH="/usr/local/bundle" \ + BUNDLE_WITHOUT="development" + +# Throw-away build stage to reduce size of final image +FROM base AS build + +# Install packages needed to build gems +RUN apt-get update -qq && \ + apt-get install --no-install-recommends -y build-essential git libyaml-dev pkg-config && \ + rm -rf /var/lib/apt/lists /var/cache/apt/archives + +# Install application gems +COPY Gemfile Gemfile.lock ./ +RUN bundle install && \ + rm -rf ~/.bundle/ "${BUNDLE_PATH}"/ruby/*/cache "${BUNDLE_PATH}"/ruby/*/bundler/gems/*/.git && \ + bundle exec bootsnap precompile --gemfile + +# Copy application code +COPY . . + +# Precompile bootsnap code for faster boot times +RUN bundle exec bootsnap precompile app/ lib/ + +# Precompiling assets for production without requiring secret RAILS_MASTER_KEY +RUN SECRET_KEY_BASE_DUMMY=1 ./bin/rails assets:precompile + + + + +# Final stage for app image +FROM base + +# Copy built artifacts: gems, application +COPY --from=build "${BUNDLE_PATH}" "${BUNDLE_PATH}" +COPY --from=build /rails /rails + +# Run and own only the runtime files as a non-root user for security +RUN groupadd --system --gid 1000 rails && \ + useradd rails --uid 1000 --gid 1000 --create-home --shell /bin/bash && \ + chown -R rails:rails db log storage tmp +USER 1000:1000 + +# Entrypoint prepares the database. +ENTRYPOINT ["/rails/bin/docker-entrypoint"] + +# Start server via Thruster by default, this can be overwritten at runtime +EXPOSE 80 +CMD ["./bin/thrust", "./bin/rails", "server"] diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000000..41a51bd086 --- /dev/null +++ b/Gemfile @@ -0,0 +1,66 @@ +source "https://rubygems.org" + +# Bundle edge Rails instead: gem "rails", github: "rails/rails", branch: "main" +gem "rails", "~> 8.0.4" +# The modern asset pipeline for Rails [https://github.com/rails/propshaft] +gem "propshaft" +# Use sqlite3 as the database for Active Record +gem "sqlite3", ">= 2.1" +# Use the Puma web server [https://github.com/puma/puma] +gem "puma", ">= 5.0" +# Use JavaScript with ESM import maps [https://github.com/rails/importmap-rails] +gem "importmap-rails" +# Hotwire's SPA-like page accelerator [https://turbo.hotwired.dev] +gem "turbo-rails" +# Hotwire's modest JavaScript framework [https://stimulus.hotwired.dev] +gem "stimulus-rails" +# Build JSON APIs with ease [https://github.com/rails/jbuilder] +gem "jbuilder" + +# Use Active Model has_secure_password [https://guides.rubyonrails.org/active_model_basics.html#securepassword] +# gem "bcrypt", "~> 3.1.7" + +# Windows does not include zoneinfo files, so bundle the tzinfo-data gem +gem "tzinfo-data", platforms: %i[ windows jruby ] + +# Use the database-backed adapters for Rails.cache, Active Job, and Action Cable +gem "solid_cache" +gem "solid_queue" +gem "solid_cable" + +# Reduces boot times through caching; required in config/boot.rb +gem "bootsnap", require: false + +# Deploy this application anywhere as a Docker container [https://kamal-deploy.org] +gem "kamal", require: false + +# Add HTTP asset caching/compression and X-Sendfile acceleration to Puma [https://github.com/basecamp/thruster/] +gem "thruster", require: false + +# Use Active Storage variants [https://guides.rubyonrails.org/active_storage_overview.html#transforming-images] +# gem "image_processing", "~> 1.2" + +group :development, :test do + # See https://guides.rubyonrails.org/debugging_rails_applications.html#debugging-with-the-debug-gem + gem "debug", platforms: %i[ mri windows ], require: "debug/prelude" + + # Static analysis for security vulnerabilities [https://brakemanscanner.org/] + gem "brakeman", require: false + + # Omakase Ruby styling [https://github.com/rails/rubocop-rails-omakase/] + gem "rubocop-rails-omakase", require: false +end + +group :development do + # Use console on exceptions pages [https://github.com/rails/web-console] + gem "web-console" +end + +group :test do + # Use system testing [https://guides.rubyonrails.org/testing.html#system-testing] + gem "capybara" + gem "selenium-webdriver" + gem 'cucumber-rails', require: false + # database_cleaner is not mandatory, but highly recommended + gem 'database_cleaner' +end diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000000..88d9dd45db --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,437 @@ +GEM + remote: https://rubygems.org/ + specs: + actioncable (8.0.4) + actionpack (= 8.0.4) + activesupport (= 8.0.4) + nio4r (~> 2.0) + websocket-driver (>= 0.6.1) + zeitwerk (~> 2.6) + actionmailbox (8.0.4) + actionpack (= 8.0.4) + activejob (= 8.0.4) + activerecord (= 8.0.4) + activestorage (= 8.0.4) + activesupport (= 8.0.4) + mail (>= 2.8.0) + actionmailer (8.0.4) + actionpack (= 8.0.4) + actionview (= 8.0.4) + activejob (= 8.0.4) + activesupport (= 8.0.4) + mail (>= 2.8.0) + rails-dom-testing (~> 2.2) + actionpack (8.0.4) + actionview (= 8.0.4) + activesupport (= 8.0.4) + nokogiri (>= 1.8.5) + rack (>= 2.2.4) + rack-session (>= 1.0.1) + rack-test (>= 0.6.3) + rails-dom-testing (~> 2.2) + rails-html-sanitizer (~> 1.6) + useragent (~> 0.16) + actiontext (8.0.4) + actionpack (= 8.0.4) + activerecord (= 8.0.4) + activestorage (= 8.0.4) + activesupport (= 8.0.4) + globalid (>= 0.6.0) + nokogiri (>= 1.8.5) + actionview (8.0.4) + activesupport (= 8.0.4) + builder (~> 3.1) + erubi (~> 1.11) + rails-dom-testing (~> 2.2) + rails-html-sanitizer (~> 1.6) + activejob (8.0.4) + activesupport (= 8.0.4) + globalid (>= 0.3.6) + activemodel (8.0.4) + activesupport (= 8.0.4) + activerecord (8.0.4) + activemodel (= 8.0.4) + activesupport (= 8.0.4) + timeout (>= 0.4.0) + activestorage (8.0.4) + actionpack (= 8.0.4) + activejob (= 8.0.4) + activerecord (= 8.0.4) + activesupport (= 8.0.4) + marcel (~> 1.0) + activesupport (8.0.4) + base64 + benchmark (>= 0.3) + bigdecimal + concurrent-ruby (~> 1.0, >= 1.3.1) + connection_pool (>= 2.2.5) + drb + i18n (>= 1.6, < 2) + logger (>= 1.4.2) + minitest (>= 5.1) + securerandom (>= 0.3) + tzinfo (~> 2.0, >= 2.0.5) + uri (>= 0.13.1) + addressable (2.8.7) + public_suffix (>= 2.0.2, < 7.0) + ast (2.4.3) + base64 (0.3.0) + bcrypt_pbkdf (1.1.1) + benchmark (0.5.0) + bigdecimal (3.3.1) + bindex (0.8.1) + bootsnap (1.18.6) + msgpack (~> 1.2) + brakeman (7.1.1) + racc + builder (3.3.0) + capybara (3.40.0) + addressable + matrix + mini_mime (>= 0.1.3) + nokogiri (~> 1.11) + rack (>= 1.6.0) + rack-test (>= 0.6.3) + regexp_parser (>= 1.5, < 3.0) + xpath (~> 3.2) + concurrent-ruby (1.3.5) + connection_pool (2.5.4) + crass (1.0.6) + cucumber (10.1.1) + base64 (~> 0.2) + builder (~> 3.2) + cucumber-ci-environment (> 9, < 11) + cucumber-core (> 15, < 17) + cucumber-cucumber-expressions (> 17, < 19) + cucumber-html-formatter (> 20.3, < 22) + diff-lcs (~> 1.5) + logger (~> 1.6) + mini_mime (~> 1.1) + multi_test (~> 1.1) + sys-uname (~> 1.3) + cucumber-ci-environment (10.0.1) + cucumber-core (15.3.0) + cucumber-gherkin (> 27, < 35) + cucumber-messages (> 26, < 30) + cucumber-tag-expressions (> 5, < 9) + cucumber-cucumber-expressions (18.0.1) + bigdecimal + cucumber-gherkin (34.0.0) + cucumber-messages (> 25, < 29) + cucumber-html-formatter (21.15.1) + cucumber-messages (> 19, < 28) + cucumber-messages (27.2.0) + cucumber-rails (4.0.0) + capybara (>= 3.25, < 4) + cucumber (>= 7, < 11) + railties (>= 6.1, < 9) + cucumber-tag-expressions (8.0.0) + database_cleaner (2.1.0) + database_cleaner-active_record (>= 2, < 3) + database_cleaner-active_record (2.2.2) + activerecord (>= 5.a) + database_cleaner-core (~> 2.0) + database_cleaner-core (2.0.1) + date (3.5.0) + debug (1.11.0) + irb (~> 1.10) + reline (>= 0.3.8) + diff-lcs (1.6.2) + dotenv (3.1.8) + drb (2.2.3) + ed25519 (1.4.0) + erb (6.0.0) + erubi (1.13.1) + et-orbi (1.4.0) + tzinfo + ffi (1.17.2-aarch64-linux-gnu) + ffi (1.17.2-aarch64-linux-musl) + ffi (1.17.2-arm-linux-gnu) + ffi (1.17.2-arm-linux-musl) + ffi (1.17.2-x86_64-linux-gnu) + ffi (1.17.2-x86_64-linux-musl) + fugit (1.12.1) + et-orbi (~> 1.4) + raabro (~> 1.4) + globalid (1.3.0) + activesupport (>= 6.1) + i18n (1.14.7) + concurrent-ruby (~> 1.0) + importmap-rails (2.2.2) + actionpack (>= 6.0.0) + activesupport (>= 6.0.0) + railties (>= 6.0.0) + io-console (0.8.1) + irb (1.15.3) + pp (>= 0.6.0) + rdoc (>= 4.0.0) + reline (>= 0.4.2) + jbuilder (2.14.1) + actionview (>= 7.0.0) + activesupport (>= 7.0.0) + json (2.16.0) + kamal (2.8.2) + activesupport (>= 7.0) + base64 (~> 0.2) + bcrypt_pbkdf (~> 1.0) + concurrent-ruby (~> 1.2) + dotenv (~> 3.1) + ed25519 (~> 1.4) + net-ssh (~> 7.3) + sshkit (>= 1.23.0, < 2.0) + thor (~> 1.3) + zeitwerk (>= 2.6.18, < 3.0) + language_server-protocol (3.17.0.5) + lint_roller (1.1.0) + logger (1.7.0) + loofah (2.24.1) + crass (~> 1.0.2) + nokogiri (>= 1.12.0) + mail (2.9.0) + logger + mini_mime (>= 0.1.1) + net-imap + net-pop + net-smtp + marcel (1.1.0) + matrix (0.4.3) + memoist3 (1.0.0) + mini_mime (1.1.5) + minitest (5.26.1) + msgpack (1.8.0) + multi_test (1.1.0) + net-imap (0.5.12) + date + net-protocol + net-pop (0.1.2) + net-protocol + net-protocol (0.2.2) + timeout + net-scp (4.1.0) + net-ssh (>= 2.6.5, < 8.0.0) + net-sftp (4.0.0) + net-ssh (>= 5.0.0, < 8.0.0) + net-smtp (0.5.1) + net-protocol + net-ssh (7.3.0) + nio4r (2.7.5) + nokogiri (1.18.10-aarch64-linux-gnu) + racc (~> 1.4) + nokogiri (1.18.10-aarch64-linux-musl) + racc (~> 1.4) + nokogiri (1.18.10-arm-linux-gnu) + racc (~> 1.4) + nokogiri (1.18.10-arm-linux-musl) + racc (~> 1.4) + nokogiri (1.18.10-x86_64-linux-gnu) + racc (~> 1.4) + nokogiri (1.18.10-x86_64-linux-musl) + racc (~> 1.4) + ostruct (0.6.3) + parallel (1.27.0) + parser (3.3.10.0) + ast (~> 2.4.1) + racc + pp (0.6.3) + prettyprint + prettyprint (0.2.0) + prism (1.6.0) + propshaft (1.3.1) + actionpack (>= 7.0.0) + activesupport (>= 7.0.0) + rack + psych (5.2.6) + date + stringio + public_suffix (6.0.2) + puma (7.1.0) + nio4r (~> 2.0) + raabro (1.4.0) + racc (1.8.1) + rack (3.2.4) + rack-session (2.1.1) + base64 (>= 0.1.0) + rack (>= 3.0.0) + rack-test (2.2.0) + rack (>= 1.3) + rackup (2.2.1) + rack (>= 3) + rails (8.0.4) + actioncable (= 8.0.4) + actionmailbox (= 8.0.4) + actionmailer (= 8.0.4) + actionpack (= 8.0.4) + actiontext (= 8.0.4) + actionview (= 8.0.4) + activejob (= 8.0.4) + activemodel (= 8.0.4) + activerecord (= 8.0.4) + activestorage (= 8.0.4) + activesupport (= 8.0.4) + bundler (>= 1.15.0) + railties (= 8.0.4) + rails-dom-testing (2.3.0) + activesupport (>= 5.0.0) + minitest + nokogiri (>= 1.6) + rails-html-sanitizer (1.6.2) + loofah (~> 2.21) + nokogiri (>= 1.15.7, != 1.16.7, != 1.16.6, != 1.16.5, != 1.16.4, != 1.16.3, != 1.16.2, != 1.16.1, != 1.16.0.rc1, != 1.16.0) + railties (8.0.4) + actionpack (= 8.0.4) + activesupport (= 8.0.4) + irb (~> 1.13) + rackup (>= 1.0.0) + rake (>= 12.2) + thor (~> 1.0, >= 1.2.2) + tsort (>= 0.2) + zeitwerk (~> 2.6) + rainbow (3.1.1) + rake (13.3.1) + rdoc (6.15.1) + erb + psych (>= 4.0.0) + tsort + regexp_parser (2.11.3) + reline (0.6.3) + io-console (~> 0.5) + rexml (3.4.4) + rubocop (1.81.7) + json (~> 2.3) + language_server-protocol (~> 3.17.0.2) + lint_roller (~> 1.1.0) + parallel (~> 1.10) + parser (>= 3.3.0.2) + rainbow (>= 2.2.2, < 4.0) + regexp_parser (>= 2.9.3, < 3.0) + rubocop-ast (>= 1.47.1, < 2.0) + ruby-progressbar (~> 1.7) + unicode-display_width (>= 2.4.0, < 4.0) + rubocop-ast (1.48.0) + parser (>= 3.3.7.2) + prism (~> 1.4) + rubocop-performance (1.26.1) + lint_roller (~> 1.1) + rubocop (>= 1.75.0, < 2.0) + rubocop-ast (>= 1.47.1, < 2.0) + rubocop-rails (2.33.4) + activesupport (>= 4.2.0) + lint_roller (~> 1.1) + rack (>= 1.1) + rubocop (>= 1.75.0, < 2.0) + rubocop-ast (>= 1.44.0, < 2.0) + rubocop-rails-omakase (1.1.0) + rubocop (>= 1.72) + rubocop-performance (>= 1.24) + rubocop-rails (>= 2.30) + ruby-progressbar (1.13.0) + rubyzip (3.2.2) + securerandom (0.4.1) + selenium-webdriver (4.38.0) + base64 (~> 0.2) + logger (~> 1.4) + rexml (~> 3.2, >= 3.2.5) + rubyzip (>= 1.2.2, < 4.0) + websocket (~> 1.0) + solid_cable (3.0.12) + actioncable (>= 7.2) + activejob (>= 7.2) + activerecord (>= 7.2) + railties (>= 7.2) + solid_cache (1.0.10) + activejob (>= 7.2) + activerecord (>= 7.2) + railties (>= 7.2) + solid_queue (1.2.4) + activejob (>= 7.1) + activerecord (>= 7.1) + concurrent-ruby (>= 1.3.1) + fugit (~> 1.11) + railties (>= 7.1) + thor (>= 1.3.1) + sqlite3 (2.8.0-aarch64-linux-gnu) + sqlite3 (2.8.0-aarch64-linux-musl) + sqlite3 (2.8.0-arm-linux-gnu) + sqlite3 (2.8.0-arm-linux-musl) + sqlite3 (2.8.0-x86_64-linux-gnu) + sqlite3 (2.8.0-x86_64-linux-musl) + sshkit (1.24.0) + base64 + logger + net-scp (>= 1.1.2) + net-sftp (>= 2.1.2) + net-ssh (>= 2.8.0) + ostruct + stimulus-rails (1.3.4) + railties (>= 6.0.0) + stringio (3.1.8) + sys-uname (1.4.1) + ffi (~> 1.1) + memoist3 (~> 1.0.0) + thor (1.4.0) + thruster (0.1.16) + thruster (0.1.16-aarch64-linux) + thruster (0.1.16-x86_64-linux) + timeout (0.4.4) + tsort (0.2.0) + turbo-rails (2.0.20) + actionpack (>= 7.1.0) + railties (>= 7.1.0) + tzinfo (2.0.6) + concurrent-ruby (~> 1.0) + unicode-display_width (3.2.0) + unicode-emoji (~> 4.1) + unicode-emoji (4.1.0) + uri (1.1.1) + useragent (0.16.11) + web-console (4.2.1) + actionview (>= 6.0.0) + activemodel (>= 6.0.0) + bindex (>= 0.4.0) + railties (>= 6.0.0) + websocket (1.2.11) + websocket-driver (0.8.0) + base64 + websocket-extensions (>= 0.1.0) + websocket-extensions (0.1.5) + xpath (3.2.0) + nokogiri (~> 1.8) + zeitwerk (2.7.3) + +PLATFORMS + aarch64-linux + aarch64-linux-gnu + aarch64-linux-musl + arm-linux-gnu + arm-linux-musl + x86_64-linux + x86_64-linux-gnu + x86_64-linux-musl + +DEPENDENCIES + bootsnap + brakeman + capybara + cucumber-rails + database_cleaner + debug + importmap-rails + jbuilder + kamal + propshaft + puma (>= 5.0) + rails (~> 8.0.4) + rubocop-rails-omakase + selenium-webdriver + solid_cable + solid_cache + solid_queue + sqlite3 (>= 2.1) + stimulus-rails + thruster + turbo-rails + tzinfo-data + web-console + +BUNDLED WITH + 2.6.9 diff --git a/README.md b/README.md index 07a95d0c24..12fe37f3d4 100644 --- a/README.md +++ b/README.md @@ -4,4 +4,4 @@ Sistema para avaliação de atividades acadêmicas remotas do CIC Integrantes Grupo 10: - Bernardo Gomes Rodrigues (231034190) - Isaac Silva (231025216) -- Maria Carolina Burgum Abreu Jorge (231013547) +- Maria Carolina Burgum Abreu Jorge (231013547) \ No newline at end of file diff --git a/Rakefile b/Rakefile new file mode 100644 index 0000000000..9a5ea7383a --- /dev/null +++ b/Rakefile @@ -0,0 +1,6 @@ +# Add your own tasks in files placed in lib/tasks ending in .rake, +# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake. + +require_relative "config/application" + +Rails.application.load_tasks diff --git a/app/assets/images/.keep b/app/assets/images/.keep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/app/assets/stylesheets/application.css b/app/assets/stylesheets/application.css new file mode 100644 index 0000000000..fe93333c0f --- /dev/null +++ b/app/assets/stylesheets/application.css @@ -0,0 +1,10 @@ +/* + * This is a manifest file that'll be compiled into application.css. + * + * With Propshaft, assets are served efficiently without preprocessing steps. You can still include + * application-wide styles in this file, but keep in mind that CSS precedence will follow the standard + * cascading order, meaning styles declared later in the document or manifest will override earlier ones, + * depending on specificity. + * + * Consider organizing styles into separate files for maintainability. + */ diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb new file mode 100644 index 0000000000..0d95db22b4 --- /dev/null +++ b/app/controllers/application_controller.rb @@ -0,0 +1,4 @@ +class ApplicationController < ActionController::Base + # Only allow modern browsers supporting webp images, web push, badges, import maps, CSS nesting, and CSS :has. + allow_browser versions: :modern +end diff --git a/app/controllers/concerns/.keep b/app/controllers/concerns/.keep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb new file mode 100644 index 0000000000..de6be7945c --- /dev/null +++ b/app/helpers/application_helper.rb @@ -0,0 +1,2 @@ +module ApplicationHelper +end diff --git a/app/javascript/application.js b/app/javascript/application.js new file mode 100644 index 0000000000..0d7b49404c --- /dev/null +++ b/app/javascript/application.js @@ -0,0 +1,3 @@ +// Configure your import map in config/importmap.rb. Read more: https://github.com/rails/importmap-rails +import "@hotwired/turbo-rails" +import "controllers" diff --git a/app/javascript/controllers/application.js b/app/javascript/controllers/application.js new file mode 100644 index 0000000000..1213e85c7a --- /dev/null +++ b/app/javascript/controllers/application.js @@ -0,0 +1,9 @@ +import { Application } from "@hotwired/stimulus" + +const application = Application.start() + +// Configure Stimulus development experience +application.debug = false +window.Stimulus = application + +export { application } diff --git a/app/javascript/controllers/hello_controller.js b/app/javascript/controllers/hello_controller.js new file mode 100644 index 0000000000..5975c0789d --- /dev/null +++ b/app/javascript/controllers/hello_controller.js @@ -0,0 +1,7 @@ +import { Controller } from "@hotwired/stimulus" + +export default class extends Controller { + connect() { + this.element.textContent = "Hello World!" + } +} diff --git a/app/javascript/controllers/index.js b/app/javascript/controllers/index.js new file mode 100644 index 0000000000..1156bf8362 --- /dev/null +++ b/app/javascript/controllers/index.js @@ -0,0 +1,4 @@ +// Import and register all your controllers from the importmap via controllers/**/*_controller +import { application } from "controllers/application" +import { eagerLoadControllersFrom } from "@hotwired/stimulus-loading" +eagerLoadControllersFrom("controllers", application) diff --git a/app/jobs/application_job.rb b/app/jobs/application_job.rb new file mode 100644 index 0000000000..d394c3d106 --- /dev/null +++ b/app/jobs/application_job.rb @@ -0,0 +1,7 @@ +class ApplicationJob < ActiveJob::Base + # Automatically retry jobs that encountered a deadlock + # retry_on ActiveRecord::Deadlocked + + # Most jobs are safe to ignore if the underlying records are no longer available + # discard_on ActiveJob::DeserializationError +end diff --git a/app/mailers/application_mailer.rb b/app/mailers/application_mailer.rb new file mode 100644 index 0000000000..3c34c8148f --- /dev/null +++ b/app/mailers/application_mailer.rb @@ -0,0 +1,4 @@ +class ApplicationMailer < ActionMailer::Base + default from: "from@example.com" + layout "mailer" +end diff --git a/app/models/application_record.rb b/app/models/application_record.rb new file mode 100644 index 0000000000..b63caeb8a5 --- /dev/null +++ b/app/models/application_record.rb @@ -0,0 +1,3 @@ +class ApplicationRecord < ActiveRecord::Base + primary_abstract_class +end diff --git a/app/models/concerns/.keep b/app/models/concerns/.keep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb new file mode 100644 index 0000000000..b4e08b61db --- /dev/null +++ b/app/views/layouts/application.html.erb @@ -0,0 +1,28 @@ + + + + <%= content_for(:title) || "Projeto Camaar" %> + + + + <%= csrf_meta_tags %> + <%= csp_meta_tag %> + + <%= yield :head %> + + <%# Enable PWA manifest for installable apps (make sure to enable in config/routes.rb too!) %> + <%#= tag.link rel: "manifest", href: pwa_manifest_path(format: :json) %> + + + + + + <%# Includes all stylesheet files in app/assets/stylesheets %> + <%= stylesheet_link_tag :app, "data-turbo-track": "reload" %> + <%= javascript_importmap_tags %> + + + + <%= yield %> + + diff --git a/app/views/layouts/mailer.html.erb b/app/views/layouts/mailer.html.erb new file mode 100644 index 0000000000..3aac9002ed --- /dev/null +++ b/app/views/layouts/mailer.html.erb @@ -0,0 +1,13 @@ + + + + + + + + + <%= yield %> + + diff --git a/app/views/layouts/mailer.text.erb b/app/views/layouts/mailer.text.erb new file mode 100644 index 0000000000..37f0bddbd7 --- /dev/null +++ b/app/views/layouts/mailer.text.erb @@ -0,0 +1 @@ +<%= yield %> diff --git a/app/views/pwa/manifest.json.erb b/app/views/pwa/manifest.json.erb new file mode 100644 index 0000000000..76a2c73c81 --- /dev/null +++ b/app/views/pwa/manifest.json.erb @@ -0,0 +1,22 @@ +{ + "name": "ProjetoCamaar", + "icons": [ + { + "src": "/icon.png", + "type": "image/png", + "sizes": "512x512" + }, + { + "src": "/icon.png", + "type": "image/png", + "sizes": "512x512", + "purpose": "maskable" + } + ], + "start_url": "/", + "display": "standalone", + "scope": "/", + "description": "ProjetoCamaar.", + "theme_color": "red", + "background_color": "red" +} diff --git a/app/views/pwa/service-worker.js b/app/views/pwa/service-worker.js new file mode 100644 index 0000000000..b3a13fb7bb --- /dev/null +++ b/app/views/pwa/service-worker.js @@ -0,0 +1,26 @@ +// Add a service worker for processing Web Push notifications: +// +// self.addEventListener("push", async (event) => { +// const { title, options } = await event.data.json() +// event.waitUntil(self.registration.showNotification(title, options)) +// }) +// +// self.addEventListener("notificationclick", function(event) { +// event.notification.close() +// event.waitUntil( +// clients.matchAll({ type: "window" }).then((clientList) => { +// for (let i = 0; i < clientList.length; i++) { +// let client = clientList[i] +// let clientPath = (new URL(client.url)).pathname +// +// if (clientPath == event.notification.data.path && "focus" in client) { +// return client.focus() +// } +// } +// +// if (clients.openWindow) { +// return clients.openWindow(event.notification.data.path) +// } +// }) +// ) +// }) diff --git a/bin/brakeman b/bin/brakeman new file mode 100644 index 0000000000..ace1c9ba08 --- /dev/null +++ b/bin/brakeman @@ -0,0 +1,7 @@ +#!/usr/bin/env ruby +require "rubygems" +require "bundler/setup" + +ARGV.unshift("--ensure-latest") + +load Gem.bin_path("brakeman", "brakeman") diff --git a/bin/bundle b/bin/bundle new file mode 100644 index 0000000000..50da5fdf9e --- /dev/null +++ b/bin/bundle @@ -0,0 +1,109 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +# +# This file was generated by Bundler. +# +# The application 'bundle' is installed as part of a gem, and +# this file is here to facilitate running it. +# + +require "rubygems" + +m = Module.new do + module_function + + def invoked_as_script? + File.expand_path($0) == File.expand_path(__FILE__) + end + + def env_var_version + ENV["BUNDLER_VERSION"] + end + + def cli_arg_version + return unless invoked_as_script? # don't want to hijack other binstubs + return unless "update".start_with?(ARGV.first || " ") # must be running `bundle update` + bundler_version = nil + update_index = nil + ARGV.each_with_index do |a, i| + if update_index && update_index.succ == i && a.match?(Gem::Version::ANCHORED_VERSION_PATTERN) + bundler_version = a + end + next unless a =~ /\A--bundler(?:[= ](#{Gem::Version::VERSION_PATTERN}))?\z/ + bundler_version = $1 + update_index = i + end + bundler_version + end + + def gemfile + gemfile = ENV["BUNDLE_GEMFILE"] + return gemfile if gemfile && !gemfile.empty? + + File.expand_path("../Gemfile", __dir__) + end + + def lockfile + lockfile = + case File.basename(gemfile) + when "gems.rb" then gemfile.sub(/\.rb$/, ".locked") + else "#{gemfile}.lock" + end + File.expand_path(lockfile) + end + + def lockfile_version + return unless File.file?(lockfile) + lockfile_contents = File.read(lockfile) + return unless lockfile_contents =~ /\n\nBUNDLED WITH\n\s{2,}(#{Gem::Version::VERSION_PATTERN})\n/ + Regexp.last_match(1) + end + + def bundler_requirement + @bundler_requirement ||= + env_var_version || + cli_arg_version || + bundler_requirement_for(lockfile_version) + end + + def bundler_requirement_for(version) + return "#{Gem::Requirement.default}.a" unless version + + bundler_gem_version = Gem::Version.new(version) + + bundler_gem_version.approximate_recommendation + end + + def load_bundler! + ENV["BUNDLE_GEMFILE"] ||= gemfile + + activate_bundler + end + + def activate_bundler + gem_error = activation_error_handling do + gem "bundler", bundler_requirement + end + return if gem_error.nil? + require_error = activation_error_handling do + require "bundler/version" + end + return if require_error.nil? && Gem::Requirement.new(bundler_requirement).satisfied_by?(Gem::Version.new(Bundler::VERSION)) + warn "Activating bundler (#{bundler_requirement}) failed:\n#{gem_error.message}\n\nTo install the version of bundler this project requires, run `gem install bundler -v '#{bundler_requirement}'`" + exit 42 + end + + def activation_error_handling + yield + nil + rescue StandardError, LoadError => e + e + end +end + +m.load_bundler! + +if m.invoked_as_script? + load Gem.bin_path("bundler", "bundle") +end diff --git a/bin/cucumber b/bin/cucumber new file mode 100644 index 0000000000..eb5e962e86 --- /dev/null +++ b/bin/cucumber @@ -0,0 +1,11 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +vendored_cucumber_bin = Dir["#{File.dirname(__FILE__)}/../vendor/{gems,plugins}/cucumber*/bin/cucumber"].first +if vendored_cucumber_bin + load File.expand_path(vendored_cucumber_bin) +else + require 'rubygems' unless ENV['NO_RUBYGEMS'] + require 'cucumber' + load Cucumber::BINARY +end diff --git a/bin/dev b/bin/dev new file mode 100644 index 0000000000..5f91c20545 --- /dev/null +++ b/bin/dev @@ -0,0 +1,2 @@ +#!/usr/bin/env ruby +exec "./bin/rails", "server", *ARGV diff --git a/bin/docker-entrypoint b/bin/docker-entrypoint new file mode 100644 index 0000000000..57567d69b4 --- /dev/null +++ b/bin/docker-entrypoint @@ -0,0 +1,14 @@ +#!/bin/bash -e + +# Enable jemalloc for reduced memory usage and latency. +if [ -z "${LD_PRELOAD+x}" ]; then + LD_PRELOAD=$(find /usr/lib -name libjemalloc.so.2 -print -quit) + export LD_PRELOAD +fi + +# If running the rails server then create or migrate existing database +if [ "${@: -2:1}" == "./bin/rails" ] && [ "${@: -1:1}" == "server" ]; then + ./bin/rails db:prepare +fi + +exec "${@}" diff --git a/bin/importmap b/bin/importmap new file mode 100644 index 0000000000..36502ab16c --- /dev/null +++ b/bin/importmap @@ -0,0 +1,4 @@ +#!/usr/bin/env ruby + +require_relative "../config/application" +require "importmap/commands" diff --git a/bin/jobs b/bin/jobs new file mode 100644 index 0000000000..dcf59f309a --- /dev/null +++ b/bin/jobs @@ -0,0 +1,6 @@ +#!/usr/bin/env ruby + +require_relative "../config/environment" +require "solid_queue/cli" + +SolidQueue::Cli.start(ARGV) diff --git a/bin/kamal b/bin/kamal new file mode 100644 index 0000000000..cbe59b95ed --- /dev/null +++ b/bin/kamal @@ -0,0 +1,27 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +# +# This file was generated by Bundler. +# +# The application 'kamal' is installed as part of a gem, and +# this file is here to facilitate running it. +# + +ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__) + +bundle_binstub = File.expand_path("bundle", __dir__) + +if File.file?(bundle_binstub) + if File.read(bundle_binstub, 300).include?("This file was generated by Bundler") + load(bundle_binstub) + else + abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run. +Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.") + end +end + +require "rubygems" +require "bundler/setup" + +load Gem.bin_path("kamal", "kamal") diff --git a/bin/rails b/bin/rails new file mode 100644 index 0000000000..efc0377492 --- /dev/null +++ b/bin/rails @@ -0,0 +1,4 @@ +#!/usr/bin/env ruby +APP_PATH = File.expand_path("../config/application", __dir__) +require_relative "../config/boot" +require "rails/commands" diff --git a/bin/rake b/bin/rake new file mode 100644 index 0000000000..4fbf10b960 --- /dev/null +++ b/bin/rake @@ -0,0 +1,4 @@ +#!/usr/bin/env ruby +require_relative "../config/boot" +require "rake" +Rake.application.run diff --git a/bin/rubocop b/bin/rubocop new file mode 100644 index 0000000000..40330c0ff1 --- /dev/null +++ b/bin/rubocop @@ -0,0 +1,8 @@ +#!/usr/bin/env ruby +require "rubygems" +require "bundler/setup" + +# explicit rubocop config increases performance slightly while avoiding config confusion. +ARGV.unshift("--config", File.expand_path("../.rubocop.yml", __dir__)) + +load Gem.bin_path("rubocop", "rubocop") diff --git a/bin/setup b/bin/setup new file mode 100644 index 0000000000..be3db3c0d6 --- /dev/null +++ b/bin/setup @@ -0,0 +1,34 @@ +#!/usr/bin/env ruby +require "fileutils" + +APP_ROOT = File.expand_path("..", __dir__) + +def system!(*args) + system(*args, exception: true) +end + +FileUtils.chdir APP_ROOT do + # This script is a way to set up or update your development environment automatically. + # This script is idempotent, so that you can run it at any time and get an expectable outcome. + # Add necessary setup steps to this file. + + puts "== Installing dependencies ==" + system("bundle check") || system!("bundle install") + + # puts "\n== Copying sample files ==" + # unless File.exist?("config/database.yml") + # FileUtils.cp "config/database.yml.sample", "config/database.yml" + # end + + puts "\n== Preparing database ==" + system! "bin/rails db:prepare" + + puts "\n== Removing old logs and tempfiles ==" + system! "bin/rails log:clear tmp:clear" + + unless ARGV.include?("--skip-server") + puts "\n== Starting development server ==" + STDOUT.flush # flush the output before exec(2) so that it displays + exec "bin/dev" + end +end diff --git a/bin/thrust b/bin/thrust new file mode 100644 index 0000000000..36bde2d832 --- /dev/null +++ b/bin/thrust @@ -0,0 +1,5 @@ +#!/usr/bin/env ruby +require "rubygems" +require "bundler/setup" + +load Gem.bin_path("thruster", "thrust") diff --git a/config.ru b/config.ru new file mode 100644 index 0000000000..4a3c09a688 --- /dev/null +++ b/config.ru @@ -0,0 +1,6 @@ +# This file is used by Rack-based servers to start the application. + +require_relative "config/environment" + +run Rails.application +Rails.application.load_server diff --git a/config/application.rb b/config/application.rb new file mode 100644 index 0000000000..47d380417a --- /dev/null +++ b/config/application.rb @@ -0,0 +1,27 @@ +require_relative "boot" + +require "rails/all" + +# Require the gems listed in Gemfile, including any gems +# you've limited to :test, :development, or :production. +Bundler.require(*Rails.groups) + +module ProjetoCamaar + class Application < Rails::Application + # Initialize configuration defaults for originally generated Rails version. + config.load_defaults 8.0 + + # Please, add to the `ignore` list any other `lib` subdirectories that do + # not contain `.rb` files, or that should not be reloaded or eager loaded. + # Common ones are `templates`, `generators`, or `middleware`, for example. + config.autoload_lib(ignore: %w[assets tasks]) + + # Configuration for the application, engines, and railties goes here. + # + # These settings can be overridden in specific environments using the files + # in config/environments, which are processed later. + # + # config.time_zone = "Central Time (US & Canada)" + # config.eager_load_paths << Rails.root.join("extras") + end +end diff --git a/config/boot.rb b/config/boot.rb new file mode 100644 index 0000000000..988a5ddc46 --- /dev/null +++ b/config/boot.rb @@ -0,0 +1,4 @@ +ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__) + +require "bundler/setup" # Set up gems listed in the Gemfile. +require "bootsnap/setup" # Speed up boot time by caching expensive operations. diff --git a/config/cable.yml b/config/cable.yml new file mode 100644 index 0000000000..b9adc5aa3a --- /dev/null +++ b/config/cable.yml @@ -0,0 +1,17 @@ +# Async adapter only works within the same process, so for manually triggering cable updates from a console, +# and seeing results in the browser, you must do so from the web console (running inside the dev process), +# not a terminal started via bin/rails console! Add "console" to any action or any ERB template view +# to make the web console appear. +development: + adapter: async + +test: + adapter: test + +production: + adapter: solid_cable + connects_to: + database: + writing: cable + polling_interval: 0.1.seconds + message_retention: 1.day diff --git a/config/cache.yml b/config/cache.yml new file mode 100644 index 0000000000..19d490843b --- /dev/null +++ b/config/cache.yml @@ -0,0 +1,16 @@ +default: &default + store_options: + # Cap age of oldest cache entry to fulfill retention policies + # max_age: <%= 60.days.to_i %> + max_size: <%= 256.megabytes %> + namespace: <%= Rails.env %> + +development: + <<: *default + +test: + <<: *default + +production: + database: cache + <<: *default diff --git a/config/credentials.yml.enc b/config/credentials.yml.enc new file mode 100644 index 0000000000..a5d0df1768 --- /dev/null +++ b/config/credentials.yml.enc @@ -0,0 +1 @@ +ctHs0gkoY+BU5N44M3TdJPGY8WdddNyhshywXQnUtSTir7HHVB16FPzt5cCS35Pt43gSnz89k/jUHaDyK+ovHMHav3vRLYbiEIvLjzAXmXRETGRK1xX+yHD4ddg4jJjrBL2KGNRea1dzgp6RM+nfY2dXSvOCljJ1Xm4RnTXdUYCUXQN86mwocT8+O5hw7lnb4CSagQDHpdWFgO1p/2lcnax4bdRNup6N4wop6ALHRozj6Iu82Jwc+Zk8hm/8bqflkw6bmPHHDsgQop9BwefWKJaBBdhvwxD0x1eMLdmzbYHhtiuU4TZkfUq7s8PacQGyQBJZ6XniNsYtT25tpVgCr2rnDIkxqemziHeOXDnU5nVbMd0RiljELgUZQ4eXYFmlUc1ULTmWDElHvBzrUK5dV7EZ+3bpG4F0CXwb2OIKL/VlHIPwDnqPtF56XofPZIZprvL8GkgMSPGvrZm2EwHX8m9YgN7UGLjCgaZUygybXihsQKRDNnk1ilFj--HmGOjo0474w4Pvp8--Ho7PmAnPSHMEvSmHl1sQkQ== \ No newline at end of file diff --git a/config/cucumber.yml b/config/cucumber.yml new file mode 100644 index 0000000000..47a4663ae2 --- /dev/null +++ b/config/cucumber.yml @@ -0,0 +1,8 @@ +<% +rerun = File.file?('rerun.txt') ? IO.read('rerun.txt') : "" +rerun = rerun.strip.gsub /\s/, ' ' +rerun_opts = rerun.empty? ? "--format #{ENV['CUCUMBER_FORMAT'] || 'progress'} features" : "--format #{ENV['CUCUMBER_FORMAT'] || 'pretty'} #{rerun}" +std_opts = "--format #{ENV['CUCUMBER_FORMAT'] || 'pretty'} --strict --tags 'not @wip'" +%> +default: <%= std_opts %> features +rerun: <%= rerun_opts %> --format rerun --out rerun.txt --strict --tags 'not @wip' diff --git a/config/database.yml b/config/database.yml new file mode 100644 index 0000000000..2640cb5f30 --- /dev/null +++ b/config/database.yml @@ -0,0 +1,41 @@ +# SQLite. Versions 3.8.0 and up are supported. +# gem install sqlite3 +# +# Ensure the SQLite 3 gem is defined in your Gemfile +# gem "sqlite3" +# +default: &default + adapter: sqlite3 + pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> + timeout: 5000 + +development: + <<: *default + database: storage/development.sqlite3 + +# Warning: The database defined as "test" will be erased and +# re-generated from your development database when you run "rake". +# Do not set this db to the same as development or production. +test: + <<: *default + database: storage/test.sqlite3 + + +# Store production database in the storage/ directory, which by default +# is mounted as a persistent Docker volume in config/deploy.yml. +production: + primary: + <<: *default + database: storage/production.sqlite3 + cache: + <<: *default + database: storage/production_cache.sqlite3 + migrations_paths: db/cache_migrate + queue: + <<: *default + database: storage/production_queue.sqlite3 + migrations_paths: db/queue_migrate + cable: + <<: *default + database: storage/production_cable.sqlite3 + migrations_paths: db/cable_migrate diff --git a/config/deploy.yml b/config/deploy.yml new file mode 100644 index 0000000000..4a5018889d --- /dev/null +++ b/config/deploy.yml @@ -0,0 +1,116 @@ +# Name of your application. Used to uniquely configure containers. +service: projeto_camaar + +# Name of the container image. +image: your-user/projeto_camaar + +# Deploy to these servers. +servers: + web: + - 192.168.0.1 + # job: + # hosts: + # - 192.168.0.1 + # cmd: bin/jobs + +# Enable SSL auto certification via Let's Encrypt and allow for multiple apps on a single web server. +# Remove this section when using multiple web servers and ensure you terminate SSL at your load balancer. +# +# Note: If using Cloudflare, set encryption mode in SSL/TLS setting to "Full" to enable CF-to-app encryption. +proxy: + ssl: true + host: app.example.com + +# Credentials for your image host. +registry: + # Specify the registry server, if you're not using Docker Hub + # server: registry.digitalocean.com / ghcr.io / ... + username: your-user + + # Always use an access token rather than real password when possible. + password: + - KAMAL_REGISTRY_PASSWORD + +# Inject ENV variables into containers (secrets come from .kamal/secrets). +env: + secret: + - RAILS_MASTER_KEY + clear: + # Run the Solid Queue Supervisor inside the web server's Puma process to do jobs. + # When you start using multiple servers, you should split out job processing to a dedicated machine. + SOLID_QUEUE_IN_PUMA: true + + # Set number of processes dedicated to Solid Queue (default: 1) + # JOB_CONCURRENCY: 3 + + # Set number of cores available to the application on each server (default: 1). + # WEB_CONCURRENCY: 2 + + # Match this to any external database server to configure Active Record correctly + # Use projeto_camaar-db for a db accessory server on same machine via local kamal docker network. + # DB_HOST: 192.168.0.2 + + # Log everything from Rails + # RAILS_LOG_LEVEL: debug + +# Aliases are triggered with "bin/kamal ". You can overwrite arguments on invocation: +# "bin/kamal logs -r job" will tail logs from the first server in the job section. +aliases: + console: app exec --interactive --reuse "bin/rails console" + shell: app exec --interactive --reuse "bash" + logs: app logs -f + dbc: app exec --interactive --reuse "bin/rails dbconsole" + + +# Use a persistent storage volume for sqlite database files and local Active Storage files. +# Recommended to change this to a mounted volume path that is backed up off server. +volumes: + - "projeto_camaar_storage:/rails/storage" + + +# Bridge fingerprinted assets, like JS and CSS, between versions to avoid +# hitting 404 on in-flight requests. Combines all files from new and old +# version inside the asset_path. +asset_path: /rails/public/assets + +# Configure the image builder. +builder: + arch: amd64 + + # # Build image via remote server (useful for faster amd64 builds on arm64 computers) + # remote: ssh://docker@docker-builder-server + # + # # Pass arguments and secrets to the Docker build process + # args: + # RUBY_VERSION: ruby-3.4.7 + # secrets: + # - GITHUB_TOKEN + # - RAILS_MASTER_KEY + +# Use a different ssh user than root +# ssh: +# user: app + +# Use accessory services (secrets come from .kamal/secrets). +# accessories: +# db: +# image: mysql:8.0 +# host: 192.168.0.2 +# # Change to 3306 to expose port to the world instead of just local network. +# port: "127.0.0.1:3306:3306" +# env: +# clear: +# MYSQL_ROOT_HOST: '%' +# secret: +# - MYSQL_ROOT_PASSWORD +# files: +# - config/mysql/production.cnf:/etc/mysql/my.cnf +# - db/production.sql:/docker-entrypoint-initdb.d/setup.sql +# directories: +# - data:/var/lib/mysql +# redis: +# image: redis:7.0 +# host: 192.168.0.2 +# port: 6379 +# directories: +# - data:/data diff --git a/config/environment.rb b/config/environment.rb new file mode 100644 index 0000000000..cac5315775 --- /dev/null +++ b/config/environment.rb @@ -0,0 +1,5 @@ +# Load the Rails application. +require_relative "application" + +# Initialize the Rails application. +Rails.application.initialize! diff --git a/config/environments/development.rb b/config/environments/development.rb new file mode 100644 index 0000000000..1a0bf09e40 --- /dev/null +++ b/config/environments/development.rb @@ -0,0 +1,76 @@ +require "active_support/core_ext/integer/time" + +Rails.application.configure do + # Configure 'rails notes' to inspect Cucumber files + config.annotations.register_directories('features') + config.annotations.register_extensions('feature') { |tag| /#\s*(#{tag}):?\s*(.*)$/ } + + # Settings specified here will take precedence over those in config/application.rb. + + # Make code changes take effect immediately without server restart. + config.enable_reloading = true + + # Do not eager load code on boot. + config.eager_load = false + + # Show full error reports. + config.consider_all_requests_local = true + + # Enable server timing. + config.server_timing = true + + # Enable/disable Action Controller caching. By default Action Controller caching is disabled. + # Run rails dev:cache to toggle Action Controller caching. + if Rails.root.join("tmp/caching-dev.txt").exist? + config.action_controller.perform_caching = true + config.action_controller.enable_fragment_cache_logging = true + config.public_file_server.headers = { "cache-control" => "public, max-age=#{2.days.to_i}" } + else + config.action_controller.perform_caching = false + end + + # Change to :null_store to avoid any caching. + config.cache_store = :memory_store + + # Store uploaded files on the local file system (see config/storage.yml for options). + config.active_storage.service = :local + + # Don't care if the mailer can't send. + config.action_mailer.raise_delivery_errors = false + + # Make template changes take effect immediately. + config.action_mailer.perform_caching = false + + # Set localhost to be used by links generated in mailer templates. + config.action_mailer.default_url_options = { host: "localhost", port: 3000 } + + # Print deprecation notices to the Rails logger. + config.active_support.deprecation = :log + + # Raise an error on page load if there are pending migrations. + config.active_record.migration_error = :page_load + + # Highlight code that triggered database queries in logs. + config.active_record.verbose_query_logs = true + + # Append comments with runtime information tags to SQL queries in logs. + config.active_record.query_log_tags_enabled = true + + # Highlight code that enqueued background job in logs. + config.active_job.verbose_enqueue_logs = true + + # Raises error for missing translations. + # config.i18n.raise_on_missing_translations = true + + # Annotate rendered view with file names. + config.action_view.annotate_rendered_view_with_filenames = true + + # Uncomment if you wish to allow Action Cable access from any origin. + # config.action_cable.disable_request_forgery_protection = true + + # Raise error when a before_action's only/except options reference missing actions. + config.action_controller.raise_on_missing_callback_actions = true + + # Apply autocorrection by RuboCop to files generated by `bin/rails generate`. + # config.generators.apply_rubocop_autocorrect_after_generate! +end diff --git a/config/environments/production.rb b/config/environments/production.rb new file mode 100644 index 0000000000..bdcd01d1bf --- /dev/null +++ b/config/environments/production.rb @@ -0,0 +1,90 @@ +require "active_support/core_ext/integer/time" + +Rails.application.configure do + # Settings specified here will take precedence over those in config/application.rb. + + # Code is not reloaded between requests. + config.enable_reloading = false + + # Eager load code on boot for better performance and memory savings (ignored by Rake tasks). + config.eager_load = true + + # Full error reports are disabled. + config.consider_all_requests_local = false + + # Turn on fragment caching in view templates. + config.action_controller.perform_caching = true + + # Cache assets for far-future expiry since they are all digest stamped. + config.public_file_server.headers = { "cache-control" => "public, max-age=#{1.year.to_i}" } + + # Enable serving of images, stylesheets, and JavaScripts from an asset server. + # config.asset_host = "http://assets.example.com" + + # Store uploaded files on the local file system (see config/storage.yml for options). + config.active_storage.service = :local + + # Assume all access to the app is happening through a SSL-terminating reverse proxy. + config.assume_ssl = true + + # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. + config.force_ssl = true + + # Skip http-to-https redirect for the default health check endpoint. + # config.ssl_options = { redirect: { exclude: ->(request) { request.path == "/up" } } } + + # Log to STDOUT with the current request id as a default log tag. + config.log_tags = [ :request_id ] + config.logger = ActiveSupport::TaggedLogging.logger(STDOUT) + + # Change to "debug" to log everything (including potentially personally-identifiable information!) + config.log_level = ENV.fetch("RAILS_LOG_LEVEL", "info") + + # Prevent health checks from clogging up the logs. + config.silence_healthcheck_path = "/up" + + # Don't log any deprecations. + config.active_support.report_deprecations = false + + # Replace the default in-process memory cache store with a durable alternative. + config.cache_store = :solid_cache_store + + # Replace the default in-process and non-durable queuing backend for Active Job. + config.active_job.queue_adapter = :solid_queue + config.solid_queue.connects_to = { database: { writing: :queue } } + + # Ignore bad email addresses and do not raise email delivery errors. + # Set this to true and configure the email server for immediate delivery to raise delivery errors. + # config.action_mailer.raise_delivery_errors = false + + # Set host to be used by links generated in mailer templates. + config.action_mailer.default_url_options = { host: "example.com" } + + # Specify outgoing SMTP server. Remember to add smtp/* credentials via rails credentials:edit. + # config.action_mailer.smtp_settings = { + # user_name: Rails.application.credentials.dig(:smtp, :user_name), + # password: Rails.application.credentials.dig(:smtp, :password), + # address: "smtp.example.com", + # port: 587, + # authentication: :plain + # } + + # Enable locale fallbacks for I18n (makes lookups for any locale fall back to + # the I18n.default_locale when a translation cannot be found). + config.i18n.fallbacks = true + + # Do not dump schema after migrations. + config.active_record.dump_schema_after_migration = false + + # Only use :id for inspections in production. + config.active_record.attributes_for_inspect = [ :id ] + + # Enable DNS rebinding protection and other `Host` header attacks. + # config.hosts = [ + # "example.com", # Allow requests from example.com + # /.*\.example\.com/ # Allow requests from subdomains like `www.example.com` + # ] + # + # Skip DNS rebinding protection for the default health check endpoint. + # config.host_authorization = { exclude: ->(request) { request.path == "/up" } } +end diff --git a/config/environments/test.rb b/config/environments/test.rb new file mode 100644 index 0000000000..e6b5c1b020 --- /dev/null +++ b/config/environments/test.rb @@ -0,0 +1,57 @@ +# The test environment is used exclusively to run your application's +# test suite. You never need to work with it otherwise. Remember that +# your test database is "scratch space" for the test suite and is wiped +# and recreated between test runs. Don't rely on the data there! + +Rails.application.configure do + # Configure 'rails notes' to inspect Cucumber files + config.annotations.register_directories('features') + config.annotations.register_extensions('feature') { |tag| /#\s*(#{tag}):?\s*(.*)$/ } + + # Settings specified here will take precedence over those in config/application.rb. + + # While tests run files are not watched, reloading is not necessary. + config.enable_reloading = false + + # Eager loading loads your entire application. When running a single test locally, + # this is usually not necessary, and can slow down your test suite. However, it's + # recommended that you enable it in continuous integration systems to ensure eager + # loading is working properly before deploying your code. + config.eager_load = ENV["CI"].present? + + # Configure public file server for tests with cache-control for performance. + config.public_file_server.headers = { "cache-control" => "public, max-age=3600" } + + # Show full error reports. + config.consider_all_requests_local = true + config.cache_store = :null_store + + # Render exception templates for rescuable exceptions and raise for other exceptions. + config.action_dispatch.show_exceptions = :rescuable + + # Disable request forgery protection in test environment. + config.action_controller.allow_forgery_protection = false + + # Store uploaded files on the local file system in a temporary directory. + config.active_storage.service = :test + + # Tell Action Mailer not to deliver emails to the real world. + # The :test delivery method accumulates sent emails in the + # ActionMailer::Base.deliveries array. + config.action_mailer.delivery_method = :test + + # Set host to be used by links generated in mailer templates. + config.action_mailer.default_url_options = { host: "example.com" } + + # Print deprecation notices to the stderr. + config.active_support.deprecation = :stderr + + # Raises error for missing translations. + # config.i18n.raise_on_missing_translations = true + + # Annotate rendered view with file names. + # config.action_view.annotate_rendered_view_with_filenames = true + + # Raise error when a before_action's only/except options reference missing actions. + config.action_controller.raise_on_missing_callback_actions = true +end diff --git a/config/importmap.rb b/config/importmap.rb new file mode 100644 index 0000000000..909dfc542d --- /dev/null +++ b/config/importmap.rb @@ -0,0 +1,7 @@ +# Pin npm packages by running ./bin/importmap + +pin "application" +pin "@hotwired/turbo-rails", to: "turbo.min.js" +pin "@hotwired/stimulus", to: "stimulus.min.js" +pin "@hotwired/stimulus-loading", to: "stimulus-loading.js" +pin_all_from "app/javascript/controllers", under: "controllers" diff --git a/config/initializers/assets.rb b/config/initializers/assets.rb new file mode 100644 index 0000000000..487324424f --- /dev/null +++ b/config/initializers/assets.rb @@ -0,0 +1,7 @@ +# Be sure to restart your server when you modify this file. + +# Version of your assets, change this if you want to expire all your assets. +Rails.application.config.assets.version = "1.0" + +# Add additional assets to the asset load path. +# Rails.application.config.assets.paths << Emoji.images_path diff --git a/config/initializers/content_security_policy.rb b/config/initializers/content_security_policy.rb new file mode 100644 index 0000000000..b3076b38fe --- /dev/null +++ b/config/initializers/content_security_policy.rb @@ -0,0 +1,25 @@ +# Be sure to restart your server when you modify this file. + +# Define an application-wide content security policy. +# See the Securing Rails Applications Guide for more information: +# https://guides.rubyonrails.org/security.html#content-security-policy-header + +# Rails.application.configure do +# config.content_security_policy do |policy| +# policy.default_src :self, :https +# policy.font_src :self, :https, :data +# policy.img_src :self, :https, :data +# policy.object_src :none +# policy.script_src :self, :https +# policy.style_src :self, :https +# # Specify URI for violation reports +# # policy.report_uri "/csp-violation-report-endpoint" +# end +# +# # Generate session nonces for permitted importmap, inline scripts, and inline styles. +# config.content_security_policy_nonce_generator = ->(request) { request.session.id.to_s } +# config.content_security_policy_nonce_directives = %w(script-src style-src) +# +# # Report violations without enforcing the policy. +# # config.content_security_policy_report_only = true +# end diff --git a/config/initializers/filter_parameter_logging.rb b/config/initializers/filter_parameter_logging.rb new file mode 100644 index 0000000000..c0b717f7ec --- /dev/null +++ b/config/initializers/filter_parameter_logging.rb @@ -0,0 +1,8 @@ +# Be sure to restart your server when you modify this file. + +# Configure parameters to be partially matched (e.g. passw matches password) and filtered from the log file. +# Use this to limit dissemination of sensitive information. +# See the ActiveSupport::ParameterFilter documentation for supported notations and behaviors. +Rails.application.config.filter_parameters += [ + :passw, :email, :secret, :token, :_key, :crypt, :salt, :certificate, :otp, :ssn, :cvv, :cvc +] diff --git a/config/initializers/inflections.rb b/config/initializers/inflections.rb new file mode 100644 index 0000000000..3860f659ea --- /dev/null +++ b/config/initializers/inflections.rb @@ -0,0 +1,16 @@ +# Be sure to restart your server when you modify this file. + +# Add new inflection rules using the following format. Inflections +# are locale specific, and you may define rules for as many different +# locales as you wish. All of these examples are active by default: +# ActiveSupport::Inflector.inflections(:en) do |inflect| +# inflect.plural /^(ox)$/i, "\\1en" +# inflect.singular /^(ox)en/i, "\\1" +# inflect.irregular "person", "people" +# inflect.uncountable %w( fish sheep ) +# end + +# These inflection rules are supported but not enabled by default: +# ActiveSupport::Inflector.inflections(:en) do |inflect| +# inflect.acronym "RESTful" +# end diff --git a/config/locales/en.yml b/config/locales/en.yml new file mode 100644 index 0000000000..6c349ae5e3 --- /dev/null +++ b/config/locales/en.yml @@ -0,0 +1,31 @@ +# Files in the config/locales directory are used for internationalization and +# are automatically loaded by Rails. If you want to use locales other than +# English, add the necessary files in this directory. +# +# To use the locales, use `I18n.t`: +# +# I18n.t "hello" +# +# In views, this is aliased to just `t`: +# +# <%= t("hello") %> +# +# To use a different locale, set it with `I18n.locale`: +# +# I18n.locale = :es +# +# This would use the information in config/locales/es.yml. +# +# To learn more about the API, please read the Rails Internationalization guide +# at https://guides.rubyonrails.org/i18n.html. +# +# Be aware that YAML interprets the following case-insensitive strings as +# booleans: `true`, `false`, `on`, `off`, `yes`, `no`. Therefore, these strings +# must be quoted to be interpreted as strings. For example: +# +# en: +# "yes": yup +# enabled: "ON" + +en: + hello: "Hello world" diff --git a/config/puma.rb b/config/puma.rb new file mode 100644 index 0000000000..a248513b24 --- /dev/null +++ b/config/puma.rb @@ -0,0 +1,41 @@ +# This configuration file will be evaluated by Puma. The top-level methods that +# are invoked here are part of Puma's configuration DSL. For more information +# about methods provided by the DSL, see https://puma.io/puma/Puma/DSL.html. +# +# Puma starts a configurable number of processes (workers) and each process +# serves each request in a thread from an internal thread pool. +# +# You can control the number of workers using ENV["WEB_CONCURRENCY"]. You +# should only set this value when you want to run 2 or more workers. The +# default is already 1. +# +# The ideal number of threads per worker depends both on how much time the +# application spends waiting for IO operations and on how much you wish to +# prioritize throughput over latency. +# +# As a rule of thumb, increasing the number of threads will increase how much +# traffic a given process can handle (throughput), but due to CRuby's +# Global VM Lock (GVL) it has diminishing returns and will degrade the +# response time (latency) of the application. +# +# The default is set to 3 threads as it's deemed a decent compromise between +# throughput and latency for the average Rails application. +# +# Any libraries that use a connection pool or another resource pool should +# be configured to provide at least as many connections as the number of +# threads. This includes Active Record's `pool` parameter in `database.yml`. +threads_count = ENV.fetch("RAILS_MAX_THREADS", 3) +threads threads_count, threads_count + +# Specifies the `port` that Puma will listen on to receive requests; default is 3000. +port ENV.fetch("PORT", 3000) + +# Allow puma to be restarted by `bin/rails restart` command. +plugin :tmp_restart + +# Run the Solid Queue supervisor inside of Puma for single-server deployments +plugin :solid_queue if ENV["SOLID_QUEUE_IN_PUMA"] + +# Specify the PID file. Defaults to tmp/pids/server.pid in development. +# In other environments, only set the PID file if requested. +pidfile ENV["PIDFILE"] if ENV["PIDFILE"] diff --git a/config/queue.yml b/config/queue.yml new file mode 100644 index 0000000000..9eace59c41 --- /dev/null +++ b/config/queue.yml @@ -0,0 +1,18 @@ +default: &default + dispatchers: + - polling_interval: 1 + batch_size: 500 + workers: + - queues: "*" + threads: 3 + processes: <%= ENV.fetch("JOB_CONCURRENCY", 1) %> + polling_interval: 0.1 + +development: + <<: *default + +test: + <<: *default + +production: + <<: *default diff --git a/config/recurring.yml b/config/recurring.yml new file mode 100644 index 0000000000..b4207f9b07 --- /dev/null +++ b/config/recurring.yml @@ -0,0 +1,15 @@ +# examples: +# periodic_cleanup: +# class: CleanSoftDeletedRecordsJob +# queue: background +# args: [ 1000, { batch_size: 500 } ] +# schedule: every hour +# periodic_cleanup_with_command: +# command: "SoftDeletedRecord.due.delete_all" +# priority: 2 +# schedule: at 5am every day + +production: + clear_solid_queue_finished_jobs: + command: "SolidQueue::Job.clear_finished_in_batches(sleep_between_batches: 0.3)" + schedule: every hour at minute 12 diff --git a/config/routes.rb b/config/routes.rb new file mode 100644 index 0000000000..48254e88ed --- /dev/null +++ b/config/routes.rb @@ -0,0 +1,14 @@ +Rails.application.routes.draw do + # Define your application routes per the DSL in https://guides.rubyonrails.org/routing.html + + # Reveal health status on /up that returns 200 if the app boots with no exceptions, otherwise 500. + # Can be used by load balancers and uptime monitors to verify that the app is live. + get "up" => "rails/health#show", as: :rails_health_check + + # Render dynamic PWA files from app/views/pwa/* (remember to link manifest in application.html.erb) + # get "manifest" => "rails/pwa#manifest", as: :pwa_manifest + # get "service-worker" => "rails/pwa#service_worker", as: :pwa_service_worker + + # Defines the root path route ("/") + # root "posts#index" +end diff --git a/config/storage.yml b/config/storage.yml new file mode 100644 index 0000000000..4942ab6694 --- /dev/null +++ b/config/storage.yml @@ -0,0 +1,34 @@ +test: + service: Disk + root: <%= Rails.root.join("tmp/storage") %> + +local: + service: Disk + root: <%= Rails.root.join("storage") %> + +# Use bin/rails credentials:edit to set the AWS secrets (as aws:access_key_id|secret_access_key) +# amazon: +# service: S3 +# access_key_id: <%= Rails.application.credentials.dig(:aws, :access_key_id) %> +# secret_access_key: <%= Rails.application.credentials.dig(:aws, :secret_access_key) %> +# region: us-east-1 +# bucket: your_own_bucket-<%= Rails.env %> + +# Remember not to checkin your GCS keyfile to a repository +# google: +# service: GCS +# project: your_project +# credentials: <%= Rails.root.join("path/to/gcs.keyfile") %> +# bucket: your_own_bucket-<%= Rails.env %> + +# Use bin/rails credentials:edit to set the Azure Storage secret (as azure_storage:storage_access_key) +# microsoft: +# service: AzureStorage +# storage_account_name: your_account_name +# storage_access_key: <%= Rails.application.credentials.dig(:azure_storage, :storage_access_key) %> +# container: your_container_name-<%= Rails.env %> + +# mirror: +# service: Mirror +# primary: local +# mirrors: [ amazon, google, microsoft ] diff --git a/db/cable_schema.rb b/db/cable_schema.rb new file mode 100644 index 0000000000..23666604a5 --- /dev/null +++ b/db/cable_schema.rb @@ -0,0 +1,11 @@ +ActiveRecord::Schema[7.1].define(version: 1) do + create_table "solid_cable_messages", force: :cascade do |t| + t.binary "channel", limit: 1024, null: false + t.binary "payload", limit: 536870912, null: false + t.datetime "created_at", null: false + t.integer "channel_hash", limit: 8, null: false + t.index ["channel"], name: "index_solid_cable_messages_on_channel" + t.index ["channel_hash"], name: "index_solid_cable_messages_on_channel_hash" + t.index ["created_at"], name: "index_solid_cable_messages_on_created_at" + end +end diff --git a/db/cache_schema.rb b/db/cache_schema.rb new file mode 100644 index 0000000000..81a410d188 --- /dev/null +++ b/db/cache_schema.rb @@ -0,0 +1,12 @@ +ActiveRecord::Schema[7.2].define(version: 1) do + create_table "solid_cache_entries", force: :cascade do |t| + t.binary "key", limit: 1024, null: false + t.binary "value", limit: 536870912, null: false + t.datetime "created_at", null: false + t.integer "key_hash", limit: 8, null: false + t.integer "byte_size", limit: 4, null: false + t.index ["byte_size"], name: "index_solid_cache_entries_on_byte_size" + t.index ["key_hash", "byte_size"], name: "index_solid_cache_entries_on_key_hash_and_byte_size" + t.index ["key_hash"], name: "index_solid_cache_entries_on_key_hash", unique: true + end +end diff --git a/db/queue_schema.rb b/db/queue_schema.rb new file mode 100644 index 0000000000..85194b6a88 --- /dev/null +++ b/db/queue_schema.rb @@ -0,0 +1,129 @@ +ActiveRecord::Schema[7.1].define(version: 1) do + create_table "solid_queue_blocked_executions", force: :cascade do |t| + t.bigint "job_id", null: false + t.string "queue_name", null: false + t.integer "priority", default: 0, null: false + t.string "concurrency_key", null: false + t.datetime "expires_at", null: false + t.datetime "created_at", null: false + t.index [ "concurrency_key", "priority", "job_id" ], name: "index_solid_queue_blocked_executions_for_release" + t.index [ "expires_at", "concurrency_key" ], name: "index_solid_queue_blocked_executions_for_maintenance" + t.index [ "job_id" ], name: "index_solid_queue_blocked_executions_on_job_id", unique: true + end + + create_table "solid_queue_claimed_executions", force: :cascade do |t| + t.bigint "job_id", null: false + t.bigint "process_id" + t.datetime "created_at", null: false + t.index [ "job_id" ], name: "index_solid_queue_claimed_executions_on_job_id", unique: true + t.index [ "process_id", "job_id" ], name: "index_solid_queue_claimed_executions_on_process_id_and_job_id" + end + + create_table "solid_queue_failed_executions", force: :cascade do |t| + t.bigint "job_id", null: false + t.text "error" + t.datetime "created_at", null: false + t.index [ "job_id" ], name: "index_solid_queue_failed_executions_on_job_id", unique: true + end + + create_table "solid_queue_jobs", force: :cascade do |t| + t.string "queue_name", null: false + t.string "class_name", null: false + t.text "arguments" + t.integer "priority", default: 0, null: false + t.string "active_job_id" + t.datetime "scheduled_at" + t.datetime "finished_at" + t.string "concurrency_key" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index [ "active_job_id" ], name: "index_solid_queue_jobs_on_active_job_id" + t.index [ "class_name" ], name: "index_solid_queue_jobs_on_class_name" + t.index [ "finished_at" ], name: "index_solid_queue_jobs_on_finished_at" + t.index [ "queue_name", "finished_at" ], name: "index_solid_queue_jobs_for_filtering" + t.index [ "scheduled_at", "finished_at" ], name: "index_solid_queue_jobs_for_alerting" + end + + create_table "solid_queue_pauses", force: :cascade do |t| + t.string "queue_name", null: false + t.datetime "created_at", null: false + t.index [ "queue_name" ], name: "index_solid_queue_pauses_on_queue_name", unique: true + end + + create_table "solid_queue_processes", force: :cascade do |t| + t.string "kind", null: false + t.datetime "last_heartbeat_at", null: false + t.bigint "supervisor_id" + t.integer "pid", null: false + t.string "hostname" + t.text "metadata" + t.datetime "created_at", null: false + t.string "name", null: false + t.index [ "last_heartbeat_at" ], name: "index_solid_queue_processes_on_last_heartbeat_at" + t.index [ "name", "supervisor_id" ], name: "index_solid_queue_processes_on_name_and_supervisor_id", unique: true + t.index [ "supervisor_id" ], name: "index_solid_queue_processes_on_supervisor_id" + end + + create_table "solid_queue_ready_executions", force: :cascade do |t| + t.bigint "job_id", null: false + t.string "queue_name", null: false + t.integer "priority", default: 0, null: false + t.datetime "created_at", null: false + t.index [ "job_id" ], name: "index_solid_queue_ready_executions_on_job_id", unique: true + t.index [ "priority", "job_id" ], name: "index_solid_queue_poll_all" + t.index [ "queue_name", "priority", "job_id" ], name: "index_solid_queue_poll_by_queue" + end + + create_table "solid_queue_recurring_executions", force: :cascade do |t| + t.bigint "job_id", null: false + t.string "task_key", null: false + t.datetime "run_at", null: false + t.datetime "created_at", null: false + t.index [ "job_id" ], name: "index_solid_queue_recurring_executions_on_job_id", unique: true + t.index [ "task_key", "run_at" ], name: "index_solid_queue_recurring_executions_on_task_key_and_run_at", unique: true + end + + create_table "solid_queue_recurring_tasks", force: :cascade do |t| + t.string "key", null: false + t.string "schedule", null: false + t.string "command", limit: 2048 + t.string "class_name" + t.text "arguments" + t.string "queue_name" + t.integer "priority", default: 0 + t.boolean "static", default: true, null: false + t.text "description" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index [ "key" ], name: "index_solid_queue_recurring_tasks_on_key", unique: true + t.index [ "static" ], name: "index_solid_queue_recurring_tasks_on_static" + end + + create_table "solid_queue_scheduled_executions", force: :cascade do |t| + t.bigint "job_id", null: false + t.string "queue_name", null: false + t.integer "priority", default: 0, null: false + t.datetime "scheduled_at", null: false + t.datetime "created_at", null: false + t.index [ "job_id" ], name: "index_solid_queue_scheduled_executions_on_job_id", unique: true + t.index [ "scheduled_at", "priority", "job_id" ], name: "index_solid_queue_dispatch_all" + end + + create_table "solid_queue_semaphores", force: :cascade do |t| + t.string "key", null: false + t.integer "value", default: 1, null: false + t.datetime "expires_at", null: false + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index [ "expires_at" ], name: "index_solid_queue_semaphores_on_expires_at" + t.index [ "key", "value" ], name: "index_solid_queue_semaphores_on_key_and_value" + t.index [ "key" ], name: "index_solid_queue_semaphores_on_key", unique: true + end + + add_foreign_key "solid_queue_blocked_executions", "solid_queue_jobs", column: "job_id", on_delete: :cascade + add_foreign_key "solid_queue_claimed_executions", "solid_queue_jobs", column: "job_id", on_delete: :cascade + add_foreign_key "solid_queue_failed_executions", "solid_queue_jobs", column: "job_id", on_delete: :cascade + add_foreign_key "solid_queue_ready_executions", "solid_queue_jobs", column: "job_id", on_delete: :cascade + add_foreign_key "solid_queue_recurring_executions", "solid_queue_jobs", column: "job_id", on_delete: :cascade + add_foreign_key "solid_queue_scheduled_executions", "solid_queue_jobs", column: "job_id", on_delete: :cascade +end diff --git a/db/seeds.rb b/db/seeds.rb new file mode 100644 index 0000000000..4fbd6ed970 --- /dev/null +++ b/db/seeds.rb @@ -0,0 +1,9 @@ +# This file should ensure the existence of records required to run the application in every environment (production, +# development, test). The code here should be idempotent so that it can be executed at any point in every environment. +# The data can then be loaded with the bin/rails db:seed command (or created alongside the database with db:setup). +# +# Example: +# +# ["Action", "Comedy", "Drama", "Horror"].each do |genre_name| +# MovieGenre.find_or_create_by!(name: genre_name) +# end diff --git a/features/importar_dados_sigaa.feature b/features/importar_dados_sigaa.feature new file mode 100644 index 0000000000..04a13e0cdb --- /dev/null +++ b/features/importar_dados_sigaa.feature @@ -0,0 +1,24 @@ +Feature: Importar dados do SIGAA + Como Administrador + Quero importar dados de turmas, matérias e participantes do SIGAA + A fim de alimentar a base de dados do sistema + + Background: + Given que estou autenticado como administrador + + Scenario: Importação bem-sucedida (feliz) + Given que existem turmas, matérias e participantes no SIGAA + When eu realizo a importação de dados + Then os dados devem ser armazenados na base do sistema + And eu devo ver a mensagem "Importação concluída com sucesso" + + Scenario: Dados já existentes na base (triste) + Given que alguns dados do SIGAA já existem na base local + When eu tento importar novamente + Then o sistema deve ignorar os registros duplicados + And eu devo ver a mensagem "Nenhum dado novo foi importado" + + Scenario: Erro de conexão com o SIGAA (triste) + Given que o SIGAA está indisponível + When eu tento realizar a importação + Then o sistema deve exibir a mensagem "Erro ao conectar com o SIGAA" diff --git a/features/step_definitions/.keep b/features/step_definitions/.keep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/features/support/env.rb b/features/support/env.rb new file mode 100644 index 0000000000..3b97d14087 --- /dev/null +++ b/features/support/env.rb @@ -0,0 +1,53 @@ +# IMPORTANT: This file is generated by cucumber-rails - edit at your own peril. +# It is recommended to regenerate this file in the future when you upgrade to a +# newer version of cucumber-rails. Consider adding your own code to a new file +# instead of editing this one. Cucumber will automatically load all features/**/*.rb +# files. + + +require 'cucumber/rails' + +# By default, any exception happening in your Rails application will bubble up +# to Cucumber so that your scenario will fail. This is a different from how +# your application behaves in the production environment, where an error page will +# be rendered instead. +# +# Sometimes we want to override this default behaviour and allow Rails to rescue +# exceptions and display an error page (just like when the app is running in production). +# Typical scenarios where you want to do this is when you test your error pages. +# There are two ways to allow Rails to rescue exceptions: +# +# 1) Tag your scenario (or feature) with @allow-rescue +# +# 2) Set the value below to true. Beware that doing this globally is not +# recommended as it will mask a lot of errors for you! +# +ActionController::Base.allow_rescue = false + +# Remove/comment out the lines below if your app doesn't have a database. +# For some databases (like MongoDB and CouchDB) you may need to use :truncation instead. +begin + DatabaseCleaner.strategy = :transaction +rescue NameError + raise "You need to add database_cleaner to your Gemfile (in the :test group) if you wish to use it." +end + +# You may also want to configure DatabaseCleaner to use different strategies for certain features and scenarios. +# See the DatabaseCleaner documentation for details. Example: +# +# Before('@no-txn,@selenium,@culerity,@celerity,@javascript') do +# # { except: [:widgets] } may not do what you expect here +# # as Cucumber::Rails::Database.javascript_strategy overrides +# # this setting. +# DatabaseCleaner.strategy = :truncation +# end +# +# Before('not @no-txn', 'not @selenium', 'not @culerity', 'not @celerity', 'not @javascript') do +# DatabaseCleaner.strategy = :transaction +# end +# + +# Possible values are :truncation and :transaction +# The :transaction strategy is faster, but might give you threading problems. +# See https://github.com/cucumber/cucumber-rails/blob/master/features/choose_javascript_database_strategy.feature +Cucumber::Rails::Database.javascript_strategy = :truncation diff --git a/lib/tasks/.keep b/lib/tasks/.keep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/lib/tasks/cucumber.rake b/lib/tasks/cucumber.rake new file mode 100644 index 0000000000..0caa4d2553 --- /dev/null +++ b/lib/tasks/cucumber.rake @@ -0,0 +1,69 @@ +# IMPORTANT: This file is generated by cucumber-rails - edit at your own peril. +# It is recommended to regenerate this file in the future when you upgrade to a +# newer version of cucumber-rails. Consider adding your own code to a new file +# instead of editing this one. Cucumber will automatically load all features/**/*.rb +# files. + + +unless ARGV.any? {|a| a =~ /^gems/} # Don't load anything when running the gems:* tasks + +vendored_cucumber_bin = Dir["#{Rails.root}/vendor/{gems,plugins}/cucumber*/bin/cucumber"].first +$LOAD_PATH.unshift(File.dirname(vendored_cucumber_bin) + '/../lib') unless vendored_cucumber_bin.nil? + +begin + require 'cucumber/rake/task' + + namespace :cucumber do + Cucumber::Rake::Task.new({ok: 'test:prepare'}, 'Run features that should pass') do |t| + t.binary = vendored_cucumber_bin # If nil, the gem's binary is used. + t.fork = true # You may get faster startup if you set this to false + t.profile = 'default' + end + + Cucumber::Rake::Task.new({wip: 'test:prepare'}, 'Run features that are being worked on') do |t| + t.binary = vendored_cucumber_bin + t.fork = true # You may get faster startup if you set this to false + t.profile = 'wip' + end + + Cucumber::Rake::Task.new({rerun: 'test:prepare'}, 'Record failing features and run only them if any exist') do |t| + t.binary = vendored_cucumber_bin + t.fork = true # You may get faster startup if you set this to false + t.profile = 'rerun' + end + + desc 'Run all features' + task all: [:ok, :wip] + + task :statsetup do + require 'rails/code_statistics' + ::STATS_DIRECTORIES << %w(Cucumber\ features features) if File.exist?('features') + ::CodeStatistics::TEST_TYPES << "Cucumber features" if File.exist?('features') + end + + end + + desc 'Alias for cucumber:ok' + task cucumber: 'cucumber:ok' + + task default: :cucumber + + task features: :cucumber do + STDERR.puts "*** The 'features' task is deprecated. See rake -T cucumber ***" + end + + # In case we don't have the generic Rails test:prepare hook, append a no-op task that we can depend upon. + task 'test:prepare' do + end + + task stats: 'cucumber:statsetup' + + +rescue LoadError + desc 'cucumber rake task not available (cucumber not installed)' + task :cucumber do + abort 'Cucumber rake task is not available. Be sure to install cucumber as a gem or plugin' + end +end + +end diff --git a/log/.keep b/log/.keep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/public/400.html b/public/400.html new file mode 100644 index 0000000000..282dbc8cc9 --- /dev/null +++ b/public/400.html @@ -0,0 +1,114 @@ + + + + + + + The server cannot process the request due to a client error (400 Bad Request) + + + + + + + + + + + + + +
+
+ +
+
+

The server cannot process the request due to a client error. Please check the request and try again. If you’re the application owner check the logs for more information.

+
+
+ + + + diff --git a/public/404.html b/public/404.html new file mode 100644 index 0000000000..c0670bc877 --- /dev/null +++ b/public/404.html @@ -0,0 +1,114 @@ + + + + + + + The page you were looking for doesn’t exist (404 Not found) + + + + + + + + + + + + + +
+
+ +
+
+

The page you were looking for doesn’t exist. You may have mistyped the address or the page may have moved. If you’re the application owner check the logs for more information.

+
+
+ + + + diff --git a/public/406-unsupported-browser.html b/public/406-unsupported-browser.html new file mode 100644 index 0000000000..9532a9ccd0 --- /dev/null +++ b/public/406-unsupported-browser.html @@ -0,0 +1,114 @@ + + + + + + + Your browser is not supported (406 Not Acceptable) + + + + + + + + + + + + + +
+
+ +
+
+

Your browser is not supported.
Please upgrade your browser to continue.

+
+
+ + + + diff --git a/public/422.html b/public/422.html new file mode 100644 index 0000000000..8bcf06014f --- /dev/null +++ b/public/422.html @@ -0,0 +1,114 @@ + + + + + + + The change you wanted was rejected (422 Unprocessable Entity) + + + + + + + + + + + + + +
+
+ +
+
+

The change you wanted was rejected. Maybe you tried to change something you didn’t have access to. If you’re the application owner check the logs for more information.

+
+
+ + + + diff --git a/public/500.html b/public/500.html new file mode 100644 index 0000000000..d77718c3a4 --- /dev/null +++ b/public/500.html @@ -0,0 +1,114 @@ + + + + + + + We’re sorry, but something went wrong (500 Internal Server Error) + + + + + + + + + + + + + +
+
+ +
+
+

We’re sorry, but something went wrong.
If you’re the application owner check the logs for more information.

+
+
+ + + + diff --git a/public/icon.png b/public/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..c4c9dbfbbd2f7c1421ffd5727188146213abbcef GIT binary patch literal 4166 zcmd6qU;WFw?|v@m)Sk^&NvB8tcujdV-r1b=i(NJxn&7{KTb zX$3(M+3TP2o^#KAo{#tIjl&t~(8D-k004kqPglzn0HFG(Q~(I*AKsD#M*g7!XK0T7 zN6P7j>HcT8rZgKl$v!xr806dyN19Bd4C0x_R*I-a?#zsTvb_89cyhuC&T**i|Rc zq5b8M;+{8KvoJ~uj9`u~d_f6`V&3+&ZX9x5pc8s)d175;@pjm(?dapmBcm0&vl9+W zx1ZD2o^nuyUHWj|^A8r>lUorO`wFF;>9XL-Jy!P}UXC{(z!FO%SH~8k`#|9;Q|eue zqWL0^Bp(fg_+Pkm!fDKRSY;+^@BF?AJE zCUWpXPst~hi_~u)SzYBDZroR+Z4xeHIlm_3Yc_9nZ(o_gg!jDgVa=E}Y8uDgem9`b zf=mfJ_@(BXSkW53B)F2s!&?_R4ptb1fYXlF++@vPhd=marQgEGRZS@B4g1Mu?euknL= z67P~tZ?*>-Hmi7GwlisNHHJDku-dSm7g@!=a}9cSL6Pa^w^2?&?$Oi8ibrr>w)xqx zOH_EMU@m05)9kuNR>>4@H%|){U$^yvVQ(YgOlh;5oU_-vivG-p4=LrN-k7D?*?u1u zsWly%tfAzKd6Fb=`eU2un_uaTXmcT#tlOL+aRS=kZZf}A7qT8lvcTx~7j` z*b>=z)mwg7%B2_!D0!1IZ?Nq{^Y$uI4Qx*6T!E2Col&2{k?ImCO=dD~A&9f9diXy^$x{6CwkBimn|1E09 zAMSezYtiL?O6hS37KpvDM?22&d{l)7h-!F)C-d3j8Z`c@($?mfd{R82)H>Qe`h{~G z!I}(2j(|49{LR?w4Jspl_i!(4T{31|dqCOpI52r5NhxYV+cDAu(xp*4iqZ2e-$YP= zoFOPmm|u*7C?S{Fp43y+V;>~@FFR76bCl@pTtyB93vNWy5yf;HKr8^0d7&GVIslYm zo3Tgt@M!`8B6IW&lK{Xk>%zp41G%`(DR&^u z5^pwD4>E6-w<8Kl2DzJ%a@~QDE$(e87lNhy?-Qgep!$b?5f7+&EM7$e>|WrX+=zCb z=!f5P>MxFyy;mIRxjc(H*}mceXw5a*IpC0PEYJ8Y3{JdoIW)@t97{wcUB@u+$FCCO z;s2Qe(d~oJC^`m$7DE-dsha`glrtu&v&93IZadvl_yjp!c89>zo;Krk+d&DEG4?x$ zufC1n+c1XD7dolX1q|7}uelR$`pT0Z)1jun<39$Sn2V5g&|(j~Z!wOddfYiZo7)A< z!dK`aBHOOk+-E_xbWCA3VR-+o$i5eO9`rMI#p_0xQ}rjEpGW;U!&&PKnivOcG(|m9 z!C8?WC6nCXw25WVa*eew)zQ=h45k8jSIPbq&?VE{oG%?4>9rwEeB4&qe#?-y_es4c|7ufw%+H5EY#oCgv!Lzv291#-oNlX~X+Jl5(riC~r z=0M|wMOP)Tt8@hNg&%V@Z9@J|Q#K*hE>sr6@oguas9&6^-=~$*2Gs%h#GF@h)i=Im z^iKk~ipWJg1VrvKS;_2lgs3n1zvNvxb27nGM=NXE!D4C!U`f*K2B@^^&ij9y}DTLB*FI zEnBL6y{jc?JqXWbkIZd7I16hA>(f9T!iwbIxJj~bKPfrO;>%*5nk&Lf?G@c2wvGrY&41$W{7HM9+b@&XY@>NZM5s|EK_Dp zQX60CBuantx>|d#DsaZ*8MW(we|#KTYZ=vNa#d*DJQe6hr~J6{_rI#?wi@s|&O}FR zG$kfPxheXh1?IZ{bDT-CWB4FTvO-k5scW^mi8?iY5Q`f8JcnnCxiy@m@D-%lO;y0pTLhh6i6l@x52j=#^$5_U^os}OFg zzdHbo(QI`%9#o*r8GCW~T3UdV`szO#~)^&X_(VW>o~umY9-ns9-V4lf~j z`QBD~pJ4a#b`*6bJ^3RS5y?RAgF7K5$ll97Y8#WZduZ`j?IEY~H(s^doZg>7-tk*t z4_QE1%%bb^p~4F5SB$t2i1>DBG1cIo;2(xTaj*Y~hlM{tSDHojL-QPg%Mo%6^7FrpB*{ z4G0@T{-77Por4DCMF zB_5Y~Phv%EQ64W8^GS6h?x6xh;w2{z3$rhC;m+;uD&pR74j+i22P5DS-tE8ABvH(U~indEbBUTAAAXfHZg5QpB@TgV9eI<)JrAkOI z8!TSOgfAJiWAXeM&vR4Glh;VxH}WG&V$bVb`a`g}GSpwggti*&)taV1@Ak|{WrV|5 zmNYx)Ans=S{c52qv@+jmGQ&vd6>6yX6IKq9O$3r&0xUTdZ!m1!irzn`SY+F23Rl6# zFRxws&gV-kM1NX(3(gnKpGi0Q)Dxi~#?nyzOR9!en;Ij>YJZVFAL*=R%7y%Mz9hU% zs>+ZB?qRmZ)nISx7wxY)y#cd$iaC~{k0avD>BjyF1q^mNQ1QcwsxiTySe<6C&cC6P zE`vwO9^k-d`9hZ!+r@Jnr+MF*2;2l8WjZ}DrwDUHzSF{WoG zucbSWguA!3KgB3MU%HH`R;XqVv0CcaGq?+;v_A5A2kpmk5V%qZE3yzQ7R5XWhq=eR zyUezH=@V)y>L9T-M-?tW(PQYTRBKZSVb_!$^H-Pn%ea;!vS_?M<~Tm>_rWIW43sPW z=!lY&fWc1g7+r?R)0p8(%zp&vl+FK4HRkns%BW+Up&wK8!lQ2~bja|9bD12WrKn#M zK)Yl9*8$SI7MAwSK$%)dMd>o+1UD<2&aQMhyjS5R{-vV+M;Q4bzl~Z~=4HFj_#2V9 zB)Gfzx3ncy@uzx?yzi}6>d%-?WE}h7v*w)Jr_gBl!2P&F3DX>j_1#--yjpL%<;JMR z*b70Gr)MMIBWDo~#<5F^Q0$VKI;SBIRneuR7)yVsN~A9I@gZTXe)E?iVII+X5h0~H zx^c(fP&4>!*q>fb6dAOC?MI>Cz3kld#J*;uik+Ps49cwm1B4 zZc1|ZxYyTv;{Z!?qS=D)sgRKx^1AYf%;y_V&VgZglfU>d+Ufk5&LV$sKv}Hoj+s; xK3FZRYdhbXT_@RW*ff3@`D1#ps#~H)p+y&j#(J|vk^lW{fF9OJt5(B-_&*Xgn9~3N literal 0 HcmV?d00001 diff --git a/public/icon.svg b/public/icon.svg new file mode 100644 index 0000000000..04b34bf83f --- /dev/null +++ b/public/icon.svg @@ -0,0 +1,3 @@ + + + diff --git a/public/robots.txt b/public/robots.txt new file mode 100644 index 0000000000..c19f78ab68 --- /dev/null +++ b/public/robots.txt @@ -0,0 +1 @@ +# See https://www.robotstxt.org/robotstxt.html for documentation on how to use the robots.txt file diff --git a/script/.keep b/script/.keep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/storage/.keep b/storage/.keep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/test/application_system_test_case.rb b/test/application_system_test_case.rb new file mode 100644 index 0000000000..cee29fd214 --- /dev/null +++ b/test/application_system_test_case.rb @@ -0,0 +1,5 @@ +require "test_helper" + +class ApplicationSystemTestCase < ActionDispatch::SystemTestCase + driven_by :selenium, using: :headless_chrome, screen_size: [ 1400, 1400 ] +end diff --git a/test/controllers/.keep b/test/controllers/.keep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/test/fixtures/files/.keep b/test/fixtures/files/.keep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/test/helpers/.keep b/test/helpers/.keep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/test/integration/.keep b/test/integration/.keep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/test/mailers/.keep b/test/mailers/.keep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/test/models/.keep b/test/models/.keep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/test/system/.keep b/test/system/.keep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/test/test_helper.rb b/test/test_helper.rb new file mode 100644 index 0000000000..0c22470ec1 --- /dev/null +++ b/test/test_helper.rb @@ -0,0 +1,15 @@ +ENV["RAILS_ENV"] ||= "test" +require_relative "../config/environment" +require "rails/test_help" + +module ActiveSupport + class TestCase + # Run tests in parallel with specified workers + parallelize(workers: :number_of_processors) + + # Setup all fixtures in test/fixtures/*.yml for all tests in alphabetical order. + fixtures :all + + # Add more helper methods to be used by all tests here... + end +end diff --git a/tmp/.keep b/tmp/.keep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tmp/pids/.keep b/tmp/pids/.keep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tmp/storage/.keep b/tmp/storage/.keep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/vendor/.keep b/vendor/.keep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/vendor/javascript/.keep b/vendor/javascript/.keep new file mode 100644 index 0000000000..e69de29bb2 From 66d2d9e998c4575de7c1fd5bac4be9f5e479739b Mon Sep 17 00:00:00 2001 From: Maria Carolina Date: Mon, 17 Nov 2025 14:27:49 -0300 Subject: [PATCH 03/16] feat: adicao do BDD da issue Edicao e Delecao de Templates --- features/edicao_e_delecao_templates.feature | 38 +++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 features/edicao_e_delecao_templates.feature diff --git a/features/edicao_e_delecao_templates.feature b/features/edicao_e_delecao_templates.feature new file mode 100644 index 0000000000..2aee533b68 --- /dev/null +++ b/features/edicao_e_delecao_templates.feature @@ -0,0 +1,38 @@ +Feature: Edição e deleção de templates + Como Administrador + Quero editar e/ou deletar um template que eu criei sem afetar os formulários já criados + A fim de organizar os templates existentes + + Background: + Given que estou autenticado como administrador + And existe um template criado previamente + + Scenario: Editar o nome de um template com sucesso (feliz) + When eu edito o template alterando seu nome para "Template Atualizado" + Then o template deve ser salvo com o novo nome + And os formulários já criados anteriormente não devem ser modificados + And eu devo ver a mensagem "Template atualizado com sucesso" + + Scenario: Editar as perguntas de um template com sucesso (feliz) + When eu edito o template alterando suas perguntas + Then o template deve ser salvo com as novas perguntas + And os formulários já criados anteriormente não devem ser modificados + And eu devo ver a mensagem "Template atualizado com sucesso" + + Scenario: Deletar um template com sucesso (feliz) + When eu deleto o template + Then o template deve ser removido do sistema + And os formulários já criados anteriormente devem permanecer intactos + And eu devo ver a mensagem "Template excluído com sucesso" + + Scenario: Tentar editar um template que está em uso por um formulário ativo (triste) + Given que o template está vinculado a um formulário ativo + When eu tento editar o template + Then a alteração deve ser bloqueada + And eu devo ver a mensagem "Não é possível editar um template em uso" + + Scenario: Tentar deletar um template que está em uso por um formulário ativo (triste) + Given que o template está vinculado a um formulário ativo + When eu tento deletar o template + Then a remoção deve ser bloqueada + And eu devo ver a mensagem "Não é possível remover um template em uso" From e865c124d734a6a9efc4d9c8d4b8345972c0465d Mon Sep 17 00:00:00 2001 From: Maria Carolina Date: Mon, 17 Nov 2025 14:47:13 -0300 Subject: [PATCH 04/16] feat: adicao do BDD da issue Atualizacao de Dados no SIGAA --- features/atualizar_dados_sigaa.feature | 43 ++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 features/atualizar_dados_sigaa.feature diff --git a/features/atualizar_dados_sigaa.feature b/features/atualizar_dados_sigaa.feature new file mode 100644 index 0000000000..1eb2d4d4bc --- /dev/null +++ b/features/atualizar_dados_sigaa.feature @@ -0,0 +1,43 @@ +Feature: Atualização de Dados do SIGAA + Como Administrador + Quero atualizar a base de dados já existente com os dados atuais do SIGAA + A fim de corrigir a base de dados do sistema + + Background: + Given que estou autenticado como administrador + + Scenario: Atualização bem-sucedida (dados novos e modificados) (feliz) + Given que a base local possui a "Turma A" com o aluno "João Silva" + And o SIGAA possui a "Turma A" com o nome do aluno atualizado para "João Silva Santos" + And o SIGAA também possui o novo aluno "Maria Costa" na "Turma A" + When eu realizo a atualização de dados + Then o nome do aluno na base local deve ser atualizado para "João Silva Santos" + And a aluna "Maria Costa" deve ser adicionada à "Turma A" na base local + And eu devo ver a mensagem "Atualização concluída com sucesso" + + Scenario: Correção de dados (remoção de dados antigos) (feliz) + Given que a base local possui o aluno "Carlos Souza" na "Turma B" + And o aluno "Carlos Souza" não está mais listado na "Turma B" no SIGAA + When eu realizo a atualização de dados + Then o aluno "Carlos Souza" deve ser removido da "Turma B" na base local + And eu devo ver a mensagem "Atualização concluída com sucesso" + + Scenario: Dados já estão atualizados (triste) + Given que os dados da base local já estão idênticos aos dados do SIGAA + When eu realizo a atualização de dados + Then o sistema não deve realizar nenhuma alteração + And eu devo ver a mensagem "A base de dados já está atualizada" + + Scenario: Erro de conexão com o SIGAA (triste) + Given que o SIGAA está indisponível + When eu tento realizar a atualização + Then o sistema deve exibir a mensagem "Erro ao conectar com o SIGAA" + And nenhuma alteração deve ser feita na base local + + Scenario: Fonte de dados não encontrada no SIGAA (triste) + Given que a base local está configurada para atualizar a "Turma de Engenharia 2020" + And a "Turma de Engenharia 2020" foi permanentemente excluída do SIGAA + When eu realizo a atualização de dados + Then o sistema deve falhar ao buscar os dados + And eu devo ver a mensagem "Erro: A 'Turma de Engenharia 2020' não foi encontrada no SIGAA. A atualização foi cancelada." + And nenhuma alteração deve ser feita na base local \ No newline at end of file From dc175af7c2f57c4a7bf96559f2fed70ea20965eb Mon Sep 17 00:00:00 2001 From: Bernardo Date: Mon, 17 Nov 2025 19:33:46 -0300 Subject: [PATCH 05/16] =?UTF-8?q?Issues=20implementadas:=20Definir=20senha?= =?UTF-8?q?=20ao=20cadastrar,=20exportar=20relat=C3=B3rios=20do=20administ?= =?UTF-8?q?rador,=20gerenciamento=20de=20departamento=20e=20redefinir=20se?= =?UTF-8?q?nha?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- features/definir_senha_cadastro.feature | 40 +++++++++++++++++++ features/exportar_relatorios_csv.feature | 34 ++++++++++++++++ .../gerenciar_turmas_departamento.feature | 32 +++++++++++++++ features/redefinir_senha.feature | 38 ++++++++++++++++++ 4 files changed, 144 insertions(+) create mode 100644 features/definir_senha_cadastro.feature create mode 100644 features/exportar_relatorios_csv.feature create mode 100644 features/gerenciar_turmas_departamento.feature create mode 100644 features/redefinir_senha.feature diff --git a/features/definir_senha_cadastro.feature b/features/definir_senha_cadastro.feature new file mode 100644 index 0000000000..153affd8fd --- /dev/null +++ b/features/definir_senha_cadastro.feature @@ -0,0 +1,40 @@ +Feature: Definir senha após cadastro + Como Usuário + Quero definir uma senha para o meu usuário a partir do email do sistema de solicitação de cadastro + A fim de acessar o sistema + + Background: + Given que recebi um email de convite para cadastro + And o email contém um link de ativação + + Scenario: Definir senha com sucesso (feliz) + Given que clico no link de ativação do email + When eu sou redirecionado para a página de definição de senha + And eu preencho uma senha segura + And eu confirmo a senha + And eu clico em "Definir senha" + Then a minha senha deve ser criada + And eu devo receber a mensagem "Senha definida com sucesso" + And eu devo ser redirecionado para login + + Scenario: Senhas não conferem (triste) + Given que estou na página de definição de senha + When eu preencho a senha "Senha123!" + And eu confirmo com uma senha diferente "Senha456!" + And eu clico em "Definir senha" + Then o sistema deve exibir a mensagem "As senhas não conferem" + And a senha não deve ser criada + + Scenario: Senha muito fraca (triste) + Given que estou na página de definição de senha + When eu preencho uma senha fraca "123" + And eu confirmo a mesma senha + And eu clico em "Definir senha" + Then o sistema deve exibir a mensagem "Senha fraca. Use letras, números e caracteres especiais" + And a senha não deve ser criada + + Scenario: Link de ativação expirado (triste) + Given que o link de ativação expirou + When eu clico no link + Then o sistema deve exibir a mensagem "Link de ativação expirado" + And eu devo ser orientado a solicitar um novo link \ No newline at end of file diff --git a/features/exportar_relatorios_csv.feature b/features/exportar_relatorios_csv.feature new file mode 100644 index 0000000000..ef7f22c047 --- /dev/null +++ b/features/exportar_relatorios_csv.feature @@ -0,0 +1,34 @@ +Feature: Baixar resultados de formulário em CSV + Como Administrador + Quero baixar um arquivo CSV contendo os resultados de um formulário + A fim de avaliar o desempenho das turmas + + Background: + Given que estou autenticado como administrador + And que existe um formulário com respostas + + Scenario: Exportar resultados com sucesso (feliz) + Given que um formulário tem respostas de participantes + When eu clico em "Exportar para CSV" + Then um arquivo CSV deve ser gerado + And o arquivo deve conter todas as respostas + And o arquivo deve estar pronto para download + + Scenario: Arquivo CSV com estrutura correta (feliz) + Given que vou exportar resultados de um formulário + When eu clico em "Exportar para CSV" + Then o arquivo deve ter colunas com: ID da resposta, Participante, Data de resposta, Respostas + And cada linha deve representar uma resposta individual + And caracteres especiais devem estar codificados corretamente + + Scenario: Exportar formulário sem respostas (triste) + Given que um formulário não possui respostas + When eu tento exportar para CSV + Then o sistema deve exibir a mensagem "Não há dados para exportar" + And nenhum arquivo deve ser criado + + Scenario: Exportar apenas respostas de uma turma específica (feliz) + Given que um formulário foi respondido por múltiplas turmas + When eu seleciono uma turma específica + And eu clico em "Exportar para CSV" + Then o arquivo deve conter apenas as respostas da turma selecionada \ No newline at end of file diff --git a/features/gerenciar_turmas_departamento.feature b/features/gerenciar_turmas_departamento.feature new file mode 100644 index 0000000000..25e9ee59a6 --- /dev/null +++ b/features/gerenciar_turmas_departamento.feature @@ -0,0 +1,32 @@ +Feature: Gerenciar turmas apenas do departamento + Como Administrador + Quero gerenciar somente as turmas do departamento o qual eu pertenço + A fim de avaliar o desempenho das turmas no semestre atual + + Background: + Given que estou autenticado como administrador + And que pertenço ao departamento "Engenharia de Computação" + + Scenario: Visualizar apenas turmas do departamento (feliz) + Given que existem turmas de diferentes departamentos + When eu acesso a listagem de turmas + Then eu devo ver apenas as turmas do "Departamento de Engenharia de Computação" + And eu não devo ver turmas de outros departamentos + + Scenario: Criar formulário apenas para turmas do departamento (feliz) + Given que estou criando um formulário + When eu seleciono um template + Then a listagem de turmas deve mostrar apenas turmas do meu departamento + And eu não devo ter a opção de selecionar turmas de outros departamentos + + Scenario: Administrador de outro departamento vê apenas suas turmas (feliz) + Given que um outro administrador pertence ao "Departamento de Engenharia Mecânica" + When ele acessa o sistema + Then ele deve ver apenas turmas do "Departamento de Engenharia Mecânica" + And não deve ver minhas turmas + + Scenario: Impossível atualizar turma de outro departamento (triste) + Given que estou autenticado como administrador + When eu tento acessar dados de uma turma de outro departamento + Then o sistema deve retornar erro 403 (Acesso Negado) + And a operação não deve ser permitida \ No newline at end of file diff --git a/features/redefinir_senha.feature b/features/redefinir_senha.feature new file mode 100644 index 0000000000..36e0803578 --- /dev/null +++ b/features/redefinir_senha.feature @@ -0,0 +1,38 @@ +Feature: Redefinir senha + Como Usuário + Quero redefinir uma senha para o meu usuário a partir do email recebido após a solicitação da troca de senha + A fim de recuperar o meu acesso ao sistema + + Background: + Given que estou na página de login + + Scenario: Solicitar redefinição de senha com sucesso (feliz) + Given que clico em "Esqueci minha senha" + When eu preencho meu email "usuario@example.com" + And eu clico em "Enviar link de recuperação" + Then um email deve ser enviado para "usuario@example.com" + And o email deve conter um link de redefinição + And eu devo ver a mensagem "Email de recuperação enviado" + + Scenario: Redefinir senha com novo link (feliz) + Given que recebi um email de recuperação de senha + And eu clico no link de recuperação + When eu sou redirecionado para a página de redefinição + And eu preencho a nova senha + And eu confirmo a nova senha + And eu clico em "Atualizar senha" + Then a minha senha deve ser atualizada + And eu devo receber a mensagem "Senha atualizada com sucesso" + + Scenario: Link de recuperação expirado (triste) + Given que o link de recuperação expirou + When eu clico no link + Then o sistema deve exibir a mensagem "Link expirado" + And eu devo ser orientado a solicitar um novo link + + Scenario: Usuário não encontrado (triste) + Given que estou na página de recuperação + When eu preencho um email inexistente "naoexisto@example.com" + And eu clico em "Enviar link de recuperação" + Then o sistema deve exibir a mensagem "Email não encontrado" + And nenhum email deve ser enviado \ No newline at end of file From 226e776c578cf12c095bd02012dc0cdc221ae242 Mon Sep 17 00:00:00 2001 From: bg! <99600828+bg1777@users.noreply.github.com> Date: Mon, 17 Nov 2025 20:02:20 -0300 Subject: [PATCH 06/16] Estrutura inicial do Markdown --- README.md | 664 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 658 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 12fe37f3d4..7df6655edb 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,659 @@ -# CAMAAR -Sistema para avaliação de atividades acadêmicas remotas do CIC +# Wiki CAMAAR - Plataforma de Avaliação de Cursos -Integrantes Grupo 10: -- Bernardo Gomes Rodrigues (231034190) -- Isaac Silva (231025216) -- Maria Carolina Burgum Abreu Jorge (231013547) \ No newline at end of file +--- + +## Informações do Projeto + +| Item | Descrição | +|------|-----------| +| **Nome do Projeto** | CAMAAR - Plataforma de Avaliação de Cursos | +| **Disciplina** | Engenharia de Software | +| **Período** | 2025.2 | +| **Integrantes do Grupo** | Bernardo Gomes Rodrigues - 231034190
[Nome 2 - Matrícula 2]
[Nome 3 - Matrícula 3]
[Nome 4 - Matrícula 4] | + +--- + +## Papéis Scrum + +| Papel | Responsável | Matrícula | +|-------|-------------|-----------| +| **Scrum Master** | Bernardo Gomes Rodrigues | 231034190 | +| **Product Owner** | [Nome do Product Owner] | [Matrícula] | + +--- + +## Escopo do Projeto + +### Descrição Geral + +O CAMAAR é uma **plataforma web para avaliação de cursos e disciplinas** integrada com o SIGAA (Sistema Integrado de Gestão de Atividades Acadêmicas) por meio de arquivos JSON. O sistema permite que administradores (coordenadores de cursos) criem formulários de avaliação que são respondidos por alunos e professores, gerando relatórios sobre o desempenho das disciplinas e infraestrutura. + +### Objetivos Principais + +- Automatizar o processo de coleta de feedback sobre disciplinas +- Integrar dados do SIGAA para alimentar a plataforma +- Permitir análise de dados através de exportação em CSV +- Fornecer controle de acesso baseado em departamento +- Facilitar a gestão de templates reutilizáveis de formulários + +### Stakeholders + +- **Coordenadores de Curso** (Administradores): Criam e gerenciam formulários +- **Professores**: Respondem questionários sobre infraestrutura e ementa +- **Alunos**: Avaliam disciplinas e professores +- **Sistema SIGAA**: Fornecedor de dados de turmas, disciplinas e participantes + +--- + +## Funcionalidades e Regras de Negócio + +### 1. Autenticação de Usuários (5 pontos) + +**Funcionalidades:** +- Login com email ou matrícula + senha +- Definir senha após convite de cadastro +- Recuperar acesso através de email (redefinir senha) + +**Regras de Negócio:** +- Senhas devem ter no mínimo 8 caracteres +- Senhas devem conter pelo menos: 1 letra maiúscula, 1 letra minúscula, 1 número e 1 caractere especial +- Link de ativação de conta válido por 48 horas +- Link de redefinição de senha válido por 24 horas +- Máximo de 5 tentativas de login falhadas antes de bloquear por 15 minutos +- Email de boas-vindas enviado automaticamente após criação de usuário +- Usuário deve alterar senha temporária no primeiro acesso + +**Responsável:** [Nome do desenvolvedor] + +--- + +### 2. Importação de Dados do SIGAA (8 pontos) + +**Funcionalidades:** +- Importar turmas, disciplinas e participantes do SIGAA +- Atualizar dados existentes com informações atualizadas +- Manter histórico de importações +- Marcar turmas como inativas quando descontinuadas + +**Regras de Negócio:** +- Importação deve ser realizada apenas por administradores +- Registros duplicados são ignorados (validação por ID único do SIGAA) +- Ao importar novos usuários, criar contas com senha temporária +- Dados importados não devem sobrescrever informações customizadas no sistema +- Cada importação deve ser registrada com: data, hora, usuário responsável, quantidade de registros processados +- Participantes removidos do SIGAA devem ter acesso desativado +- Atualização de mudanças de turmas de alunos/professores +- Máximo 1 importação simultânea (evitar condições de corrida) + +**Responsável:** [Nome do desenvolvedor] + +--- + +### 3. Gerenciamento de Templates de Formulários (5 pontos) + +**Funcionalidades:** +- Criar templates com múltiplos tipos de questões +- Visualizar templates criados +- Editar templates sem afetar formulários já criados +- Deletar templates sem afetar formulários existentes + +**Regras de Negócio:** +- Template deve ter no mínimo 1 questão +- Nome do template deve ser único por administrador +- Apenas o criador do template pode editá-lo (ou outro admin do mesmo departamento) +- Tipos de questões suportados: Múltipla escolha, Escala Likert, Texto aberto, Verdadeiro/Falso +- Edições em template afetam apenas novos formulários criados, não retroativamente +- Template deletado não afeta formulários já criados baseados nele +- Histórico de versões do template é mantido +- Administrador só pode gerenciar templates do seu departamento + +**Responsável:** [Nome do desenvolvedor] + +--- + +### 4. Criação de Formulários (8 pontos) + +**Funcionalidades:** +- Criar formulário baseado em template +- Selecionar turmas para aplicar o formulário +- Escolher tipo de avaliador (docentes ou discentes) +- Definir data de abertura e fechamento +- Visualizar formulários criados + +**Regras de Negócio:** +- Formulário herda todas as questões do template no momento da criação +- Deve selecionar no mínimo 1 turma +- Deve escolher tipo de avaliador (obrigatório) +- Data de fechamento deve ser posterior à data de abertura +- Formulário não pode ser editado após criação (apenas deletado e recriado) +- Apenas turmas do departamento do administrador podem ser selecionadas +- Formulário ativo quando data atual está entre abertura e fechamento +- Mesmo formulário não pode ser respondido 2 vezes pelo mesmo participante +- Notificação automática enviada aos participantes quando formulário é criado + +**Responsável:** [Nome do desenvolvedor] + +--- + +### 5. Resposta de Questionários (5 pontos) + +**Funcionalidades:** +- Visualizar formulários não respondidos +- Responder questionário +- Salvar progresso como rascunho +- Submeter respostas + +**Regras de Negócio:** +- Participante visualiza apenas formulários de turmas onde está matriculado +- Formulário deve estar dentro do período de abertura/fechamento para responder +- Todos os campos obrigatórios devem ser preenchidos antes de enviar +- Rascunho é salvo automaticamente a cada 30 segundos +- Participante pode editar respostas enquanto rascunho não foi enviado +- Uma vez enviado, não pode ser alterado +- Resposta não pode ser submetida duas vezes pelo mesmo participante +- Sistema valida tipo de resposta conforme tipo de questão + +**Responsável:** [Nome do desenvolvedor] + +--- + +### 6. Exportação de Resultados (5 pontos) + +**Funcionalidades:** +- Exportar respostas em formato CSV +- Filtrar por turma específica +- Download do arquivo + +**Regras de Negócio:** +- Apenas administrador pode exportar resultados +- Arquivo CSV deve conter: ID da resposta, Participante, Data de resposta, Respostas individuais +- Formato CSV deve ser compatível com Excel e planilhas +- Caracteres especiais devem estar codificados corretamente (UTF-8) +- Arquivo só pode ser gerado se houver respostas +- Apenas respostas de formulários do departamento do admin são exportadas +- Nomes de participantes anonimizados por padrão (apenas matrícula mostrada) +- Arquivo gerado com timestamp: `formulario_[id]_[data_hora].csv` + +**Responsável:** [Nome do desenvolvedor] + +--- + +### 7. Controle de Acesso por Departamento (5 pontos) + +**Funcionalidades:** +- Visualizar apenas turmas do departamento +- Criar formulários apenas para turmas do departamento +- Gerenciar templates apenas do departamento +- Controle de permissão em operações + +**Regras de Negócio:** +- Administrador só vê/gerencia turmas do seu departamento +- Administrador não pode criar formulário para turma de outro departamento +- Erro 403 (Acesso Negado) deve ser retornado para tentativas não autorizadas +- Super Admin pode gerenciar múltiplos departamentos (se aplicável) +- Departamento é definido no perfil do usuário durante importação do SIGAA +- Logs de tentativas de acesso não autorizado devem ser registrados + +**Responsável:** [Nome do desenvolvedor] + +--- + +### 8. Diferenciação de Avaliadores (3 pontos) + +**Funcionalidades:** +- Escolher tipo de avaliador (docentes ou discentes) +- Exibir formulário apenas para o tipo correto + +**Regras de Negócio:** +- Ao criar formulário, obrigatório selecionar tipo: "Docentes" ou "Discentes" +- Aluno só vê formulários criados para "Discentes" +- Professor só vê formulários criados para "Docentes" +- Sistema valida tipo de usuário ao tentar acessar formulário +- Formulário para docente é enviado apenas para professores das turmas +- Formulário para discente é enviado apenas para alunos das turmas +- Mesmo formulário com dois tipos diferentes pode coexistir para mesma turma + +**Responsável:** [Nome do desenvolvedor] + +--- + +### 9. Gestão de Usuários e Participantes (3 pontos) + +**Funcionalidades:** +- Cadastro automático de participantes na importação +- Desativação de participantes inativos +- Visualização de histórico de usuários + +**Regras de Negócio:** +- Usuários são criados automaticamente durante importação do SIGAA +- Usuário inativo não pode fazer login +- Quando participante é removido do SIGAA, status muda para inativo +- Email de boas-vindas é enviado automaticamente +- Senha temporária é gerada e enviada por email +- Usuário pode ter múltiplos papéis (aluno em uma turma, professor em outra, admin de disciplina) +- Histórico de mudanças de status é mantido + +**Responsável:** [Nome do desenvolvedor] + +--- + +## Atribuição de Histórias de Usuário + +| # | História de Usuário | Funcionalidade | Pontos | Responsável | +|---|---------------------|-----------------|--------|-------------| +| 1 | Importar dados do SIGAA | Importação de Dados | 8 | [Nome] | +| 2 | Responder questionário sobre turma | Resposta de Questionários | 5 | [Nome] | +| 3 | Cadastrar participantes ao importar | Gestão de Usuários | 3 | [Nome] | +| 4 | Baixar resultados em CSV | Exportação de Resultados | 5 | [Nome] | +| 5 | Criar template de formulário | Gerenciamento de Templates | 5 | [Nome] | +| 6 | Criar formulário baseado em template | Criação de Formulários | 8 | [Nome] | +| 7 | Acessar sistema com credenciais | Autenticação | 3 | [Nome] | +| 8 | Definir senha após cadastro | Autenticação | 2 | [Nome] | +| 9 | Gerenciar turmas do departamento | Controle de Acesso | 5 | [Nome] | +| 10 | Redefinir senha | Autenticação | 3 | [Nome] | +| 11 | Atualizar base de dados existente | Importação de Dados | 5 | [Nome] | +| 12 | Visualizar formulários não respondidos | Resposta de Questionários | 3 | [Nome] | +| 13 | Visualizar formulários criados | Criação de Formulários | 3 | [Nome] | +| 14 | Visualizar templates criados | Gerenciamento de Templates | 2 | [Nome] | +| 15 | Editar e deletar template | Gerenciamento de Templates | 3 | [Nome] | +| 16 | Escolher tipo de avaliador | Diferenciação de Avaliadores | 3 | [Nome] | + +**Total de Pontos: 62 pontos** + +--- + +## Histórias de Usuário Detalhadas com Pontuação + +### HU-01: Importar dados do SIGAA (8 pontos) + +``` +Como Administrador +Quero importar dados de turmas, matérias e participantes do SIGAA +A fim de alimentar a base de dados do sistema + +Critérios de Aceitação: +- Sistema importa com sucesso turmas, disciplinas e participantes do SIGAA +- Dados duplicados são ignorados e registrados em relatório +- Novos usuários recebem email de boas-vindas +- Histórico de importação é salvo com timestamp +- Erro de conexão é tratado graciosamente +- Máximo 1 importação simultânea +``` + +**Pontos:** 8 | **Responsável:** [Nome] + +--- + +### HU-02: Responder questionário sobre turma (5 pontos) + +``` +Como Participante de uma turma +Quero responder o questionário sobre a turma em que estou matriculado +A fim de submeter minha avaliação da turma + +Critérios de Aceitação: +- Visualiza questionário da turma +- Preenche questões obrigatórias +- Salva como rascunho (auto-save a cada 30s) +- Submete respostas finais +- Não pode responder 2 vezes o mesmo formulário +``` + +**Pontos:** 5 | **Responsável:** [Nome] + +--- + +### HU-03: Cadastrar participantes ao importar (3 pontos) + +``` +Como Administrador +Quero cadastrar participantes de turmas do SIGAA ao importar dados de usuários novos +A fim de que eles acessem o sistema CAMAAR + +Critérios de Aceitação: +- Novos usuários são criados automaticamente +- Cada usuário recebe email de boas-vindas +- Senha temporária é gerada +- Usuário deve alterar senha no primeiro acesso +- Usuários já existentes são associados às novas turmas +``` + +**Pontos:** 3 | **Responsável:** [Nome] + +--- + +### HU-04: Baixar resultados em CSV (5 pontos) + +``` +Como Administrador +Quero baixar um arquivo CSV contendo os resultados de um formulário +A fim de avaliar o desempenho das turmas + +Critérios de Aceitação: +- Arquivo CSV é gerado com estrutura correta +- Colunas: ID, Participante, Data, Respostas +- Caracteres especiais codificados (UTF-8) +- Filtro por turma específica +- Anonimização de nomes (apenas matrícula) +``` + +**Pontos:** 5 | **Responsável:** [Nome] + +--- + +### HU-05: Criar template de formulário (5 pontos) + +``` +Como Administrador +Quero criar um template de formulário contendo as questões +A fim de gerar formulários de avaliações reutilizáveis + +Critérios de Aceitação: +- Template com nome único +- Mínimo 1 questão obrigatória +- Suporta múltiplos tipos: múltipla escolha, Likert, texto, V/F +- Apenas criador pode editar +- Edições não afetam formulários já criados +``` + +**Pontos:** 5 | **Responsável:** [Nome] + +--- + +### HU-06: Criar formulário baseado em template (8 pontos) + +``` +Como Administrador +Quero criar um formulário baseado em um template para turmas escolhidas +A fim de avaliar o desempenho das turmas no semestre atual + +Critérios de Aceitação: +- Seleciona template +- Escolhe múltiplas turmas (mínimo 1) +- Define datas de abertura/fechamento +- Escolhe tipo de avaliador (docentes/discentes) +- Formulário herda questões do template +- Notificação enviada aos participantes +``` + +**Pontos:** 8 | **Responsável:** [Nome] + +--- + +### HU-07: Acessar sistema com credenciais (3 pontos) + +``` +Como Usuário do sistema +Quero acessar o sistema utilizando email ou matrícula e senha +A fim de responder formulários ou gerenciar o sistema + +Critérios de Aceitação: +- Login com email funciona +- Login com matrícula funciona +- Validação de credenciais +- Redirecionamento para painel +- Bloqueio após 5 tentativas falhadas por 15 minutos +``` + +**Pontos:** 3 | **Responsável:** [Nome] + +--- + +### HU-08: Definir senha após cadastro (2 pontos) + +``` +Como Usuário +Quero definir uma senha para o meu usuário a partir do email de cadastro +A fim de acessar o sistema + +Critérios de Aceitação: +- Link de ativação válido por 48 horas +- Senha deve cumprir critérios de segurança +- Senhas devem conferir +- Redirecionamento para login após sucesso +``` + +**Pontos:** 2 | **Responsável:** [Nome] + +--- + +### HU-09: Gerenciar turmas do departamento (5 pontos) + +``` +Como Administrador +Quero gerenciar somente as turmas do departamento o qual eu pertenço +A fim de avaliar o desempenho das turmas no semestre atual + +Critérios de Aceitação: +- Visualiza apenas turmas do departamento +- Criar formulário apenas com turmas do departamento +- Erro 403 para tentativas de acesso não autorizado +- Logs de tentativas não autorizadas +``` + +**Pontos:** 5 | **Responsável:** [Nome] + +--- + +### HU-10: Redefinir senha (3 pontos) + +``` +Como Usuário +Quero redefinir uma senha a partir do email recebido +A fim de recuperar meu acesso ao sistema + +Critérios de Aceitação: +- Link de recuperação válido por 24 horas +- Validação de senha +- Email de confirmação enviado +- Redirecionamento para login +``` + +**Pontos:** 3 | **Responsável:** [Nome] + +--- + +### HU-11: Atualizar base de dados existente (5 pontos) + +``` +Como Administrador +Quero atualizar a base de dados com dados atuais do SIGAA +A fim de corrigir a base de dados do sistema + +Critérios de Aceitação: +- Sincroniza dados existentes +- Adiciona novos dados +- Marca turmas como inativas +- Atualiza mudanças de turmas +- Mantém histórico de atualizações +``` + +**Pontos:** 5 | **Responsável:** [Nome] + +--- + +### HU-12: Visualizar formulários não respondidos (3 pontos) + +``` +Como Participante de uma turma +Quero visualizar os formulários não respondidos das turmas em que estou matriculado +A fim de poder escolher qual irei responder + +Critérios de Aceitação: +- Lista apenas formulários não respondidos +- Mostra turma, disciplina, datas +- Filtra por turma +- Formulários respondidos não aparecem +``` + +**Pontos:** 3 | **Responsável:** [Nome] + +--- + +### HU-13: Visualizar formulários criados (3 pontos) + +``` +Como Administrador +Quero visualizar os formulários criados +A fim de poder gerar um relatório a partir das respostas + +Critérios de Aceitação: +- Lista todos os formulários +- Mostra nome, template, turmas, status, data +- Quantidade de respostas exibida +- Acesso apenas a formulários do departamento +- Opção de visualizar detalhes +``` + +**Pontos:** 3 | **Responsável:** [Nome] + +--- + +### HU-14: Visualizar templates criados (2 pontos) + +``` +Como Administrador +Quero visualizar os templates criados +A fim de poder editar e/ou deletar um template que eu criei + +Critérios de Aceitação: +- Lista todos os templates +- Mostra nome, quantidade de questões, data +- Acesso aos detalhes +- Opções de editar/deletar +``` + +**Pontos:** 2 | **Responsável:** [Nome] + +--- + +### HU-15: Editar e deletar template (3 pontos) + +``` +Como Administrador +Quero editar e/ou deletar um template que eu criei sem afetar formulários já criados +A fim de organizar os templates existentes + +Critérios de Aceitação: +- Editar template não afeta formulários existentes +- Deletar template não deleta formulários +- Confirmação de exclusão +- Apenas criador pode editar +- Histórico de versões mantido +``` + +**Pontos:** 3 | **Responsável:** [Nome] + +--- + +### HU-16: Escolher tipo de avaliador (3 pontos) + +``` +Como Administrador +Quero escolher criar um formulário para os docentes ou os discentes de uma turma +A fim de avaliar o desempenho de uma matéria + +Critérios de Aceitação: +- Opção obrigatória: Docentes ou Discentes +- Professores veem apenas formulários para Docentes +- Alunos veem apenas formulários para Discentes +- Múltiplos formulários podem coexistir para mesma turma +- Notificação apenas para tipo correto +``` + +**Pontos:** 3 | **Responsável:** [Nome] + +--- + +## Política de Branching + +### Estratégia Git Flow + +``` +- main: Produção (releases e hotfixes) +- develop: Desenvolvimento principal +- feature/HU-XX-descricao: Novas funcionalidades +- bugfix/HU-XX-descricao: Correções de bugs +- hotfix/issue-descricao: Correções urgentes em produção +``` + +### Fluxo de Trabalho + +1. **Iniciar Nova Funcionalidade:** + - Criação de branch para a funcionalidade + - Garantir que a nova branch está atualizada com as alterações da main + +2. **Trabalhar na Funcionalidade:** + - Commits descritivos em português + - Formato: `HU-01: Descrição da alteração` + - Exemplo: `HU-01: Implementar validação de duplicatas` + +3. **Pull Request para Develop:** + - Descrever as alterações + - Referenciar a HU + - Mínimo 1 aprovação antes de merge + - Rodar testes antes de merge + +### Convenção de Commits + +``` +(): + + +``` + +**Tipos:** +- `feat`: Nova funcionalidade (HU) +- `fix`: Correção de bug +- `docs`: Documentação +- `style`: Formatação +- `refactor`: Refatoração +- `test`: Testes +- `chore`: Tarefas de build/dependências + +**Exemplo:** +``` +feat(autenticacao): Implementar login com email e matrícula +``` + +--- + +## Métricas e Velocidade + +### Cálculo de Velocity + +**Sprint Atual:** +- Total de Pontos: **62 pontos** +- Histórias por Sprint: [A definir conforme organização] + +**Fórmula:** +``` +Velocity = Pontos Concluídos / Número de Sprints + +Exemplo (após 3 sprints): +Sprint 1: 21 pontos +Sprint 2: 18 pontos +Sprint 3: 20 pontos +Velocity Média = (21+18+20)/3 = 19.67 pontos/sprint +``` + +### Capacidade de Planning + +``` +Baseado na velocity média, para próxima sprint: +- Pontos a planejar ≈ Velocity média +- Buffer (20% do total) para imprevistos +- Ajustar conforme necessário +``` + +--- + +## Próximos Passos + +- [X] Preencher nomes e matrículas dos integrantes +- [ ] Definir duração de cada sprint +- [ ] Criar backlog com priorização +- [X] Configurar repositório Git +- [X] Configurar ambiente de desenvolvimento +- [X] Criar estrutura inicial do Rails +- [X] Iniciar Sprint 1 From 4c0216221f9cd306fb3e8d137ecdfd3635734295 Mon Sep 17 00:00:00 2001 From: Maria Carolina Date: Mon, 17 Nov 2025 20:28:48 -0300 Subject: [PATCH 07/16] fix: correcao do BDD de Edicao e Delecao de Templates --- features/edicao_e_delecao_templates.feature | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/features/edicao_e_delecao_templates.feature b/features/edicao_e_delecao_templates.feature index 2aee533b68..8e9f41bb25 100644 --- a/features/edicao_e_delecao_templates.feature +++ b/features/edicao_e_delecao_templates.feature @@ -5,26 +5,35 @@ Feature: Edição e deleção de templates Background: Given que estou autenticado como administrador - And existe um template criado previamente + And existe um template com o nome "Template Turma Antiga" Scenario: Editar o nome de um template com sucesso (feliz) - When eu edito o template alterando seu nome para "Template Atualizado" + When eu clico para editar o template + And eu altero seu nome para "Template Turma Atualizada" Then o template deve ser salvo com o novo nome And os formulários já criados anteriormente não devem ser modificados And eu devo ver a mensagem "Template atualizado com sucesso" Scenario: Editar as perguntas de um template com sucesso (feliz) - When eu edito o template alterando suas perguntas + When eu clico para editar o template + And eu altero suas perguntas Then o template deve ser salvo com as novas perguntas And os formulários já criados anteriormente não devem ser modificados And eu devo ver a mensagem "Template atualizado com sucesso" Scenario: Deletar um template com sucesso (feliz) - When eu deleto o template + When eu clico para deletar o template Then o template deve ser removido do sistema And os formulários já criados anteriormente devem permanecer intactos And eu devo ver a mensagem "Template excluído com sucesso" + Scenario: Tentativa de salvar com nome em branco (triste) + Given que eu clico para editar o template + When eu apago o nome do template, deixando-o em branco + And eu salvo as alterações + Then eu devo ver a mensagem "Nome do template não pode ficar em branco" + And o template deve continuar com o nome "Template Turma Antiga" + Scenario: Tentar editar um template que está em uso por um formulário ativo (triste) Given que o template está vinculado a um formulário ativo When eu tento editar o template From 80a10912e06b3cce81c39add391f14b9b72e1630 Mon Sep 17 00:00:00 2001 From: Maria Carolina Date: Mon, 17 Nov 2025 20:33:16 -0300 Subject: [PATCH 08/16] fix: correcao do BDD de Importar Dados do SIGAA --- features/importar_dados_sigaa.feature | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/features/importar_dados_sigaa.feature b/features/importar_dados_sigaa.feature index 04a13e0cdb..c757d1f0f6 100644 --- a/features/importar_dados_sigaa.feature +++ b/features/importar_dados_sigaa.feature @@ -13,8 +13,8 @@ Feature: Importar dados do SIGAA And eu devo ver a mensagem "Importação concluída com sucesso" Scenario: Dados já existentes na base (triste) - Given que alguns dados do SIGAA já existem na base local - When eu tento importar novamente + Given que "Turma Engenharia de Software" do SIGAA já existem na base local + When eu tento importar novamente "Turma Engenharia de Software" Then o sistema deve ignorar os registros duplicados And eu devo ver a mensagem "Nenhum dado novo foi importado" From 7f57bc80b071c2c8bc0909c1d246d3bf7a93087f Mon Sep 17 00:00:00 2001 From: Maria Carolina Date: Mon, 17 Nov 2025 20:44:37 -0300 Subject: [PATCH 09/16] =?UTF-8?q?feat:=20adicao=20do=20BDD=20da=20issue=20?= =?UTF-8?q?Criar=20Template=20de=20Formul=C3=A1rio?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- features/criar_template_formulario.feature | 40 ++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 features/criar_template_formulario.feature diff --git a/features/criar_template_formulario.feature b/features/criar_template_formulario.feature new file mode 100644 index 0000000000..d8e88ffa83 --- /dev/null +++ b/features/criar_template_formulario.feature @@ -0,0 +1,40 @@ +Feature: Criação de Template de Formulário + Como Administrador + Quero criar um template de formulário contendo as questões do formulário + A fim de gerar formulários de avaliações para avaliar o desempenho das turmas + + Background: + Given que estou autenticado como administrador + + Scenario: Criação de template bem-sucedida (feliz) + Given que eu estou na página de criação de templates + When eu preencho o nome do template com "Avaliação Padrão Semestral" + And eu adiciono a pergunta "O professor foi claro nas explicações?" + And eu adiciono a pergunta "Os materiais de aula foram úteis?" + And eu salvo o template + Then eu devo ver a mensagem "Template criado com sucesso" + And o "Avaliação Padrão Semestral" deve aparecer na lista de templates + + Scenario: Tentativa de criar template sem nome (triste) + Given que eu estou na página de criação de templates + When eu deixo o nome do template em branco + And eu adiciono a pergunta "O professor foi claro nas explicações?" + And eu tento salvar o template + Then eu devo ver a mensagem "Erro: O nome do template é obrigatório" + And o template não deve ser criado + + Scenario: Tentativa de criar template sem perguntas (triste) + Given que eu estou na página de criação de templates + When eu preencho o nome do template com "Template Vazio" + And eu NÃO adiciono nenhuma pergunta + And eu tento salvar o template + Then eu devo ver a mensagem "Erro: O template deve conter pelo menos uma pergunta" + And o template não deve ser criado + + Scenario: Tentativa de criar template com nome duplicado (triste) + Given que já existe um template com o nome "Avaliação Padrão Semestral" + When eu preencho o nome do template com "Avaliação Padrão Semestral" + And eu adiciono uma pergunta + And eu tento salvar o template + Then eu devo ver a mensagem "Erro: Já existe um template com este nome" + And o template não deve ser criado \ No newline at end of file From f222059aa97d24ee020030347f6f3ec87458737c Mon Sep 17 00:00:00 2001 From: Maria Carolina Date: Mon, 17 Nov 2025 20:53:54 -0300 Subject: [PATCH 10/16] feat: adicao do BDD da issue Visualizacao dos Templates Criados --- .../visualizacao_templates_criados.feature | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 features/visualizacao_templates_criados.feature diff --git a/features/visualizacao_templates_criados.feature b/features/visualizacao_templates_criados.feature new file mode 100644 index 0000000000..7c8728b7c4 --- /dev/null +++ b/features/visualizacao_templates_criados.feature @@ -0,0 +1,21 @@ +Feature: Visualização de Templates + Como Administrador + Quero visualizar os templates criados + A fim de poder editar e/ou deletar um template que eu criei + + Background: + Given que estou autenticado como administrador + + Scenario: Visualizar lista de templates existentes (feliz) + Given que existem os templates "Template Avaliação Semestral" e "Template Rascunho" cadastrados + When eu acesso a página de "Meus Templates" + Then eu devo ver "Template Avaliação Semestral" na lista + And eu devo ver um botão de "Editar" e "Deletar" ao lado de "Template Avaliação Semestral" + And eu devo ver "Template Rascunho" na lista + And eu devo ver um botão de "Editar" e "Deletar" ao lado de "Template Rascunho" + + Scenario: Visualizar quando não há templates cadastrados (triste/alternativo) + Given que nenhum template foi criado ainda + When eu acesso a página de "Meus Templates" + Then eu devo ver a mensagem "Nenhum template encontrado" + And eu devo ver um botão para "Criar Novo Template" \ No newline at end of file From b2bb055d019dd3c2cf47b5b1973bd9310c0e4632 Mon Sep 17 00:00:00 2001 From: Bernardo Date: Mon, 17 Nov 2025 21:04:53 -0300 Subject: [PATCH 11/16] issues implementadas: visualizar formularios criados, visualizar formularios para responder, formularios para docentes e discentes --- .../formularios_discentes_docentes.feature | 40 +++++++++++++++++++ .../visualizar_formularios_criados.feature | 31 ++++++++++++++ ...alizar_formularios_nao_respondidos.feature | 31 ++++++++++++++ 3 files changed, 102 insertions(+) create mode 100644 features/formularios_discentes_docentes.feature create mode 100644 features/visualizar_formularios_criados.feature create mode 100644 features/visualizar_formularios_nao_respondidos.feature diff --git a/features/formularios_discentes_docentes.feature b/features/formularios_discentes_docentes.feature new file mode 100644 index 0000000000..2accdc4f7d --- /dev/null +++ b/features/formularios_discentes_docentes.feature @@ -0,0 +1,40 @@ +Feature: Escolher criar formulário para docentes ou discentes + Como Administrador + Quero escolher criar um formulário para os docentes ou os dicentes de uma turma + A fim de avaliar o desempenho de uma matéria + + Background: + Given que estou autenticado como administrador + And que estou criando um novo formulário + + Scenario: Criar formulário para alunos (discentes) (feliz) + Given que estou na página de criar formulário + When eu seleciono um template + And eu escolho as turmas + And eu seleciono "Discentes" como tipo de avaliador + And eu clico em "Criar formulário" + Then o formulário deve ser criado apenas para alunos + And apenas alunos da turma devem receber notificação + + Scenario: Criar formulário para professores (docentes) (feliz) + Given que estou na página de criar formulário + When eu seleciono um template + And eu escolho as turmas + And eu seleciono "Docentes" como tipo de avaliador + And eu clico em "Criar formulário" + Then o formulário deve ser criado apenas para professores + And apenas professores da turma devem receber notificação + + Scenario: Avaliadores corretos veem apenas seus formulários (feliz) + Given que um formulário foi criado para "Discentes" + When um professor da turma faz login + Then ele não deve ver este formulário nos pendentes + And quando um aluno faz login, ele vê o formulário + + Scenario: Criar dois formulários diferentes para mesma turma (feliz) + Given que estou criando dois formulários para a mesma turma + When eu crio um formulário para "Discentes" + And eu crio outro formulário para "Docentes" + Then os dois formulários devem coexistir + And cada grupo receberá apenas o formulário destinado a ele +``` \ No newline at end of file diff --git a/features/visualizar_formularios_criados.feature b/features/visualizar_formularios_criados.feature new file mode 100644 index 0000000000..b8bbf4823a --- /dev/null +++ b/features/visualizar_formularios_criados.feature @@ -0,0 +1,31 @@ +Feature: Visualizar formulários criados + Como Administrador + Quero visualizar os formulários criados + A fim de poder gerar um relatório a partir das respostas + + Background: + Given que estou autenticado como administrador + + Scenario: Listar todos os formulários criados (feliz) + Given que criei vários formulários + When eu acesso a seção "Meus Formulários" + Then eu devo ver uma lista de todos os formulários + And cada formulário deve mostrar: nome, template usado, turmas, status, data de criação + + Scenario: Formulário mostra quantidade de respostas (feliz) + Given que um formulário foi respondido por alguns participantes + When eu visualizo a lista de formulários + Then cada formulário deve exibir a quantidade de respostas recebidas + And eu devo conseguir comparar o progresso entre formulários + + Scenario: Acessar detalhes do formulário (feliz) + Given que existe um formulário criado + When eu clico em um formulário + Then eu devo ver os detalhes: questões, data de abertura/fechamento + And eu devo ter a opção de visualizar respostas + + Scenario: Formulários apenas do meu departamento (feliz) + Given que administro apenas um departamento + When eu acesso a seção "Meus Formulários" + Then eu devo ver apenas os formulários criados para turmas do meu departamento + And eu não devo ver formulários de outros departamentos \ No newline at end of file diff --git a/features/visualizar_formularios_nao_respondidos.feature b/features/visualizar_formularios_nao_respondidos.feature new file mode 100644 index 0000000000..af689f404d --- /dev/null +++ b/features/visualizar_formularios_nao_respondidos.feature @@ -0,0 +1,31 @@ +Feature: Visualizar formulários não respondidos + Como Participante de uma turma + Quero visualizar os formulários não respondidos das turmas em que estou matriculado + A fim de poder escolher qual irei responder + + Background: + Given que estou autenticado como participante + And que estou matriculado em 3 turmas diferentes + + Scenario: Visualizar lista de formulários não respondidos (feliz) + Given que existem formulários disponíveis nas minhas turmas + When eu acesso a seção "Formulários Pendentes" + Then eu devo ver apenas os formulários que ainda não respondi + And cada formulário deve mostrar: turma, disciplina, data de abertura e fechamento + + Scenario: Formulários respondidos não aparecem na lista (feliz) + Given que já respondi um formulário + When eu acesso a seção "Formulários Pendentes" + Then o formulário que respondi não deve aparecer na lista + And apenas formulários novos ou em aberto devem ser mostrados + + Scenario: Nenhum formulário pendente (triste) + Given que não há formulários pendentes para responder + When eu acesso a seção "Formulários Pendentes" + Then eu devo ver a mensagem "Não há formulários pendentes" + + Scenario: Filtrar formulários por turma (feliz) + Given que existem formulários não respondidos de diferentes turmas + When eu seleciono uma turma específica + Then eu devo ver apenas os formulários daquela turma + And os formulários de outras turmas devem ser ocultados \ No newline at end of file From 8ef3fc1e87057e49b0f2d44e77bb6a3a05d82e91 Mon Sep 17 00:00:00 2001 From: bg! <99600828+bg1777@users.noreply.github.com> Date: Mon, 17 Nov 2025 21:26:42 -0300 Subject: [PATCH 12/16] Atualizando wiki do projeto --- README.md | 36 +++++++++++------------------------- 1 file changed, 11 insertions(+), 25 deletions(-) diff --git a/README.md b/README.md index 7df6655edb..7bac3c310e 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ | **Nome do Projeto** | CAMAAR - Plataforma de Avaliação de Cursos | | **Disciplina** | Engenharia de Software | | **Período** | 2025.2 | -| **Integrantes do Grupo** | Bernardo Gomes Rodrigues - 231034190
[Nome 2 - Matrícula 2]
[Nome 3 - Matrícula 3]
[Nome 4 - Matrícula 4] | +| **Integrantes do Grupo** | Bernardo Gomes Rodrigues - 231034190
Isaac Silva - 231025216
Filipe Abadia Marcelino - 190087161
Maria Carolina Burgum Abreu Jorge - 231013547 | --- @@ -18,7 +18,7 @@ | Papel | Responsável | Matrícula | |-------|-------------|-----------| | **Scrum Master** | Bernardo Gomes Rodrigues | 231034190 | -| **Product Owner** | [Nome do Product Owner] | [Matrícula] | +| **Product Owner** | Maria Carolina Burgum Abreu Jorge | 231013547 | --- @@ -52,14 +52,12 @@ O CAMAAR é uma **plataforma web para avaliação de cursos e disciplinas** inte **Funcionalidades:** - Login com email ou matrícula + senha - Definir senha após convite de cadastro +- Email de boas vindas informando a senha (se aplicável) - Recuperar acesso através de email (redefinir senha) **Regras de Negócio:** -- Senhas devem ter no mínimo 8 caracteres +- Senhas devem ter no mínimo 4 caracteres - Senhas devem conter pelo menos: 1 letra maiúscula, 1 letra minúscula, 1 número e 1 caractere especial -- Link de ativação de conta válido por 48 horas -- Link de redefinição de senha válido por 24 horas -- Máximo de 5 tentativas de login falhadas antes de bloquear por 15 minutos - Email de boas-vindas enviado automaticamente após criação de usuário - Usuário deve alterar senha temporária no primeiro acesso @@ -94,17 +92,15 @@ O CAMAAR é uma **plataforma web para avaliação de cursos e disciplinas** inte **Funcionalidades:** - Criar templates com múltiplos tipos de questões - Visualizar templates criados -- Editar templates sem afetar formulários já criados -- Deletar templates sem afetar formulários existentes +- Editar templates +- Deletar templates **Regras de Negócio:** - Template deve ter no mínimo 1 questão - Nome do template deve ser único por administrador - Apenas o criador do template pode editá-lo (ou outro admin do mesmo departamento) -- Tipos de questões suportados: Múltipla escolha, Escala Likert, Texto aberto, Verdadeiro/Falso +- Tipos de questões suportados: Múltipla escolha, Texto aberto, Verdadeiro/Falso - Edições em template afetam apenas novos formulários criados, não retroativamente -- Template deletado não afeta formulários já criados baseados nele -- Histórico de versões do template é mantido - Administrador só pode gerenciar templates do seu departamento **Responsável:** [Nome do desenvolvedor] @@ -117,19 +113,14 @@ O CAMAAR é uma **plataforma web para avaliação de cursos e disciplinas** inte - Criar formulário baseado em template - Selecionar turmas para aplicar o formulário - Escolher tipo de avaliador (docentes ou discentes) -- Definir data de abertura e fechamento - Visualizar formulários criados **Regras de Negócio:** - Formulário herda todas as questões do template no momento da criação - Deve selecionar no mínimo 1 turma - Deve escolher tipo de avaliador (obrigatório) -- Data de fechamento deve ser posterior à data de abertura -- Formulário não pode ser editado após criação (apenas deletado e recriado) - Apenas turmas do departamento do administrador podem ser selecionadas -- Formulário ativo quando data atual está entre abertura e fechamento - Mesmo formulário não pode ser respondido 2 vezes pelo mesmo participante -- Notificação automática enviada aos participantes quando formulário é criado **Responsável:** [Nome do desenvolvedor] @@ -140,14 +131,11 @@ O CAMAAR é uma **plataforma web para avaliação de cursos e disciplinas** inte **Funcionalidades:** - Visualizar formulários não respondidos - Responder questionário -- Salvar progresso como rascunho - Submeter respostas **Regras de Negócio:** - Participante visualiza apenas formulários de turmas onde está matriculado -- Formulário deve estar dentro do período de abertura/fechamento para responder - Todos os campos obrigatórios devem ser preenchidos antes de enviar -- Rascunho é salvo automaticamente a cada 30 segundos - Participante pode editar respostas enquanto rascunho não foi enviado - Uma vez enviado, não pode ser alterado - Resposta não pode ser submetida duas vezes pelo mesmo participante @@ -161,13 +149,13 @@ O CAMAAR é uma **plataforma web para avaliação de cursos e disciplinas** inte **Funcionalidades:** - Exportar respostas em formato CSV -- Filtrar por turma específica +- Filtrar por formulário - Download do arquivo **Regras de Negócio:** - Apenas administrador pode exportar resultados - Arquivo CSV deve conter: ID da resposta, Participante, Data de resposta, Respostas individuais -- Formato CSV deve ser compatível com Excel e planilhas +- Formato CSV deve ser compatível com planilhas - Caracteres especiais devem estar codificados corretamente (UTF-8) - Arquivo só pode ser gerado se houver respostas - Apenas respostas de formulários do departamento do admin são exportadas @@ -192,7 +180,6 @@ O CAMAAR é uma **plataforma web para avaliação de cursos e disciplinas** inte - Erro 403 (Acesso Negado) deve ser retornado para tentativas não autorizadas - Super Admin pode gerenciar múltiplos departamentos (se aplicável) - Departamento é definido no perfil do usuário durante importação do SIGAA -- Logs de tentativas de acesso não autorizado devem ser registrados **Responsável:** [Nome do desenvolvedor] @@ -228,9 +215,8 @@ O CAMAAR é uma **plataforma web para avaliação de cursos e disciplinas** inte - Usuários são criados automaticamente durante importação do SIGAA - Usuário inativo não pode fazer login - Quando participante é removido do SIGAA, status muda para inativo -- Email de boas-vindas é enviado automaticamente -- Senha temporária é gerada e enviada por email -- Usuário pode ter múltiplos papéis (aluno em uma turma, professor em outra, admin de disciplina) +- Email de boas-vindas é enviado automaticamente (se aplicável) +- Senha temporária é gerada e enviada no email de boas vindas - Histórico de mudanças de status é mantido **Responsável:** [Nome do desenvolvedor] From 95a8c09709d29a4eabce79804f7e970889500570 Mon Sep 17 00:00:00 2001 From: bg! <99600828+bg1777@users.noreply.github.com> Date: Mon, 17 Nov 2025 21:39:32 -0300 Subject: [PATCH 13/16] =?UTF-8?q?Mais=20altera=C3=A7=C3=B5es=20no=20md=20d?= =?UTF-8?q?a=20wiki?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 20 ++++---------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 7bac3c310e..4bbe7c5b93 100644 --- a/README.md +++ b/README.md @@ -132,6 +132,7 @@ O CAMAAR é uma **plataforma web para avaliação de cursos e disciplinas** inte - Visualizar formulários não respondidos - Responder questionário - Submeter respostas +- Filtrar respostas de turmas **Regras de Negócio:** - Participante visualiza apenas formulários de turmas onde está matriculado @@ -280,7 +281,6 @@ A fim de submeter minha avaliação da turma Critérios de Aceitação: - Visualiza questionário da turma - Preenche questões obrigatórias -- Salva como rascunho (auto-save a cada 30s) - Submete respostas finais - Não pode responder 2 vezes o mesmo formulário ``` @@ -337,7 +337,7 @@ A fim de gerar formulários de avaliações reutilizáveis Critérios de Aceitação: - Template com nome único - Mínimo 1 questão obrigatória -- Suporta múltiplos tipos: múltipla escolha, Likert, texto, V/F +- Suporta múltiplos tipos: múltipla escolha, texto, V/F - Apenas criador pode editar - Edições não afetam formulários já criados ``` @@ -356,7 +356,6 @@ A fim de avaliar o desempenho das turmas no semestre atual Critérios de Aceitação: - Seleciona template - Escolhe múltiplas turmas (mínimo 1) -- Define datas de abertura/fechamento - Escolhe tipo de avaliador (docentes/discentes) - Formulário herda questões do template - Notificação enviada aos participantes @@ -370,15 +369,13 @@ Critérios de Aceitação: ``` Como Usuário do sistema -Quero acessar o sistema utilizando email ou matrícula e senha +Quero acessar o sistema utilizando email e senha A fim de responder formulários ou gerenciar o sistema Critérios de Aceitação: - Login com email funciona -- Login com matrícula funciona - Validação de credenciais - Redirecionamento para painel -- Bloqueio após 5 tentativas falhadas por 15 minutos ``` **Pontos:** 3 | **Responsável:** [Nome] @@ -393,7 +390,6 @@ Quero definir uma senha para o meu usuário a partir do email de cadastro A fim de acessar o sistema Critérios de Aceitação: -- Link de ativação válido por 48 horas - Senha deve cumprir critérios de segurança - Senhas devem conferir - Redirecionamento para login após sucesso @@ -414,7 +410,6 @@ Critérios de Aceitação: - Visualiza apenas turmas do departamento - Criar formulário apenas com turmas do departamento - Erro 403 para tentativas de acesso não autorizado -- Logs de tentativas não autorizadas ``` **Pontos:** 5 | **Responsável:** [Nome] @@ -429,7 +424,6 @@ Quero redefinir uma senha a partir do email recebido A fim de recuperar meu acesso ao sistema Critérios de Aceitação: -- Link de recuperação válido por 24 horas - Validação de senha - Email de confirmação enviado - Redirecionamento para login @@ -449,7 +443,6 @@ A fim de corrigir a base de dados do sistema Critérios de Aceitação: - Sincroniza dados existentes - Adiciona novos dados -- Marca turmas como inativas - Atualiza mudanças de turmas - Mantém histórico de atualizações ``` @@ -468,7 +461,6 @@ A fim de poder escolher qual irei responder Critérios de Aceitação: - Lista apenas formulários não respondidos - Mostra turma, disciplina, datas -- Filtra por turma - Formulários respondidos não aparecem ``` @@ -521,11 +513,8 @@ Quero editar e/ou deletar um template que eu criei sem afetar formulários já c A fim de organizar os templates existentes Critérios de Aceitação: -- Editar template não afeta formulários existentes -- Deletar template não deleta formulários - Confirmação de exclusão -- Apenas criador pode editar -- Histórico de versões mantido +- Apenas criador pode editar e excluir ``` **Pontos:** 3 | **Responsável:** [Nome] @@ -544,7 +533,6 @@ Critérios de Aceitação: - Professores veem apenas formulários para Docentes - Alunos veem apenas formulários para Discentes - Múltiplos formulários podem coexistir para mesma turma -- Notificação apenas para tipo correto ``` **Pontos:** 3 | **Responsável:** [Nome] From 2b3e1f03f0b025ab352e52b552574fac6d669a00 Mon Sep 17 00:00:00 2001 From: Filipe Marcelino <105222322+Fam21@users.noreply.github.com> Date: Tue, 18 Nov 2025 18:47:43 -0300 Subject: [PATCH 14/16] Add files via upload --- features/cadastrar_usuario_do_sistema.feature | 53 ++++++++++++++++++ features/criar_formulario.feature | 56 +++++++++++++++++++ features/responder_formulario.feature | 38 +++++++++++++ features/sistema_login.feature | 46 +++++++++++++++ 4 files changed, 193 insertions(+) create mode 100644 features/cadastrar_usuario_do_sistema.feature create mode 100644 features/criar_formulario.feature create mode 100644 features/responder_formulario.feature create mode 100644 features/sistema_login.feature diff --git a/features/cadastrar_usuario_do_sistema.feature b/features/cadastrar_usuario_do_sistema.feature new file mode 100644 index 0000000000..a9ec6496ff --- /dev/null +++ b/features/cadastrar_usuario_do_sistema.feature @@ -0,0 +1,53 @@ +Feature: Importação de participantes do SIGAA + Como Administrador + Quero cadastrar participantes de turmas do SIGAA ao importar dados de usuários novos para o sistema + A fim de que eles acessem o sistema CAMAAR + + Scenario: Administrador importa participantes de uma turma do SIGAA + Given que estou autenticado como Administrador + And estou na seção "Gerenciamento" + When eu seleciono a opção "Importar Participantes do SIGAA" + And escolho a turma "Turma A" + And confirmo a importação + Then o sistema deve importar os dados dos usuários da turma "Turma A" + And deve registrar que os usuários importados estão pendentes de definição de senha + + Scenario: Sistema envia solicitação para definição de senha aos usuários importados + Given que usuários foram importados da turma "Turma A" + And estão marcados como pendentes de definição de senha + When a importação é concluída + Then o sistema deve enviar uma solicitação para definição de senha para cada usuário novo importado + + Scenario: Usuário define a senha pela primeira vez + Given que um usuário foi importado e está pendente de definição de senha + When o usuário acessa o link de definição de senha enviado pelo sistema + And informa uma nova senha válida + Then o sistema deve registrar a senha do usuário + And o cadastro do usuário deve ser efetivado + And o usuário deve estar apto a acessar o sistema CAMAAR + + Scenario: Usuário tenta acessar o sistema sem ter definido a senha + Given que um usuário foi importado e está pendente de definição de senha + When o usuário tenta acessar o sistema CAMAAR + Then o sistema deve impedir o acesso + And deve informar que a senha deve ser definida antes do primeiro acesso + + Scenario: Administrador importa usuários já existentes no sistema + Given que estou autenticado como Administrador + And estou na seção "Importar Participantes do SIGAA" + When eu importo uma turma que contém usuários já cadastrados no CAMAAR + Then o sistema não deve recriar esses usuários + And deve apenas associá-los à turma importada + + Scenario: Administrador tenta importar turma sem selecionar uma turma + Given que estou autenticado como Administrador + When eu tento iniciar a importação sem selecionar uma turma + Then o sistema deve informar que é necessário escolher uma turma + And não deve iniciar a importação + + Scenario: Importação falha devido a erro no SIGAA + Given que estou autenticado como Administrador + And estou na página de importação de participantes + When ocorre uma falha na comunicação com o SIGAA + Then o sistema deve informar que não foi possível completar a importação + And não deve registrar nenhum usuário como importado diff --git a/features/criar_formulario.feature b/features/criar_formulario.feature new file mode 100644 index 0000000000..6b99b2e06e --- /dev/null +++ b/features/criar_formulario.feature @@ -0,0 +1,56 @@ +Feature: Criação de formulários de avaliação + Como Administrador + Quero escolher criar um formulário para os docentes ou os discentes de uma turma + A fim de avaliar o desempenho de uma matéria + + Scenario: Administrador acessa a área de criação de formulários + Given que estou autenticado como Administrador + When eu acesso a seção de "Gerenciamento" no menu lateral + Then o sistema deve exibir a opção "Criar Formulário" + And deve permitir selecionar uma turma para criar o formulário + + Scenario: Criar formulário de avaliação para docentes + Given que estou autenticado como Administrador + And estou na página de criação de formulário + When eu seleciono a turma "Turma A" + And escolho o tipo de público "Docentes" + And preencho as perguntas do formulário + And confirmo a criação + Then o sistema deve registrar o formulário para os docentes da turma "Turma A" + And deve exibir uma mensagem de confirmação de criação + + Scenario: Criar formulário de avaliação para discentes + Given que estou autenticado como Administrador + And estou na página de criação de formulário + When eu seleciono a turma "Turma B" + And escolho o tipo de público "Discentes" + And preencho as perguntas do formulário + And confirmo a criação + Then o sistema deve registrar o formulário para os discentes da turma "Turma B" + And deve exibir uma mensagem de confirmação de criação + + Scenario: Administrador tenta criar formulário sem selecionar a turma + Given que estou autenticado como Administrador + And estou na página de criação de formulário + When eu deixo de selecionar uma turma + And tento confirmar a criação do formulário + Then o sistema deve informar que a seleção da turma é obrigatória + And não deve criar o formulário + + Scenario: Administrador tenta criar formulário sem definir o tipo de público + Given que estou autenticado como Administrador + And estou na página de criação de formulário + When eu seleciono uma turma + And não escolho se o formulário é para docentes ou discentes + And tento confirmar a criação + Then o sistema deve informar que o tipo de público deve ser selecionado + And não deve criar o formulário + + Scenario: Administrador tenta criar formulário sem perguntas + Given que estou autenticado como Administrador + And estou na página de criação de formulário + When eu seleciono uma turma + And escolho o tipo de público "Docentes" + And tento criar o formulário sem adicionar perguntas + Then o sistema deve informar que o formulário deve conter ao menos uma pergunta + And não deve criar o formulário diff --git a/features/responder_formulario.feature b/features/responder_formulario.feature new file mode 100644 index 0000000000..1790add42b --- /dev/null +++ b/features/responder_formulario.feature @@ -0,0 +1,38 @@ +Feature: Responder questionário de avaliação da turma + Como Participante de uma turma + Eu quero responder o questionário sobre a turma em que estou matriculado + A fim de submeter minha avaliação da turma + + Scenario: Acessar questionário disponível para avaliação + Given que estou autenticado no sistema como Participante + And estou matriculado em uma turma que possui um questionário de avaliação aberto + When eu acesso a área de avaliações da minha turma + Then o sistema deve exibir o questionário disponível para resposta + + Scenario: Responder questionário com sucesso + Given que estou autenticado no sistema como Participante + And existe um questionário de avaliação aberto para a turma em que estou matriculado + When eu preencho todas as perguntas obrigatórias do questionário + And submeto as respostas + Then o sistema deve registrar minhas respostas + And exibir uma confirmação de envio da avaliação + + Scenario: Tentativa de envio com respostas incompletas + Given que estou autenticado no sistema como Participante + And existe um questionário de avaliação aberto para a minha turma + When eu tento submeter o questionário deixando perguntas obrigatórias em branco + Then o sistema deve impedir a submissão + And exibir uma mensagem informando que há perguntas obrigatórias não respondidas + + Scenario: Participante tenta responder um questionário já enviado + Given que estou autenticado no sistema como Participante + And já submeti anteriormente minha avaliação da turma + When eu tento acessar novamente o questionário de avaliação + Then o sistema deve informar que minha avaliação já foi enviada + And não deve permitir uma nova submissão + + Scenario: Participante tenta responder questionário inexistente + Given que estou autenticado no sistema como Participante + And minha turma não possui questionário de avaliação disponível + When eu acesso a área de avaliações da turma + Then o sistema deve informar que não há avaliações disponíveis no momento diff --git a/features/sistema_login.feature b/features/sistema_login.feature new file mode 100644 index 0000000000..d436a75827 --- /dev/null +++ b/features/sistema_login.feature @@ -0,0 +1,46 @@ +Feature: Autenticação de Usuário + Como Usuário do sistema + Quero acessar o sistema utilizando um e-mail ou matrícula e uma senha já cadastrada + A fim de responder formulários ou gerenciar o sistema + + Scenario: Login com credenciais válidas usando e-mail + Given que existe um usuário cadastrado com email "usuario@exemplo.com" e senha "123456" + And estou na página de login + When eu informo o email "usuario@exemplo.com" e a senha "123456" + Then o sistema deve autenticar o usuário + And deve exibir a página inicial do sistema + + Scenario: Login com credenciais válidas usando matrícula + Given que existe um usuário cadastrado com matrícula "202312345" e senha "abc123" + And estou na página de login + When eu informo a matrícula "202312345" e a senha "abc123" + Then o sistema deve autenticar o usuário + And deve exibir a página inicial do sistema + + Scenario: Login com credenciais inválidas + Given que estou na página de login + When eu informo o identificador "usuario@exemplo.com" e a senha "senha_incorreta" + Then o sistema deve exibir uma mensagem de erro de autenticação + And não deve permitir o acesso ao sistema + + Scenario: Login de administrador exibe opções de gerenciamento + Given que existe um usuário administrador com email "admin@exemplo.com" e senha "admin123" + And estou na página de login + When eu informo o email "admin@exemplo.com" e a senha "admin123" + Then o sistema deve autenticar o usuário + And deve exibir a página inicial do sistema + And deve mostrar a opção "Gerenciamento" no menu lateral + + Scenario: Login de usuário comum não exibe opções de gerenciamento + Given que existe um usuário comum com email "user@exemplo.com" e senha "user123" + And estou na página de login + When eu informo o email "user@exemplo.com" e a senha "user123" + Then o sistema deve autenticar o usuário + And deve exibir a página inicial do sistema + And não deve mostrar a opção "Gerenciamento" no menu lateral + + Scenario: Tentativa de login sem preencher todos os campos + Given que estou na página de login + When eu tento entrar no sistema sem preencher o identificador ou a senha + Then o sistema deve informar que todos os campos são obrigatórios + And não deve prosseguir com a autenticação From cbad876b82b1bc450dfdd433e2e197c19b27fac6 Mon Sep 17 00:00:00 2001 From: bg! <99600828+bg1777@users.noreply.github.com> Date: Tue, 18 Nov 2025 21:18:32 -0300 Subject: [PATCH 15/16] Ajustes finais ao markdown --- README.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/README.md b/README.md index 4bbe7c5b93..8a35d0069c 100644 --- a/README.md +++ b/README.md @@ -78,10 +78,8 @@ O CAMAAR é uma **plataforma web para avaliação de cursos e disciplinas** inte - Registros duplicados são ignorados (validação por ID único do SIGAA) - Ao importar novos usuários, criar contas com senha temporária - Dados importados não devem sobrescrever informações customizadas no sistema -- Cada importação deve ser registrada com: data, hora, usuário responsável, quantidade de registros processados - Participantes removidos do SIGAA devem ter acesso desativado - Atualização de mudanças de turmas de alunos/professores -- Máximo 1 importação simultânea (evitar condições de corrida) **Responsável:** [Nome do desenvolvedor] @@ -137,7 +135,7 @@ O CAMAAR é uma **plataforma web para avaliação de cursos e disciplinas** inte **Regras de Negócio:** - Participante visualiza apenas formulários de turmas onde está matriculado - Todos os campos obrigatórios devem ser preenchidos antes de enviar -- Participante pode editar respostas enquanto rascunho não foi enviado +- Participante pode editar respostas enquanto formulário não foi enviado - Uma vez enviado, não pode ser alterado - Resposta não pode ser submetida duas vezes pelo mesmo participante - Sistema valida tipo de resposta conforme tipo de questão From e3a5fcfcade70740849bed86ab197a53dfaa5ded Mon Sep 17 00:00:00 2001 From: Bernardo Rodrigues Date: Tue, 18 Nov 2025 21:19:34 -0300 Subject: [PATCH 16/16] Ajustes as issues: cadastrar usuario do sistema, criar formulario, edicao e delecao de templates, formularios discentes e docentes, responder formularios e sistema login --- features/cadastrar_usuario_do_sistema.feature | 14 +++++++------- features/criar_formulario.feature | 12 ++++++------ features/edicao_e_delecao_templates.feature | 17 +++++++++++++++++ features/formularios_discentes_docentes.feature | 3 +-- features/responder_formulario.feature | 17 ++++++++++++----- features/sistema_login.feature | 12 ++++++------ 6 files changed, 49 insertions(+), 26 deletions(-) diff --git a/features/cadastrar_usuario_do_sistema.feature b/features/cadastrar_usuario_do_sistema.feature index a9ec6496ff..ccae729dfd 100644 --- a/features/cadastrar_usuario_do_sistema.feature +++ b/features/cadastrar_usuario_do_sistema.feature @@ -3,7 +3,7 @@ Feature: Importação de participantes do SIGAA Quero cadastrar participantes de turmas do SIGAA ao importar dados de usuários novos para o sistema A fim de que eles acessem o sistema CAMAAR - Scenario: Administrador importa participantes de uma turma do SIGAA + Scenario: Administrador importa participantes de uma turma do SIGAA (feliz) Given que estou autenticado como Administrador And estou na seção "Gerenciamento" When eu seleciono a opção "Importar Participantes do SIGAA" @@ -12,13 +12,13 @@ Feature: Importação de participantes do SIGAA Then o sistema deve importar os dados dos usuários da turma "Turma A" And deve registrar que os usuários importados estão pendentes de definição de senha - Scenario: Sistema envia solicitação para definição de senha aos usuários importados + Scenario: Sistema envia solicitação para definição de senha aos usuários importados (feliz) Given que usuários foram importados da turma "Turma A" And estão marcados como pendentes de definição de senha When a importação é concluída Then o sistema deve enviar uma solicitação para definição de senha para cada usuário novo importado - Scenario: Usuário define a senha pela primeira vez + Scenario: Usuário define a senha pela primeira vez (feliz) Given que um usuário foi importado e está pendente de definição de senha When o usuário acessa o link de definição de senha enviado pelo sistema And informa uma nova senha válida @@ -26,26 +26,26 @@ Feature: Importação de participantes do SIGAA And o cadastro do usuário deve ser efetivado And o usuário deve estar apto a acessar o sistema CAMAAR - Scenario: Usuário tenta acessar o sistema sem ter definido a senha + Scenario: Usuário tenta acessar o sistema sem ter definido a senha (triste) Given que um usuário foi importado e está pendente de definição de senha When o usuário tenta acessar o sistema CAMAAR Then o sistema deve impedir o acesso And deve informar que a senha deve ser definida antes do primeiro acesso - Scenario: Administrador importa usuários já existentes no sistema + Scenario: Administrador importa usuários já existentes no sistema (triste) Given que estou autenticado como Administrador And estou na seção "Importar Participantes do SIGAA" When eu importo uma turma que contém usuários já cadastrados no CAMAAR Then o sistema não deve recriar esses usuários And deve apenas associá-los à turma importada - Scenario: Administrador tenta importar turma sem selecionar uma turma + Scenario: Administrador tenta importar turma sem selecionar uma turma (triste) Given que estou autenticado como Administrador When eu tento iniciar a importação sem selecionar uma turma Then o sistema deve informar que é necessário escolher uma turma And não deve iniciar a importação - Scenario: Importação falha devido a erro no SIGAA + Scenario: Importação falha devido a erro no SIGAA (triste) Given que estou autenticado como Administrador And estou na página de importação de participantes When ocorre uma falha na comunicação com o SIGAA diff --git a/features/criar_formulario.feature b/features/criar_formulario.feature index 6b99b2e06e..7ffd474026 100644 --- a/features/criar_formulario.feature +++ b/features/criar_formulario.feature @@ -3,13 +3,13 @@ Feature: Criação de formulários de avaliação Quero escolher criar um formulário para os docentes ou os discentes de uma turma A fim de avaliar o desempenho de uma matéria - Scenario: Administrador acessa a área de criação de formulários + Scenario: Administrador acessa a área de criação de formulários (feliz) Given que estou autenticado como Administrador When eu acesso a seção de "Gerenciamento" no menu lateral Then o sistema deve exibir a opção "Criar Formulário" And deve permitir selecionar uma turma para criar o formulário - Scenario: Criar formulário de avaliação para docentes + Scenario: Criar formulário de avaliação para docentes (feliz) Given que estou autenticado como Administrador And estou na página de criação de formulário When eu seleciono a turma "Turma A" @@ -19,7 +19,7 @@ Feature: Criação de formulários de avaliação Then o sistema deve registrar o formulário para os docentes da turma "Turma A" And deve exibir uma mensagem de confirmação de criação - Scenario: Criar formulário de avaliação para discentes + Scenario: Criar formulário de avaliação para discentes (feliz) Given que estou autenticado como Administrador And estou na página de criação de formulário When eu seleciono a turma "Turma B" @@ -29,7 +29,7 @@ Feature: Criação de formulários de avaliação Then o sistema deve registrar o formulário para os discentes da turma "Turma B" And deve exibir uma mensagem de confirmação de criação - Scenario: Administrador tenta criar formulário sem selecionar a turma + Scenario: Administrador tenta criar formulário sem selecionar a turma (triste) Given que estou autenticado como Administrador And estou na página de criação de formulário When eu deixo de selecionar uma turma @@ -37,7 +37,7 @@ Feature: Criação de formulários de avaliação Then o sistema deve informar que a seleção da turma é obrigatória And não deve criar o formulário - Scenario: Administrador tenta criar formulário sem definir o tipo de público + Scenario: Administrador tenta criar formulário sem definir o tipo de público (triste) Given que estou autenticado como Administrador And estou na página de criação de formulário When eu seleciono uma turma @@ -46,7 +46,7 @@ Feature: Criação de formulários de avaliação Then o sistema deve informar que o tipo de público deve ser selecionado And não deve criar o formulário - Scenario: Administrador tenta criar formulário sem perguntas + Scenario: Administrador tenta criar formulário sem perguntas (triste) Given que estou autenticado como Administrador And estou na página de criação de formulário When eu seleciono uma turma diff --git a/features/edicao_e_delecao_templates.feature b/features/edicao_e_delecao_templates.feature index 8e9f41bb25..1a129159e2 100644 --- a/features/edicao_e_delecao_templates.feature +++ b/features/edicao_e_delecao_templates.feature @@ -45,3 +45,20 @@ Feature: Edição e deleção de templates When eu tento deletar o template Then a remoção deve ser bloqueada And eu devo ver a mensagem "Não é possível remover um template em uso" + + Scenario: Edições em template não afetam formulários já criados (feliz) + Given que criei Template V1 com 3 perguntas + And criei Formulário A baseado em Template V1 + When eu edito Template V1 adicionando 1 pergunta + And crio Formulário B baseado em Template V1 (agora com 4 perguntas) + Then Formulário A deve manter as 3 perguntas originais + And Formulário B deve ter as 4 novas perguntas + + Scenario: Admin de outro departamento não pode editar template (triste) + Given que Admin A criou um template no Dept. X + And Admin B pertence ao Dept. Y + When Admin B tenta editar template de Admin A + Then o sistema retorna erro 403 + And mensagem "Acesso negado" + + diff --git a/features/formularios_discentes_docentes.feature b/features/formularios_discentes_docentes.feature index 2accdc4f7d..5b58f02c5e 100644 --- a/features/formularios_discentes_docentes.feature +++ b/features/formularios_discentes_docentes.feature @@ -36,5 +36,4 @@ Feature: Escolher criar formulário para docentes ou discentes When eu crio um formulário para "Discentes" And eu crio outro formulário para "Docentes" Then os dois formulários devem coexistir - And cada grupo receberá apenas o formulário destinado a ele -``` \ No newline at end of file + And cada grupo receberá apenas o formulário destinado a ele \ No newline at end of file diff --git a/features/responder_formulario.feature b/features/responder_formulario.feature index 1790add42b..58a5e23781 100644 --- a/features/responder_formulario.feature +++ b/features/responder_formulario.feature @@ -3,13 +3,13 @@ Feature: Responder questionário de avaliação da turma Eu quero responder o questionário sobre a turma em que estou matriculado A fim de submeter minha avaliação da turma - Scenario: Acessar questionário disponível para avaliação + Scenario: Acessar questionário disponível para avaliação (feliz) Given que estou autenticado no sistema como Participante And estou matriculado em uma turma que possui um questionário de avaliação aberto When eu acesso a área de avaliações da minha turma Then o sistema deve exibir o questionário disponível para resposta - Scenario: Responder questionário com sucesso + Scenario: Responder questionário com sucesso (feliz) Given que estou autenticado no sistema como Participante And existe um questionário de avaliação aberto para a turma em que estou matriculado When eu preencho todas as perguntas obrigatórias do questionário @@ -17,22 +17,29 @@ Feature: Responder questionário de avaliação da turma Then o sistema deve registrar minhas respostas And exibir uma confirmação de envio da avaliação - Scenario: Tentativa de envio com respostas incompletas + Scenario: Tentativa de envio com respostas incompletas (triste) Given que estou autenticado no sistema como Participante And existe um questionário de avaliação aberto para a minha turma When eu tento submeter o questionário deixando perguntas obrigatórias em branco Then o sistema deve impedir a submissão And exibir uma mensagem informando que há perguntas obrigatórias não respondidas - Scenario: Participante tenta responder um questionário já enviado + Scenario: Participante tenta responder um questionário já enviado (triste) Given que estou autenticado no sistema como Participante And já submeti anteriormente minha avaliação da turma When eu tento acessar novamente o questionário de avaliação Then o sistema deve informar que minha avaliação já foi enviada And não deve permitir uma nova submissão - Scenario: Participante tenta responder questionário inexistente + Scenario: Participante tenta responder questionário inexistente (triste) Given que estou autenticado no sistema como Participante And minha turma não possui questionário de avaliação disponível When eu acesso a área de avaliações da turma Then o sistema deve informar que não há avaliações disponíveis no momento + + Scenario: Participante tenta enviar resposta duplicada na mesma sessão (triste) + Given que estou respondendo um formulário + When eu clico "Enviar" com sucesso + And imediatamente tenta enviar novamente + Then o sistema deve bloquear + And exibir "Esta resposta já foi submetida" diff --git a/features/sistema_login.feature b/features/sistema_login.feature index d436a75827..f50e22f58e 100644 --- a/features/sistema_login.feature +++ b/features/sistema_login.feature @@ -3,27 +3,27 @@ Feature: Autenticação de Usuário Quero acessar o sistema utilizando um e-mail ou matrícula e uma senha já cadastrada A fim de responder formulários ou gerenciar o sistema - Scenario: Login com credenciais válidas usando e-mail + Scenario: Login com credenciais válidas usando e-mail (feliz) Given que existe um usuário cadastrado com email "usuario@exemplo.com" e senha "123456" And estou na página de login When eu informo o email "usuario@exemplo.com" e a senha "123456" Then o sistema deve autenticar o usuário And deve exibir a página inicial do sistema - Scenario: Login com credenciais válidas usando matrícula + Scenario: Login com credenciais válidas usando matrícula (feliz) Given que existe um usuário cadastrado com matrícula "202312345" e senha "abc123" And estou na página de login When eu informo a matrícula "202312345" e a senha "abc123" Then o sistema deve autenticar o usuário And deve exibir a página inicial do sistema - Scenario: Login com credenciais inválidas + Scenario: Login com credenciais inválidas (triste) Given que estou na página de login When eu informo o identificador "usuario@exemplo.com" e a senha "senha_incorreta" Then o sistema deve exibir uma mensagem de erro de autenticação And não deve permitir o acesso ao sistema - Scenario: Login de administrador exibe opções de gerenciamento + Scenario: Login de administrador exibe opções de gerenciamento (feliz) Given que existe um usuário administrador com email "admin@exemplo.com" e senha "admin123" And estou na página de login When eu informo o email "admin@exemplo.com" e a senha "admin123" @@ -31,7 +31,7 @@ Feature: Autenticação de Usuário And deve exibir a página inicial do sistema And deve mostrar a opção "Gerenciamento" no menu lateral - Scenario: Login de usuário comum não exibe opções de gerenciamento + Scenario: Login de usuário comum não exibe opções de gerenciamento (feliz) Given que existe um usuário comum com email "user@exemplo.com" e senha "user123" And estou na página de login When eu informo o email "user@exemplo.com" e a senha "user123" @@ -39,7 +39,7 @@ Feature: Autenticação de Usuário And deve exibir a página inicial do sistema And não deve mostrar a opção "Gerenciamento" no menu lateral - Scenario: Tentativa de login sem preencher todos os campos + Scenario: Tentativa de login sem preencher todos os campos (triste) Given que estou na página de login When eu tento entrar no sistema sem preencher o identificador ou a senha Then o sistema deve informar que todos os campos são obrigatórios