diff --git a/app/models/user_allowed_guard.rb b/app/models/user_allowed_guard.rb new file mode 100644 index 0000000..a3f0084 --- /dev/null +++ b/app/models/user_allowed_guard.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +class UserAllowedGuard < Clearance::SignInGuard + def call + return next_guard if !signed_in? || allowed? + + failure('Your user is banned.') + end + + def allowed? + !current_user.banned? + end +end diff --git a/config/initializers/clearance.rb b/config/initializers/clearance.rb index 381138e..1c8c6a8 100644 --- a/config/initializers/clearance.rb +++ b/config/initializers/clearance.rb @@ -4,4 +4,5 @@ config.routes = false config.mailer_sender = 'no-reply@openjobs.me' config.rotate_csrf_on_sign_in = true + config.sign_in_guards = [UserAllowedGuard] end diff --git a/config/rails_best_practices.yml b/config/rails_best_practices.yml index 7a960a6..c978c3a 100644 --- a/config/rails_best_practices.yml +++ b/config/rails_best_practices.yml @@ -25,7 +25,7 @@ RemoveEmptyHelpersCheck: { } RemoveTrailingWhitespaceCheck: { } RemoveUnusedMethodsInControllersCheck: { except_methods: ['UsersController#user_params'] } RemoveUnusedMethodsInHelpersCheck: { except_methods: [] } -RemoveUnusedMethodsInModelsCheck: { except_methods: ['Vacancy#slug_candidates'] } +RemoveUnusedMethodsInModelsCheck: { except_methods: ['Vacancy#slug_candidates', 'UserAllowedGuard#call'] } ReplaceComplexCreationWithFactoryMethodCheck: { attribute_assignment_count: 2 } ReplaceInstanceVariableWithLocalVariableCheck: { ignored_files: 'app/views/users/_form.html.erb' } #RestrictAutoGeneratedRoutesCheck: { } diff --git a/db/migrate/20191024195622_add_banned_to_users.rb b/db/migrate/20191024195622_add_banned_to_users.rb new file mode 100644 index 0000000..cbf1a6d --- /dev/null +++ b/db/migrate/20191024195622_add_banned_to_users.rb @@ -0,0 +1,5 @@ +class AddBannedToUsers < ActiveRecord::Migration[5.2] + def change + add_column :users, :banned, :boolean, null: false, default: false + end +end diff --git a/db/structure.sql b/db/structure.sql index 97af91a..a0d75aa 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -1,28 +1,21 @@ +-- +-- PostgreSQL database dump +-- + +-- Dumped from database version 11.5 (Debian 11.5-1.pgdg90+1) +-- Dumped by pg_dump version 11.3 + SET statement_timeout = 0; SET lock_timeout = 0; SET idle_in_transaction_session_timeout = 0; SET client_encoding = 'UTF8'; SET standard_conforming_strings = on; +SELECT pg_catalog.set_config('search_path', '', false); SET check_function_bodies = false; +SET xmloption = content; SET client_min_messages = warning; SET row_security = off; --- --- Name: plpgsql; Type: EXTENSION; Schema: -; Owner: - --- - -CREATE EXTENSION IF NOT EXISTS plpgsql WITH SCHEMA pg_catalog; - - --- --- Name: EXTENSION plpgsql; Type: COMMENT; Schema: -; Owner: - --- - -COMMENT ON EXTENSION plpgsql IS 'PL/pgSQL procedural language'; - - -SET search_path = public, pg_catalog; - SET default_tablespace = ''; SET default_with_oids = false; @@ -31,7 +24,7 @@ SET default_with_oids = false; -- Name: ar_internal_metadata; Type: TABLE; Schema: public; Owner: - -- -CREATE TABLE ar_internal_metadata ( +CREATE TABLE public.ar_internal_metadata ( key character varying NOT NULL, value character varying, created_at timestamp without time zone NOT NULL, @@ -43,13 +36,14 @@ CREATE TABLE ar_internal_metadata ( -- Name: companies; Type: TABLE; Schema: public; Owner: - -- -CREATE TABLE companies ( +CREATE TABLE public.companies ( id bigint NOT NULL, name character varying, url character varying, created_at timestamp without time zone NOT NULL, updated_at timestamp without time zone NOT NULL, - company_tsv tsvector + company_tsv tsvector, + domain character varying ); @@ -57,7 +51,7 @@ CREATE TABLE companies ( -- Name: companies_id_seq; Type: SEQUENCE; Schema: public; Owner: - -- -CREATE SEQUENCE companies_id_seq +CREATE SEQUENCE public.companies_id_seq START WITH 1 INCREMENT BY 1 NO MINVALUE @@ -69,14 +63,14 @@ CREATE SEQUENCE companies_id_seq -- Name: companies_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - -- -ALTER SEQUENCE companies_id_seq OWNED BY companies.id; +ALTER SEQUENCE public.companies_id_seq OWNED BY public.companies.id; -- -- Name: schema_migrations; Type: TABLE; Schema: public; Owner: - -- -CREATE TABLE schema_migrations ( +CREATE TABLE public.schema_migrations ( version character varying NOT NULL ); @@ -85,7 +79,7 @@ CREATE TABLE schema_migrations ( -- Name: users; Type: TABLE; Schema: public; Owner: - -- -CREATE TABLE users ( +CREATE TABLE public.users ( id bigint NOT NULL, created_at timestamp without time zone NOT NULL, updated_at timestamp without time zone NOT NULL, @@ -93,7 +87,8 @@ CREATE TABLE users ( encrypted_password character varying(128) NOT NULL, confirmation_token character varying(128), remember_token character varying(128) NOT NULL, - company_id integer + company_id integer, + banned boolean DEFAULT false NOT NULL ); @@ -101,7 +96,7 @@ CREATE TABLE users ( -- Name: users_id_seq; Type: SEQUENCE; Schema: public; Owner: - -- -CREATE SEQUENCE users_id_seq +CREATE SEQUENCE public.users_id_seq START WITH 1 INCREMENT BY 1 NO MINVALUE @@ -113,14 +108,14 @@ CREATE SEQUENCE users_id_seq -- Name: users_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - -- -ALTER SEQUENCE users_id_seq OWNED BY users.id; +ALTER SEQUENCE public.users_id_seq OWNED BY public.users.id; -- -- Name: vacancies; Type: TABLE; Schema: public; Owner: - -- -CREATE TABLE vacancies ( +CREATE TABLE public.vacancies ( id integer NOT NULL, job_title character varying, location character varying, @@ -138,7 +133,8 @@ CREATE TABLE vacancies ( -- Name: vacancies_id_seq; Type: SEQUENCE; Schema: public; Owner: - -- -CREATE SEQUENCE vacancies_id_seq +CREATE SEQUENCE public.vacancies_id_seq + AS integer START WITH 1 INCREMENT BY 1 NO MINVALUE @@ -150,35 +146,35 @@ CREATE SEQUENCE vacancies_id_seq -- Name: vacancies_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - -- -ALTER SEQUENCE vacancies_id_seq OWNED BY vacancies.id; +ALTER SEQUENCE public.vacancies_id_seq OWNED BY public.vacancies.id; -- -- Name: companies id; Type: DEFAULT; Schema: public; Owner: - -- -ALTER TABLE ONLY companies ALTER COLUMN id SET DEFAULT nextval('companies_id_seq'::regclass); +ALTER TABLE ONLY public.companies ALTER COLUMN id SET DEFAULT nextval('public.companies_id_seq'::regclass); -- -- Name: users id; Type: DEFAULT; Schema: public; Owner: - -- -ALTER TABLE ONLY users ALTER COLUMN id SET DEFAULT nextval('users_id_seq'::regclass); +ALTER TABLE ONLY public.users ALTER COLUMN id SET DEFAULT nextval('public.users_id_seq'::regclass); -- -- Name: vacancies id; Type: DEFAULT; Schema: public; Owner: - -- -ALTER TABLE ONLY vacancies ALTER COLUMN id SET DEFAULT nextval('vacancies_id_seq'::regclass); +ALTER TABLE ONLY public.vacancies ALTER COLUMN id SET DEFAULT nextval('public.vacancies_id_seq'::regclass); -- -- Name: ar_internal_metadata ar_internal_metadata_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- -ALTER TABLE ONLY ar_internal_metadata +ALTER TABLE ONLY public.ar_internal_metadata ADD CONSTRAINT ar_internal_metadata_pkey PRIMARY KEY (key); @@ -186,7 +182,7 @@ ALTER TABLE ONLY ar_internal_metadata -- Name: companies companies_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- -ALTER TABLE ONLY companies +ALTER TABLE ONLY public.companies ADD CONSTRAINT companies_pkey PRIMARY KEY (id); @@ -194,7 +190,7 @@ ALTER TABLE ONLY companies -- Name: schema_migrations schema_migrations_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- -ALTER TABLE ONLY schema_migrations +ALTER TABLE ONLY public.schema_migrations ADD CONSTRAINT schema_migrations_pkey PRIMARY KEY (version); @@ -202,7 +198,7 @@ ALTER TABLE ONLY schema_migrations -- Name: users users_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- -ALTER TABLE ONLY users +ALTER TABLE ONLY public.users ADD CONSTRAINT users_pkey PRIMARY KEY (id); @@ -210,7 +206,7 @@ ALTER TABLE ONLY users -- Name: vacancies vacancies_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- -ALTER TABLE ONLY vacancies +ALTER TABLE ONLY public.vacancies ADD CONSTRAINT vacancies_pkey PRIMARY KEY (id); @@ -221,6 +217,13 @@ ALTER TABLE ONLY vacancies CREATE INDEX index_companies_on_company_tsv ON public.companies USING gin (company_tsv); +-- +-- Name: index_companies_on_domain; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_companies_on_domain ON public.companies USING btree (domain); + + -- -- Name: index_users_on_company_id; Type: INDEX; Schema: public; Owner: - -- @@ -288,18 +291,3 @@ CREATE TRIGGER vacancies_tsvectorupdate BEFORE INSERT OR UPDATE ON public.vacanc -- PostgreSQL database dump complete -- -SET search_path TO "$user", public; - -INSERT INTO "schema_migrations" (version) VALUES -('20170222022125'), -('20170304231833'), -('20170314043437'), -('20170329184143'), -('20180216223455'), -('20180220224847'), -('20180220231334'), -('20180220232910'), -('20180221233924'), -('20180305210520'); - - diff --git a/spec/features/banned_user_sign_in_spec.rb b/spec/features/banned_user_sign_in_spec.rb new file mode 100644 index 0000000..90a71ff --- /dev/null +++ b/spec/features/banned_user_sign_in_spec.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.feature 'Signing in with a Banned User' do + scenario 'does not allow banned user to sign in' do + create(:user, email: 'banned@user.com', password: 'password', banned: true) + + visit sign_in_path + + fill_in 'E-mail', with: 'banned@user.com' + fill_in 'Password', with: 'password' + + click_button 'Sign in' + + expect(page).to have_text 'Your user is banned.' + end + + scenario 'allows unbanned user to sign in' do + create(:user, email: 'unbanned@user.com', password: 'password', banned: false) + + visit sign_in_path + + fill_in 'E-mail', with: 'unbanned@user.com' + fill_in 'Password', with: 'password' + + click_button 'Sign in' + + expect(page).not_to have_text 'Your user is banned.' + end +end