From 348a6d16a229edf6242845867218b91eb73ca0d2 Mon Sep 17 00:00:00 2001 From: oscar Date: Fri, 6 Oct 2017 16:08:31 -0500 Subject: [PATCH] Add a password field type. * New Field::Password * Modify the Customer Dashboard to show new field * Add field information in Customizing Dashboards documentation --- app/views/fields/password/_form.html.erb | 23 +++++++ app/views/fields/password/_index.html.erb | 18 +++++ app/views/fields/password/_show.html.erb | 18 +++++ docs/customizing_dashboards.md | 12 ++++ lib/administrate/base_dashboard.rb | 1 + lib/administrate/field/password.rb | 25 +++++++ .../app/dashboards/customer_dashboard.rb | 4 +- ...0171006144755_add_password_to_customers.rb | 5 ++ spec/example_app/db/schema.rb | 1 + spec/example_app/db/seeds.rb | 1 + spec/lib/fields/password_spec.rb | 65 +++++++++++++++++++ 11 files changed, 172 insertions(+), 1 deletion(-) create mode 100644 app/views/fields/password/_form.html.erb create mode 100644 app/views/fields/password/_index.html.erb create mode 100644 app/views/fields/password/_show.html.erb create mode 100644 lib/administrate/field/password.rb create mode 100644 spec/example_app/db/migrate/20171006144755_add_password_to_customers.rb create mode 100644 spec/lib/fields/password_spec.rb diff --git a/app/views/fields/password/_form.html.erb b/app/views/fields/password/_form.html.erb new file mode 100644 index 0000000000..0786fa2eef --- /dev/null +++ b/app/views/fields/password/_form.html.erb @@ -0,0 +1,23 @@ +<%# +# Password Form Partial + +This partial renders an input element for a password attribute. +By default, the input is a password field. + +## Local variables: + +- `f`: + A Rails form generator, used to help create the appropriate input fields. +- `field`: + An instance of [Administrate::Field::Password][1]. + A wrapper around the Password. + +[1]: http://www.rubydoc.info/gems/administrate/Administrate/Field/Password +%> + +
+ <%= f.label field.attribute %> +
+
+ <%= f.password_field field.attribute, value: field.data %> +
diff --git a/app/views/fields/password/_index.html.erb b/app/views/fields/password/_index.html.erb new file mode 100644 index 0000000000..afff005708 --- /dev/null +++ b/app/views/fields/password/_index.html.erb @@ -0,0 +1,18 @@ +<%# +# Password Index Partial + +This partial renders a password attribute +to be displayed on a resource's index page. + +By default, the attribute is rendered as a truncated string. + +## Local variables: + +- `field`: + An instance of [Administrate::Field::Password][1]. + A wrapper around the Password. + +[1]: http://www.rubydoc.info/gems/administrate/Administrate/Field/Password +%> + +<%= field.truncate %> diff --git a/app/views/fields/password/_show.html.erb b/app/views/fields/password/_show.html.erb new file mode 100644 index 0000000000..84e52bd63d --- /dev/null +++ b/app/views/fields/password/_show.html.erb @@ -0,0 +1,18 @@ +<%# +# Password Show Partial + +This partial renders a password attribute, +to be displayed on a resource's show page. + +By default, the attribute is rendered as an truncate string. + +## Local variables: + +- `field`: + An instance of [Administrate::Field::Password][1]. + A wrapper around the Password. + +[1]: http://www.rubydoc.info/gems/administrate/Administrate/Field/Password +%> + +<%= field.truncate %> diff --git a/docs/customizing_dashboards.md b/docs/customizing_dashboards.md index e89ce41c81..7d9987be56 100644 --- a/docs/customizing_dashboards.md +++ b/docs/customizing_dashboards.md @@ -62,6 +62,7 @@ specify, including: - `Field::Select` - `Field::String` - `Field::Text` +- `Field::Password` ## Customizing Fields @@ -158,6 +159,17 @@ Default is `false`. `:truncate` - Set the number of characters to display in the index view. Defaults to `50`. +**Field::Password** + +`:searchable` - Specify if the attribute should be considered when searching. +Default is `false`. + +`:truncate` - Set the number of characters to display in the views. +Defaults to `50`. + +`:character` - Set the replace character. +Defaults to `•`. + ### Defining Labels To change the user-facing label for an attribute, diff --git a/lib/administrate/base_dashboard.rb b/lib/administrate/base_dashboard.rb index 5b4345c3fb..46215fc9ad 100644 --- a/lib/administrate/base_dashboard.rb +++ b/lib/administrate/base_dashboard.rb @@ -10,6 +10,7 @@ require "administrate/field/string" require "administrate/field/text" require "administrate/field/time" +require "administrate/field/password" module Administrate class BaseDashboard diff --git a/lib/administrate/field/password.rb b/lib/administrate/field/password.rb new file mode 100644 index 0000000000..21fc0be5aa --- /dev/null +++ b/lib/administrate/field/password.rb @@ -0,0 +1,25 @@ +require_relative "base" + +module Administrate + module Field + class Password < Field::Base + def self.searchable? + false + end + + def truncate + data.to_s.gsub(/./, character)[0...truncation_length] + end + + private + + def truncation_length + options.fetch(:truncate, 50) + end + + def character + options.fetch(:character, "•") + end + end + end +end diff --git a/spec/example_app/app/dashboards/customer_dashboard.rb b/spec/example_app/app/dashboards/customer_dashboard.rb index fe9323a495..22e932f483 100644 --- a/spec/example_app/app/dashboards/customer_dashboard.rb +++ b/spec/example_app/app/dashboards/customer_dashboard.rb @@ -12,9 +12,10 @@ class CustomerDashboard < Administrate::BaseDashboard kind: Field::Select.with_options(collection: Customer::KINDS), country: Field::BelongsTo. with_options(primary_key: :code, foreign_key: :country_code), + password: Field::Password, } - COLLECTION_ATTRIBUTES = ATTRIBUTE_TYPES.keys + COLLECTION_ATTRIBUTES = ATTRIBUTE_TYPES.keys - %i[created_at updated_at] SHOW_PAGE_ATTRIBUTES = ATTRIBUTE_TYPES.keys - [:name] FORM_ATTRIBUTES = [ :name, @@ -22,6 +23,7 @@ class CustomerDashboard < Administrate::BaseDashboard :email_subscriber, :kind, :country, + :password, ].freeze def display_resource(customer) diff --git a/spec/example_app/db/migrate/20171006144755_add_password_to_customers.rb b/spec/example_app/db/migrate/20171006144755_add_password_to_customers.rb new file mode 100644 index 0000000000..bebae8a81b --- /dev/null +++ b/spec/example_app/db/migrate/20171006144755_add_password_to_customers.rb @@ -0,0 +1,5 @@ +class AddPasswordToCustomers < ActiveRecord::Migration[4.2] + def change + add_column :customers, :password, :string + end +end diff --git a/spec/example_app/db/schema.rb b/spec/example_app/db/schema.rb index 1829722c7b..36292ac3fc 100644 --- a/spec/example_app/db/schema.rb +++ b/spec/example_app/db/schema.rb @@ -39,6 +39,7 @@ t.boolean "email_subscriber" t.string "kind", default: "standard", null: false t.string "country_code" + t.string "password" end create_table "delayed_jobs", id: :serial, force: :cascade do |t| diff --git a/spec/example_app/db/seeds.rb b/spec/example_app/db/seeds.rb index 91a9a2ca57..e151fa82a1 100644 --- a/spec/example_app/db/seeds.rb +++ b/spec/example_app/db/seeds.rb @@ -29,6 +29,7 @@ name: name, email: Faker::Internet.safe_email(name), country: countries.sample, + password: Faker::Internet.password, } end diff --git a/spec/lib/fields/password_spec.rb b/spec/lib/fields/password_spec.rb new file mode 100644 index 0000000000..36ec3da12c --- /dev/null +++ b/spec/lib/fields/password_spec.rb @@ -0,0 +1,65 @@ +require "administrate/field/password" +require "support/field_matchers" + +describe Administrate::Field::Password do + include FieldMatchers + + describe "#to_partial_path" do + it "returns a partial based on the page being rendered" do + page = :show + field = Administrate::Field::Password.new(:password, "my_password", page) + + path = field.to_partial_path + + expect(path).to eq("/fields/password/#{page}") + end + end + + it { should_permit_param(:foo, for_attribute: :foo) } + + describe "#truncate" do + it "renders an empty string for nil" do + string = Administrate::Field::Password.new(:secret, nil, :show) + + expect(string.truncate).to eq("") + end + + it "defaults to displaying up to 50 characters" do + short = Administrate::Field::Password.new(:short_secret, lorem(30), :show) + long = Administrate::Field::Password.new(:long_secret, lorem(60), :show) + + expect(short.truncate).to eq(lorem(30)) + expect(long.truncate).to eq(lorem(50)) + end + + context "with a `truncate` option" do + it "shortens to the given length" do + password = password_with_options(lorem(30), truncate: 20) + + expect(password.truncate).to eq(lorem(20)) + end + + it "different to default character" do + password = password_with_options(lorem(30), character: "*") + + expect(password.truncate).to eq(lorem(30, "*")) + end + + it "shortens to the given length & different to default character" do + password = password_with_options(lorem(30), + truncate: 10, + character: "-") + + expect(password.truncate).to eq(lorem(10, "-")) + end + end + end + + def password_with_options(string, options) + Administrate::Field::Password.new(:string, string, :page, options) + end + + def lorem(n, character = "•") + character * n + end +end