diff --git a/Gemfile b/Gemfile index a33ae6b..f636d77 100644 --- a/Gemfile +++ b/Gemfile @@ -23,6 +23,8 @@ gem "redis", "~> 4.0" gem "bootsnap", require: false +gem "rails-i18n", "~> 7.0" + gem "image_processing", "~> 1.2" gem "pundit", "~> 2.2" diff --git a/Gemfile.lock b/Gemfile.lock index def0681..05d6373 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -249,6 +249,9 @@ GEM ruby-graphviz (~> 1.2) rails-html-sanitizer (1.4.3) loofah (~> 2.3) + rails-i18n (7.0.5) + i18n (>= 0.7, < 2) + railties (>= 6.0.0, < 8) railties (7.0.3.1) actionpack (= 7.0.3.1) activesupport (= 7.0.3.1) @@ -357,6 +360,7 @@ DEPENDENCIES rack-cors (~> 1.1) rails (~> 7.0.3, >= 7.0.3.1) rails-erd (~> 1.7) + rails-i18n (~> 7.0) redis (~> 4.0) rspec-rails (~> 5.1) sassc-rails diff --git a/app/admin/roles.rb b/app/admin/roles.rb deleted file mode 100644 index 288fb6e..0000000 --- a/app/admin/roles.rb +++ /dev/null @@ -1,3 +0,0 @@ -ActiveAdmin.register Role do - permit_params :name -end diff --git a/app/admin/users.rb b/app/admin/users.rb index 872ed37..b063edb 100644 --- a/app/admin/users.rb +++ b/app/admin/users.rb @@ -1,5 +1,5 @@ ActiveAdmin.register User do - permit_params :email, :name, role_ids: [] + permit_params :email, :name, roles: [] index do selectable_column diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 09705d1..6b4dcfa 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -1,2 +1,3 @@ class ApplicationController < ActionController::Base + before_action :authenticate_user! end diff --git a/app/controllers/users/omniauth_callbacks_controller.rb b/app/controllers/users/omniauth_callbacks_controller.rb index e014b0d..f95f169 100644 --- a/app/controllers/users/omniauth_callbacks_controller.rb +++ b/app/controllers/users/omniauth_callbacks_controller.rb @@ -14,7 +14,7 @@ module Users else session['devise.google_data'] = request.env['omniauth.auth'].except('extra') - redirect_to new_user_registration_url, alert: 'User not found.' + redirect_to new_user_session_url, alert: 'User not found.' end end end diff --git a/app/graphql/types/user_type.rb b/app/graphql/types/user_type.rb index 93e9560..24b3209 100644 --- a/app/graphql/types/user_type.rb +++ b/app/graphql/types/user_type.rb @@ -9,9 +9,5 @@ module Types field :email, String, null: false field :roles, [Enums::RoleEnum], null: false field :avatar_url, String, null: true - - def roles - object.roles.map(&:name) - end end end diff --git a/app/javascript/components/Appbar/Appbar.tsx b/app/javascript/components/Appbar/Appbar.tsx index 5ff9150..e8c968c 100644 --- a/app/javascript/components/Appbar/Appbar.tsx +++ b/app/javascript/components/Appbar/Appbar.tsx @@ -11,6 +11,7 @@ import { classNames } from '../../utils'; import { DashboardRoutePaths, QuestionRoutePaths, SessionRoutePaths } from '../../routes' import { turnOff } from '../../services/store/unsavedChanges'; import { CurrentUserAvatar } from "../CurrentUserAvatar"; +import { localFetch } from '../../utils/localFetch'; const UserMenu: FC = () => { const { user } = useCurrentUser(); @@ -21,8 +22,14 @@ const UserMenu: FC = () => { const doLogout = () => { setConfirmLogout(false) + dispatch(turnOff()) - history.push('/') + + localFetch('/users/sign_out', { + method: 'DELETE' + }).then(() => { + window.location.href = '/' + }) } const handleLogout = () => { diff --git a/app/javascript/utils/localFetch.ts b/app/javascript/utils/localFetch.ts new file mode 100644 index 0000000..36bde7e --- /dev/null +++ b/app/javascript/utils/localFetch.ts @@ -0,0 +1,24 @@ +type LocalFetch = typeof fetch + +export const localFetch: LocalFetch = (input, init) => { + const { headers, ...rest } = init ?? {} + + const crfsToken = document + .querySelector("[name='csrf-token']") + ?.getAttribute('content') + + if (!crfsToken) { + throw new Error('CSRF token not found') + } + + const customInt: RequestInit = { + headers: { + 'Content-Type': 'application/json', + 'X-CSRF-Token': crfsToken, + ...(headers ?? {}), + }, + ...rest, + } + + return fetch(input, customInt) +} diff --git a/app/models/role.rb b/app/models/role.rb deleted file mode 100644 index a612a08..0000000 --- a/app/models/role.rb +++ /dev/null @@ -1,18 +0,0 @@ -# == Schema Information -# -# Table name: roles -# -# id :bigint not null, primary key -# name :string -# created_at :datetime not null -# updated_at :datetime not null -# -# Indexes -# -# index_roles_on_name (name) UNIQUE -# -class Role < ApplicationRecord - has_and_belongs_to_many :users - - validates :name, presence: true, uniqueness: true -end diff --git a/app/models/user.rb b/app/models/user.rb index b825d38..a20c75e 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -10,6 +10,7 @@ # remember_created_at :datetime # reset_password_sent_at :datetime # reset_password_token :string +# roles :string default([]), is an Array # created_at :datetime not null # updated_at :datetime not null # @@ -19,21 +20,31 @@ # index_users_on_reset_password_token (reset_password_token) UNIQUE # class User < ApplicationRecord + extend Enumerize + devise :database_authenticatable, - :registerable, :recoverable, :rememberable, :validatable, :omniauthable, omniauth_providers: [:google_oauth2] - has_and_belongs_to_many :roles + enumerize :roles, + multiple: true, + default: :teacher, + in: %i[admin nde coordinator center_director pro_rector teacher] validates :name, presence: true + roles.values.each do |role| + define_method "#{role}?" do + roles.include?(role) + end + end + def self.from_omniauth(email, avatar_url) - @user = User.find_by!(email: email) - @user.update(avatar_url: avatar_url) - @user + User.find_by(email: email).tap do |user| + user.update(avatar_url: avatar_url) unless user.nil? + end end end diff --git a/app/policies/application_policy.rb b/app/policies/application_policy.rb index eee630d..46a9435 100644 --- a/app/policies/application_policy.rb +++ b/app/policies/application_policy.rb @@ -6,7 +6,7 @@ class ApplicationPolicy def initialize(user, record) @user = user @record = record - @roles = user.roles.map { |r| r.name.to_sym } + @roles = user.roles end def is?(role) diff --git a/config/initializers/locale.rb b/config/initializers/locale.rb new file mode 100644 index 0000000..ba31f86 --- /dev/null +++ b/config/initializers/locale.rb @@ -0,0 +1 @@ +I18n.default_locale = 'pt-BR' \ No newline at end of file diff --git a/config/locales/activeadmin.pt-BR.yml b/config/locales/activeadmin.pt-BR.yml new file mode 100644 index 0000000..e7bde81 --- /dev/null +++ b/config/locales/activeadmin.pt-BR.yml @@ -0,0 +1,143 @@ +pt-BR: + active_admin: + dashboard: "Painel Administrativo" + dashboard_welcome: + welcome: "Bem vindo ao Active Admin. Esta é a página de painéis padrão." + call_to_action: "Para adicionar seções ao painel, verifique 'app/admin/dashboard.rb'" + view: "Visualizar" + edit: "Editar" + delete: "Remover" + delete_confirmation: "Você tem certeza que deseja remover este item?" + create_another: "Criar outro %{model}" + new_model: "Novo(a) %{model}" + edit_model: "Editar %{model}" + delete_model: "Remover %{model}" + details: "Detalhes do(a) %{model}" + cancel: "Cancelar" + empty: "Vazio" + previous: "Anterior" + next: "Próximo" + download: "Baixar:" + has_many_new: "Adicionar Novo(a) %{model}" + has_many_delete: "Remover" + has_many_remove: "Remover" + filters: + buttons: + filter: "Filtrar" + clear: "Limpar Filtros" + predicates: + contains: "Contém" + equals: "Igual A" + starts_with: "Começa com" + ends_with: "Termina com" + greater_than: "Maior Que" + less_than: "Menor Que" + gteq_datetime: "Maior ou igual a" + lteq_datetime: "Menor ou igual a" + from: "A partir de" + to: "Até" + search_status: + headline: "Buscou:" + current_scope: "Em:" + current_filters: "Filtros escolhidos:" + no_current_filters: "Nenhum" + status_tag: + "yes": "Sim" + "no": "Não" + "unset": "Não" + main_content: "Por favor implemente %{model}#main_content para exibir conteúdo." + logout: "Sair" + powered_by: "Powered by %{active_admin} %{version}" + sidebars: + filters: "Filtros" + search_status: "Buscou" + pagination: + empty: "Nenhum(a) %{model} encontrado(a)" + one: "Exibindo 1 %{model}" + one_page: "Exibindo todos(as) os(as) %{n} %{model}" + multiple: "Exibindo %{model} %{from} - %{to} de um total de %{total}" + multiple_without_total: "Exibindo %{model} %{from} - %{to}" + per_page: "Por página: " + entry: + one: "registro" + other: "registros" + any: "Qualquer" + blank_slate: + content: "Não existem %{resource_name} ainda." + link: "Novo" + dropdown_actions: + button_label: "Ações" + batch_actions: + button_label: "Ações em lote" + default_confirmation: "Tem certeza que quer fazer isso?" + delete_confirmation: "Tem certeza que deseja excluir estes %{plural_model}?" + succesfully_destroyed: + one: "Excluiu com sucesso 1 %{model}" + other: "Excluiu com sucesso %{count} %{plural_model}" + selection_toggle_explanation: "(Alternar Seleção)" + action_label: "%{title} Selecionado" + labels: + destroy: "Excluir" + comments: + created_at: "Criado em" + resource_type: "Tipo de Objeto" + author_type: "Tipo de Autor" + body: "Conteúdo" + author: "Autor" + add: "Adicionar Comentário" + delete: "Deletar comentário" + delete_confirmation: "Tem certeza que deseja excluir este comentário?" + resource: "Objeto" + no_comments_yet: "Nenhum comentário." + author_missing: "Anônimo" + title_content: "Comentários: %{count}" + errors: + empty_text: "O comentário não foi salvo porque o texto estava vazio." + devise: + username: + title: "Nome de Usuário" + email: + title: "E-mail" + subdomain: + title: "Subdomínio" + password: + title: "Senha" + password_confirmation: + title: "Confirmação de senha" + sign_up: + title: "Cadastre-se" + submit: "Continuar" + login: + title: "Conta" + remember_me: "Lembrar da senha" + submit: "Entrar" + reset_password: + title: "Esqueceu sua senha?" + submit: "Reinicie minha senha" + change_password: + title: "Troque sua senha" + submit: "Troque minha senha" + unlock: + title: "Reenviar instruções de desbloqueio" + submit: "Reenviar instruções de desbloqueio" + resend_confirmation_instructions: + title: "Reenviar instruções de confirmação" + submit: "Reenviar instruções de confirmação" + links: + sign_up: "Criar conta" + sign_in: "Entrar" + forgot_your_password: "Esqueceu sua senha?" + sign_in_with_omniauth_provider: "Entre com o %{provider}" + resend_unlock_instructions: "Reenviar instruções de desbloqueio" + resend_confirmation_instructions: "Reenviar instruções de confirmação" + unsupported_browser: + headline: "O ActiveAdmin não oferece suporte ao Internet Explorer versão 8 ou inferior." + recommendation: "Nós recomendamos atualizar para a última versão do Internet Explorer, Google Chrome, ou Firefox." + turn_off_compatibility_view: "Se você está usando o IE 9 ou superior, desligue o \"Modo de Exibição de Compatibilidade\"." + access_denied: + message: "Você não tem permissão para realizar o solicitado" + index_list: + table: "Tabela" + block: "Lista" + grid: "Grid" + blog: "Blog" \ No newline at end of file diff --git a/config/routes.rb b/config/routes.rb index d9cf4bf..d2c385d 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -10,7 +10,11 @@ Rails.application.routes.draw do post "/graphql", to: "graphql#execute" - ActiveAdmin.routes(self) + + authenticate :user, ->(u) { u.admin? } do + ActiveAdmin.routes(self) + end + if Rails.env.development? mount GraphqlPlayground::Rails::Engine, at: "/playground", graphql_path: "/graphql" diff --git a/db/migrate/20220725224431_add_roles_to_user.rb b/db/migrate/20220725224431_add_roles_to_user.rb new file mode 100644 index 0000000..ac81403 --- /dev/null +++ b/db/migrate/20220725224431_add_roles_to_user.rb @@ -0,0 +1,5 @@ +class AddRolesToUser < ActiveRecord::Migration[7.0] + def change + add_column(:users, :roles, :string, array: true, null: true, default: []) + end +end diff --git a/db/migrate/20220725225343_drop_roles.rb b/db/migrate/20220725225343_drop_roles.rb new file mode 100644 index 0000000..3760387 --- /dev/null +++ b/db/migrate/20220725225343_drop_roles.rb @@ -0,0 +1,5 @@ +class DropRoles < ActiveRecord::Migration[7.0] + def change + drop_table :roles + end +end diff --git a/db/schema.rb b/db/schema.rb index f622139..00eeb43 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.0].define(version: 2022_07_22_153417) do +ActiveRecord::Schema[7.0].define(version: 2022_07_25_225343) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -118,13 +118,6 @@ ActiveRecord::Schema[7.0].define(version: 2022_07_22_153417) do t.index ["user_id"], name: "index_review_requests_on_user_id" end - create_table "roles", force: :cascade do |t| - t.string "name" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false - t.index ["name"], name: "index_roles_on_name", unique: true - end - create_table "roles_users", id: false, force: :cascade do |t| t.bigint "user_id", null: false t.bigint "role_id", null: false @@ -153,6 +146,7 @@ ActiveRecord::Schema[7.0].define(version: 2022_07_22_153417) do t.datetime "created_at", null: false t.datetime "updated_at", null: false t.string "avatar_url" + t.string "roles", default: [], array: true t.index ["email"], name: "index_users_on_email", unique: true t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true end diff --git a/spec/factories/roles.rb b/spec/factories/roles.rb deleted file mode 100644 index d06efc0..0000000 --- a/spec/factories/roles.rb +++ /dev/null @@ -1,18 +0,0 @@ -# == Schema Information -# -# Table name: roles -# -# id :bigint not null, primary key -# name :string -# created_at :datetime not null -# updated_at :datetime not null -# -# Indexes -# -# index_roles_on_name (name) UNIQUE -# -FactoryBot.define do - factory :role do - - end -end diff --git a/spec/factories/users.rb b/spec/factories/users.rb index 62ad826..bbddcec 100644 --- a/spec/factories/users.rb +++ b/spec/factories/users.rb @@ -10,6 +10,7 @@ # remember_created_at :datetime # reset_password_sent_at :datetime # reset_password_token :string +# roles :string default([]), is an Array # created_at :datetime not null # updated_at :datetime not null # diff --git a/spec/models/role_spec.rb b/spec/models/role_spec.rb deleted file mode 100644 index 6f65c40..0000000 --- a/spec/models/role_spec.rb +++ /dev/null @@ -1,18 +0,0 @@ -# == Schema Information -# -# Table name: roles -# -# id :bigint not null, primary key -# name :string -# created_at :datetime not null -# updated_at :datetime not null -# -# Indexes -# -# index_roles_on_name (name) UNIQUE -# -require 'rails_helper' - -RSpec.describe Role, type: :model do - pending "add some examples to (or delete) #{__FILE__}" -end diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index b150fb6..3daa4a6 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -10,6 +10,7 @@ # remember_created_at :datetime # reset_password_sent_at :datetime # reset_password_token :string +# roles :string default([]), is an Array # created_at :datetime not null # updated_at :datetime not null #