From f46264873e492d2f670b1cdc6c6e7996ed8a93d1 Mon Sep 17 00:00:00 2001 From: ElliottAYoung Date: Mon, 17 Apr 2017 13:50:03 -0500 Subject: [PATCH 01/18] feat: install flipper gems --- Gemfile | 5 +++++ Gemfile.lock | 12 ++++++++++++ 2 files changed, 17 insertions(+) diff --git a/Gemfile b/Gemfile index 0474869c8..b6adbefce 100644 --- a/Gemfile +++ b/Gemfile @@ -103,6 +103,11 @@ gem 'ng-rails-csrf', '~> 0.1.0' gem 'bootstrap-tagsinput-rails', '~> 0.4.2' gem 'dialog-polyfill-rails', '~> 0.4.5' +# Feature Flagging +gem 'flipper', '~> 0.10' +gem 'flipper-ui', '~> 0.10' +gem 'flipper-active_record', '~> 0.10' + group :tasks do # Parsing gem 'nokogiri' diff --git a/Gemfile.lock b/Gemfile.lock index 89f0b9be5..137001d14 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -208,6 +208,15 @@ GEM ffi (1.9.17) fission (0.5.0) CFPropertyList (~> 2.2) + flipper (0.10.2) + flipper-active_record (0.10.2) + activerecord (>= 3.2, < 6) + flipper (~> 0.10.2) + flipper-ui (0.10.2) + erubis (~> 2.7.0) + flipper (~> 0.10.2) + rack (>= 1.4, < 3) + rack-protection (>= 1.5.3, < 2.1.0) fog (1.38.0) fog-aliyun (>= 0.1.0) fog-atmos @@ -739,6 +748,9 @@ DEPENDENCIES excon (~> 0.55.0) factory_girl_rails (~> 4.8) faker (~> 1.7) + flipper (~> 0.10) + flipper-active_record (~> 0.10) + flipper-ui (~> 0.10) fog (~> 1.38.0) font-awesome-sass (~> 4.7.0) foreman From af75a0aba5668d5dc1159d6eb37ca6ea57a9c4e1 Mon Sep 17 00:00:00 2001 From: ElliottAYoung Date: Mon, 17 Apr 2017 13:50:11 -0500 Subject: [PATCH 02/18] chore: add flipper initializer --- config/initializers/flipper.rb | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 config/initializers/flipper.rb diff --git a/config/initializers/flipper.rb b/config/initializers/flipper.rb new file mode 100644 index 000000000..273848d1f --- /dev/null +++ b/config/initializers/flipper.rb @@ -0,0 +1,5 @@ +module Cortex + def self.flipper + @flipper ||= Flipper.new(Flipper::Adapters::ActiveRecord.new) + end +end From be5d121519e783232b9df492e40c82dbcaea1c3f Mon Sep 17 00:00:00 2001 From: ElliottAYoung Date: Mon, 17 Apr 2017 13:59:50 -0500 Subject: [PATCH 03/18] feat: build in config logic for Flipper --- config/application.rb | 10 ++++++++++ config/routes.rb | 8 ++++++++ 2 files changed, 18 insertions(+) diff --git a/config/application.rb b/config/application.rb index 2587cfa20..ad72f9fb4 100644 --- a/config/application.rb +++ b/config/application.rb @@ -40,5 +40,15 @@ class Application < Rails::Application # Needed until there is a better fix for Paperclip. https://github.com/thoughtbot/paperclip/issues/1924#issuecomment-123927367 Paperclip.options[:content_type_mappings] = {:csv => 'text/plain'} + + config.middleware.use Flipper::Middleware::Memoizer, lambda { + Cortex.flipper + } + + Flipper.register(:internal) { |request| request.internal? } + Flipper.register(:authenticated) { |request| request.session[:current_user].present? && request.session[:current_user][:authenticated] } + Flipper.register(:hiring_dot) { |request| request.host == 'admin.cbcortex.com' } + Flipper.register(:dev) { |request| request.host == 'dev.admin.cbcortex.com' || request.host == 'localhost' } + Flipper.register(:staging) { |request| request.host == 'stg.admin.cbcortex.com' } end end diff --git a/config/routes.rb b/config/routes.rb index 7babd0022..cccd95da4 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -35,4 +35,12 @@ # API ::API.logger Rails.logger mount ::API => '/api' + + # Flipper + authenticated :user, lambda {|u| u.is_admin? } do + flipper_block = lambda { + Cortex.flipper + } + mount Flipper::UI.app(flipper_block) => '/flipper' + end end From 9075917d7023d023d420a30c3216f7dac45c7706 Mon Sep 17 00:00:00 2001 From: ElliottAYoung Date: Mon, 17 Apr 2017 14:00:30 -0500 Subject: [PATCH 04/18] chore: run generated flipper migration --- .../20170417185915_create_flipper_tables.rb | 22 +++ db/schema.rb | 178 +++++++++--------- 2 files changed, 114 insertions(+), 86 deletions(-) create mode 100644 db/migrate/20170417185915_create_flipper_tables.rb diff --git a/db/migrate/20170417185915_create_flipper_tables.rb b/db/migrate/20170417185915_create_flipper_tables.rb new file mode 100644 index 000000000..5041e1f31 --- /dev/null +++ b/db/migrate/20170417185915_create_flipper_tables.rb @@ -0,0 +1,22 @@ +class CreateFlipperTables < ActiveRecord::Migration + def self.up + create_table :flipper_features do |t| + t.string :key, null: false + t.timestamps null: false + end + add_index :flipper_features, :key, unique: true + + create_table :flipper_gates do |t| + t.string :feature_key, null: false + t.string :key, null: false + t.string :value + t.timestamps null: false + end + add_index :flipper_gates, [:feature_key, :key, :value], unique: true + end + + def self.down + drop_table :flipper_gates + drop_table :flipper_features + end +end diff --git a/db/schema.rb b/db/schema.rb index bc50594c9..db1c93dc3 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.define(version: 20170327182543) do +ActiveRecord::Schema.define(version: 20170417185915) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -58,19 +58,14 @@ end create_table "categories", force: :cascade do |t| - t.string "name" - t.integer "user_id", null: false + t.string "name", limit: 255 + t.integer "user_id", null: false t.integer "parent_id" t.integer "lft" t.integer "rgt" t.integer "depth" t.datetime "created_at" t.datetime "updated_at" - t.index ["depth"], name: "index_categories_on_depth", using: :btree - t.index ["lft"], name: "index_categories_on_lft", using: :btree - t.index ["parent_id"], name: "index_categories_on_parent_id", using: :btree - t.index ["rgt"], name: "index_categories_on_rgt", using: :btree - t.index ["user_id"], name: "index_categories_on_user_id", using: :btree end create_table "categories_posts", id: false, force: :cascade do |t| @@ -175,6 +170,22 @@ t.index ["id"], name: "index_fields_on_id", using: :btree end + create_table "flipper_features", force: :cascade do |t| + t.string "key", null: false + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index ["key"], name: "index_flipper_features_on_key", unique: true, using: :btree + end + + create_table "flipper_gates", force: :cascade do |t| + t.string "feature_key", null: false + t.string "key", null: false + t.string "value" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index ["feature_key", "key", "value"], name: "index_flipper_gates_on_feature_key_and_key_and_value", unique: true, using: :btree + end + create_table "locales", id: :uuid, default: -> { "uuid_generate_v4()" }, force: :cascade do |t| t.string "name", null: false t.integer "localization_id" @@ -197,24 +208,23 @@ end create_table "media", force: :cascade do |t| - t.string "name" + t.string "name", limit: 255 t.integer "user_id" - t.string "attachment_file_name" - t.string "attachment_content_type" + t.string "attachment_file_name", limit: 255 + t.string "attachment_content_type", limit: 255 t.integer "attachment_file_size" t.datetime "attachment_updated_at" - t.string "dimensions" + t.string "dimensions", limit: 255 t.text "description" - t.string "alt" + t.string "alt", limit: 255 t.boolean "active" t.datetime "deactive_at" t.datetime "created_at" t.datetime "updated_at" - t.string "digest" + t.string "digest", limit: 255 t.datetime "deleted_at" t.hstore "meta" - t.string "type", default: "Media", null: false - t.index ["name"], name: "index_media_on_name", using: :btree + t.string "type", limit: 255, default: "Media", null: false t.index ["user_id"], name: "index_media_on_user_id", using: :btree end @@ -224,48 +234,48 @@ end create_table "oauth_access_grants", force: :cascade do |t| - t.integer "resource_owner_id", null: false - t.integer "application_id", null: false - t.string "token", null: false - t.integer "expires_in", null: false - t.text "redirect_uri", null: false - t.datetime "created_at", null: false + t.integer "resource_owner_id", null: false + t.integer "application_id", null: false + t.string "token", limit: 255, null: false + t.integer "expires_in", null: false + t.text "redirect_uri", null: false + t.datetime "created_at", null: false t.datetime "revoked_at" - t.string "scopes" + t.string "scopes", limit: 255 t.index ["token"], name: "index_oauth_access_grants_on_token", unique: true, using: :btree end create_table "oauth_access_tokens", force: :cascade do |t| t.integer "resource_owner_id" t.integer "application_id" - t.string "token", null: false - t.string "refresh_token" + t.string "token", limit: 255, null: false + t.string "refresh_token", limit: 255 t.integer "expires_in" t.datetime "revoked_at" - t.datetime "created_at", null: false - t.string "scopes" + t.datetime "created_at", null: false + t.string "scopes", limit: 255 t.index ["refresh_token"], name: "index_oauth_access_tokens_on_refresh_token", unique: true, using: :btree t.index ["resource_owner_id"], name: "index_oauth_access_tokens_on_resource_owner_id", using: :btree t.index ["token"], name: "index_oauth_access_tokens_on_token", unique: true, using: :btree end create_table "oauth_applications", force: :cascade do |t| - t.string "name", null: false - t.string "uid", null: false - t.string "secret", null: false - t.text "redirect_uri", null: false + t.string "name", limit: 255, null: false + t.string "uid", limit: 255, null: false + t.string "secret", limit: 255, null: false + t.text "redirect_uri", null: false t.datetime "created_at" t.datetime "updated_at" t.integer "owner_id" - t.string "owner_type" - t.string "scopes", default: "", null: false + t.string "owner_type", limit: 255 + t.string "scopes", default: "", null: false t.index ["owner_id", "owner_type"], name: "index_oauth_applications_on_owner_id_and_owner_type", using: :btree t.index ["uid"], name: "index_oauth_applications_on_uid", unique: true, using: :btree end create_table "onet_occupations", force: :cascade do |t| - t.string "soc" - t.string "title" + t.string "soc", limit: 255 + t.string "title", limit: 255 t.text "description" t.datetime "created_at" t.datetime "updated_at" @@ -285,45 +295,44 @@ end create_table "posts", force: :cascade do |t| - t.integer "user_id", null: false - t.string "title" + t.integer "user_id", null: false + t.string "title", limit: 255 t.datetime "published_at" t.datetime "expired_at" t.datetime "deleted_at" - t.boolean "draft", default: true, null: false - t.integer "comment_count", default: 0, null: false + t.boolean "draft", default: true, null: false + t.integer "comment_count", default: 0, null: false t.text "body" t.datetime "created_at" t.datetime "updated_at" - t.string "short_description" - t.integer "job_phase", null: false - t.integer "display", null: false + t.string "short_description", limit: 255 + t.integer "job_phase", null: false + t.integer "display", null: false t.text "notes" - t.string "copyright_owner" - t.string "seo_title" - t.string "seo_description" - t.string "seo_preview" - t.string "custom_author" - t.string "slug", null: false + t.string "copyright_owner", limit: 255 + t.string "seo_title", limit: 255 + t.string "seo_description", limit: 255 + t.string "seo_preview", limit: 255 + t.string "custom_author", limit: 255 + t.string "slug", null: false t.integer "featured_media_id" t.integer "primary_industry_id" t.integer "primary_category_id" t.integer "tile_media_id" t.hstore "meta" - t.string "type", default: "Post", null: false + t.string "type", default: "Post", null: false t.integer "author_id" - t.boolean "is_wysiwyg", default: true - t.boolean "noindex", default: false - t.boolean "nofollow", default: false - t.boolean "nosnippet", default: false - t.boolean "noodp", default: false - t.boolean "noarchive", default: false - t.boolean "noimageindex", default: false - t.boolean "is_sticky", default: false + t.boolean "is_wysiwyg", default: true + t.boolean "noindex", default: false + t.boolean "nofollow", default: false + t.boolean "nosnippet", default: false + t.boolean "noodp", default: false + t.boolean "noarchive", default: false + t.boolean "noimageindex", default: false + t.boolean "is_sticky", default: false t.index ["author_id"], name: "index_posts_on_author_id", using: :btree t.index ["slug"], name: "index_posts_on_slug", using: :btree t.index ["type"], name: "index_posts_on_type", using: :btree - t.index ["user_id"], name: "index_posts_on_user_id", using: :btree end create_table "role_permissions", force: :cascade do |t| @@ -335,11 +344,10 @@ create_table "roles", force: :cascade do |t| t.string "name" + t.datetime "created_at" + t.datetime "updated_at" t.string "resource_type" - t.integer "resource_id" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false - t.index ["name", "resource_type", "resource_id"], name: "index_roles_on_name_and_resource_type_and_resource_id", using: :btree + t.string "resource_id" t.index ["name"], name: "index_roles_on_name", using: :btree end @@ -355,10 +363,10 @@ create_table "taggings", force: :cascade do |t| t.integer "tag_id" - t.string "taggable_type" t.integer "taggable_id" - t.string "tagger_type" + t.string "taggable_type", limit: 255 t.integer "tagger_id" + t.string "tagger_type", limit: 255 t.string "context", limit: 128 t.datetime "created_at" t.index ["context"], name: "index_taggings_on_context", using: :btree @@ -373,8 +381,9 @@ end create_table "tags", force: :cascade do |t| - t.string "name" - t.integer "taggings_count", default: 0 + t.string "name", limit: 255 + t.integer "taggings_count", default: 0 + t.integer "tenant_id", default: 1 t.index ["name"], name: "index_tags_on_name", unique: true, using: :btree end @@ -389,47 +398,43 @@ t.string "contact_email", limit: 200 t.string "contact_phone", limit: 20 t.datetime "deleted_at" - t.string "contract" - t.string "did" + t.string "contract", limit: 255 + t.string "did", limit: 255 t.datetime "active_at" t.datetime "deactive_at" t.integer "owner_id" t.datetime "created_at" t.datetime "updated_at" - t.index ["did"], name: "index_tenants_on_did", using: :btree - t.index ["owner_id"], name: "index_tenants_on_owner_id", using: :btree t.index ["parent_id"], name: "index_tenants_on_parent_id", using: :btree end create_table "users", force: :cascade do |t| - t.string "email", default: "", null: false + t.string "email", limit: 255, default: "", null: false t.datetime "created_at" t.datetime "updated_at" - t.integer "tenant_id", null: false - t.string "encrypted_password", default: "", null: false - t.string "reset_password_token" + t.integer "tenant_id", null: false + t.string "encrypted_password", limit: 255, default: "", null: false + t.string "reset_password_token", limit: 255 t.datetime "reset_password_sent_at" t.datetime "remember_created_at" - t.integer "sign_in_count", default: 0, null: false + t.integer "sign_in_count", default: 0, null: false t.datetime "current_sign_in_at" t.datetime "last_sign_in_at" - t.string "current_sign_in_ip" - t.string "last_sign_in_ip" - t.string "firstname", null: false - t.string "lastname" - t.string "locale", limit: 30, default: "en_US", null: false - t.string "timezone", limit: 30, default: "EST", null: false - t.boolean "admin", default: false, null: false + t.string "current_sign_in_ip", limit: 255 + t.string "last_sign_in_ip", limit: 255 + t.string "firstname", limit: 255, null: false + t.string "lastname", limit: 255 + t.string "locale", limit: 30, default: "en_US", null: false + t.string "timezone", limit: 30, default: "EST", null: false + t.boolean "admin", default: false, null: false t.index ["email"], name: "index_users_on_email", unique: true, using: :btree t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true, using: :btree t.index ["tenant_id"], name: "index_users_on_tenant_id", using: :btree end create_table "users_roles", id: false, force: :cascade do |t| - t.integer "user_id" - t.integer "role_id" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false + t.integer "user_id" + t.integer "role_id" t.index ["user_id", "role_id"], name: "index_users_roles_on_user_id_and_role_id", using: :btree end @@ -452,6 +457,7 @@ t.boolean "noodp", default: false t.boolean "noarchive", default: false t.boolean "noimageindex", default: false + t.text "seo_keywords" t.string "dynamic_yield_sku" t.string "dynamic_yield_category" t.jsonb "tables_widget" From 65777456bb656b19cfddf7aee595fb846d8a8878 Mon Sep 17 00:00:00 2001 From: ElliottAYoung Date: Mon, 17 Apr 2017 14:03:01 -0500 Subject: [PATCH 05/18] feat: add flag_enabled? method to application_helper --- app/helpers/application_helper.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 2161cdcb0..407de01a5 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -12,4 +12,8 @@ def extra_config def qualtrics_domain extra_config.qualtrics_id.delete('_').downcase end + + def flag_enabled?(flag_name) + Cortex.flipper[flag_name].enabled?(current_user, request) + end end From aa8f38f58666a5cd6c8ac38c2c939f81b1a70c7c Mon Sep 17 00:00:00 2001 From: Alex Tharp Date: Wed, 19 Apr 2017 12:00:04 -0500 Subject: [PATCH 06/18] fix: explicitly specify all ES field mappings for Webpage index --- app/models/concerns/searchable_webpage.rb | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/app/models/concerns/searchable_webpage.rb b/app/models/concerns/searchable_webpage.rb index 79559ea94..c87d36284 100644 --- a/app/models/concerns/searchable_webpage.rb +++ b/app/models/concerns/searchable_webpage.rb @@ -5,12 +5,31 @@ module SearchableWebpage include Searchable mapping do - indexes :id, :type => :integer, :index => :not_analyzed - indexes :tenant_id, :type => :integer, :index => :not_analyzed indexes :name, :analyzer => :snowball indexes :url, :analyzer => :keyword + indexes :dynamic_yield_sku, :analyzer => :keyword + indexes :dynamic_yield_category, :analyzer => :keyword indexes :created_by, :analyzer => :keyword indexes :created_at, :type => :date, :include_in_all => false + indexes :deleted_at, :type => :date, :include_in_all => false + indexes :updated_at, :type => :date, :include_in_all => false + + indexes :id, :type => :integer, :index => :not_analyzed + indexes :tenant_id, :type => :integer, :index => :not_analyzed + indexes :user_id, :type => :integer, :index => :not_analyzed + indexes :thumbnail_file_name, :type => :string, :index => :not_analyzed + indexes :thumbnail_content_type, :type => :string, :index => :not_analyzed + indexes :thumbnail_file_size, :type => :long, :index => :not_analyzed + indexes :thumbnail_updated_at, :type => :date, :index => :not_analyzed + indexes :seo_title, :type => :string, :index => :not_analyzed + indexes :seo_description, :type => :string, :index => :not_analyzed + indexes :noindex, :type => :boolean, :index => :not_analyzed + indexes :nofollow, :type => :boolean, :index => :not_analyzed + indexes :nosnippet, :type => :boolean, :index => :not_analyzed + indexes :noodp, :type => :boolean, :index => :not_analyzed + indexes :noarchive, :type => :boolean, :index => :not_analyzed + indexes :noimageindex, :type => :boolean, :index => :not_analyzed + indexes :tables_widget, :type => :string, :index => :not_analyzed end def as_indexed_json(options = {}) From a5a0f473d3c6beb061ec55fbc7b3b1906179b0d8 Mon Sep 17 00:00:00 2001 From: Alex Tharp Date: Wed, 19 Apr 2017 12:09:36 -0500 Subject: [PATCH 07/18] fix: disable indexing of Webpages tables_widget field --- app/models/concerns/searchable_webpage.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/concerns/searchable_webpage.rb b/app/models/concerns/searchable_webpage.rb index c87d36284..d0aa48c93 100644 --- a/app/models/concerns/searchable_webpage.rb +++ b/app/models/concerns/searchable_webpage.rb @@ -29,7 +29,7 @@ module SearchableWebpage indexes :noodp, :type => :boolean, :index => :not_analyzed indexes :noarchive, :type => :boolean, :index => :not_analyzed indexes :noimageindex, :type => :boolean, :index => :not_analyzed - indexes :tables_widget, :type => :string, :index => :not_analyzed + indexes :tables_widget, :type => :nested, :enabled => false end def as_indexed_json(options = {}) From fe230097b432479ac8733bdb2ed3977246114bbd Mon Sep 17 00:00:00 2001 From: ElliottAYoung Date: Wed, 19 Apr 2017 14:01:48 -0500 Subject: [PATCH 08/18] refactor: move flipper groupings into initializer --- config/application.rb | 10 ---------- config/initializers/flipper.rb | 8 ++++++++ 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/config/application.rb b/config/application.rb index ad72f9fb4..2587cfa20 100644 --- a/config/application.rb +++ b/config/application.rb @@ -40,15 +40,5 @@ class Application < Rails::Application # Needed until there is a better fix for Paperclip. https://github.com/thoughtbot/paperclip/issues/1924#issuecomment-123927367 Paperclip.options[:content_type_mappings] = {:csv => 'text/plain'} - - config.middleware.use Flipper::Middleware::Memoizer, lambda { - Cortex.flipper - } - - Flipper.register(:internal) { |request| request.internal? } - Flipper.register(:authenticated) { |request| request.session[:current_user].present? && request.session[:current_user][:authenticated] } - Flipper.register(:hiring_dot) { |request| request.host == 'admin.cbcortex.com' } - Flipper.register(:dev) { |request| request.host == 'dev.admin.cbcortex.com' || request.host == 'localhost' } - Flipper.register(:staging) { |request| request.host == 'stg.admin.cbcortex.com' } end end diff --git a/config/initializers/flipper.rb b/config/initializers/flipper.rb index 273848d1f..db3d70fc0 100644 --- a/config/initializers/flipper.rb +++ b/config/initializers/flipper.rb @@ -3,3 +3,11 @@ def self.flipper @flipper ||= Flipper.new(Flipper::Adapters::ActiveRecord.new) end end + +Cortex::Application.config.middleware.use Flipper::Middleware::Memoizer, Cortex.flipper + +Flipper.register(:internal) { |request| request.internal? } +Flipper.register(:authenticated) { |request| request.session[:current_user].present? && request.session[:current_user][:authenticated] } +Flipper.register(:cortex) { |request| request.host == 'admin.cbcortex.com' } +Flipper.register(:dev) { |request| request.host == 'dev.admin.cbcortex.com' || request.host == 'localhost' } +Flipper.register(:staging) { |request| request.host == 'stg.admin.cbcortex.com' } From 609ff913f5b7210d343b968a89de339aa2096be5 Mon Sep 17 00:00:00 2001 From: ElliottAYoung Date: Wed, 19 Apr 2017 14:03:39 -0500 Subject: [PATCH 09/18] refactor: clean noise from schema file --- db/schema.rb | 162 +++++++++++++++++++++++++++------------------------ 1 file changed, 86 insertions(+), 76 deletions(-) diff --git a/db/schema.rb b/db/schema.rb index db1c93dc3..ddaf9127f 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.define(version: 20170417185915) do +ActiveRecord::Schema.define(version: 20170327182543) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -58,14 +58,19 @@ end create_table "categories", force: :cascade do |t| - t.string "name", limit: 255 - t.integer "user_id", null: false + t.string "name" + t.integer "user_id", null: false t.integer "parent_id" t.integer "lft" t.integer "rgt" t.integer "depth" t.datetime "created_at" t.datetime "updated_at" + t.index ["depth"], name: "index_categories_on_depth", using: :btree + t.index ["lft"], name: "index_categories_on_lft", using: :btree + t.index ["parent_id"], name: "index_categories_on_parent_id", using: :btree + t.index ["rgt"], name: "index_categories_on_rgt", using: :btree + t.index ["user_id"], name: "index_categories_on_user_id", using: :btree end create_table "categories_posts", id: false, force: :cascade do |t| @@ -208,23 +213,24 @@ end create_table "media", force: :cascade do |t| - t.string "name", limit: 255 + t.string "name" t.integer "user_id" - t.string "attachment_file_name", limit: 255 - t.string "attachment_content_type", limit: 255 + t.string "attachment_file_name" + t.string "attachment_content_type" t.integer "attachment_file_size" t.datetime "attachment_updated_at" - t.string "dimensions", limit: 255 + t.string "dimensions" t.text "description" - t.string "alt", limit: 255 + t.string "alt" t.boolean "active" t.datetime "deactive_at" t.datetime "created_at" t.datetime "updated_at" - t.string "digest", limit: 255 + t.string "digest" t.datetime "deleted_at" t.hstore "meta" - t.string "type", limit: 255, default: "Media", null: false + t.string "type", default: "Media", null: false + t.index ["name"], name: "index_media_on_name", using: :btree t.index ["user_id"], name: "index_media_on_user_id", using: :btree end @@ -234,48 +240,48 @@ end create_table "oauth_access_grants", force: :cascade do |t| - t.integer "resource_owner_id", null: false - t.integer "application_id", null: false - t.string "token", limit: 255, null: false - t.integer "expires_in", null: false - t.text "redirect_uri", null: false - t.datetime "created_at", null: false + t.integer "resource_owner_id", null: false + t.integer "application_id", null: false + t.string "token", null: false + t.integer "expires_in", null: false + t.text "redirect_uri", null: false + t.datetime "created_at", null: false t.datetime "revoked_at" - t.string "scopes", limit: 255 + t.string "scopes" t.index ["token"], name: "index_oauth_access_grants_on_token", unique: true, using: :btree end create_table "oauth_access_tokens", force: :cascade do |t| t.integer "resource_owner_id" t.integer "application_id" - t.string "token", limit: 255, null: false - t.string "refresh_token", limit: 255 + t.string "token", null: false + t.string "refresh_token" t.integer "expires_in" t.datetime "revoked_at" - t.datetime "created_at", null: false - t.string "scopes", limit: 255 + t.datetime "created_at", null: false + t.string "scopes" t.index ["refresh_token"], name: "index_oauth_access_tokens_on_refresh_token", unique: true, using: :btree t.index ["resource_owner_id"], name: "index_oauth_access_tokens_on_resource_owner_id", using: :btree t.index ["token"], name: "index_oauth_access_tokens_on_token", unique: true, using: :btree end create_table "oauth_applications", force: :cascade do |t| - t.string "name", limit: 255, null: false - t.string "uid", limit: 255, null: false - t.string "secret", limit: 255, null: false - t.text "redirect_uri", null: false + t.string "name", null: false + t.string "uid", null: false + t.string "secret", null: false + t.text "redirect_uri", null: false t.datetime "created_at" t.datetime "updated_at" t.integer "owner_id" - t.string "owner_type", limit: 255 - t.string "scopes", default: "", null: false + t.string "owner_type" + t.string "scopes", default: "", null: false t.index ["owner_id", "owner_type"], name: "index_oauth_applications_on_owner_id_and_owner_type", using: :btree t.index ["uid"], name: "index_oauth_applications_on_uid", unique: true, using: :btree end create_table "onet_occupations", force: :cascade do |t| - t.string "soc", limit: 255 - t.string "title", limit: 255 + t.string "soc" + t.string "title" t.text "description" t.datetime "created_at" t.datetime "updated_at" @@ -295,44 +301,45 @@ end create_table "posts", force: :cascade do |t| - t.integer "user_id", null: false - t.string "title", limit: 255 + t.integer "user_id", null: false + t.string "title" t.datetime "published_at" t.datetime "expired_at" t.datetime "deleted_at" - t.boolean "draft", default: true, null: false - t.integer "comment_count", default: 0, null: false + t.boolean "draft", default: true, null: false + t.integer "comment_count", default: 0, null: false t.text "body" t.datetime "created_at" t.datetime "updated_at" - t.string "short_description", limit: 255 - t.integer "job_phase", null: false - t.integer "display", null: false + t.string "short_description" + t.integer "job_phase", null: false + t.integer "display", null: false t.text "notes" - t.string "copyright_owner", limit: 255 - t.string "seo_title", limit: 255 - t.string "seo_description", limit: 255 - t.string "seo_preview", limit: 255 - t.string "custom_author", limit: 255 - t.string "slug", null: false + t.string "copyright_owner" + t.string "seo_title" + t.string "seo_description" + t.string "seo_preview" + t.string "custom_author" + t.string "slug", null: false t.integer "featured_media_id" t.integer "primary_industry_id" t.integer "primary_category_id" t.integer "tile_media_id" t.hstore "meta" - t.string "type", default: "Post", null: false + t.string "type", default: "Post", null: false t.integer "author_id" - t.boolean "is_wysiwyg", default: true - t.boolean "noindex", default: false - t.boolean "nofollow", default: false - t.boolean "nosnippet", default: false - t.boolean "noodp", default: false - t.boolean "noarchive", default: false - t.boolean "noimageindex", default: false - t.boolean "is_sticky", default: false + t.boolean "is_wysiwyg", default: true + t.boolean "noindex", default: false + t.boolean "nofollow", default: false + t.boolean "nosnippet", default: false + t.boolean "noodp", default: false + t.boolean "noarchive", default: false + t.boolean "noimageindex", default: false + t.boolean "is_sticky", default: false t.index ["author_id"], name: "index_posts_on_author_id", using: :btree t.index ["slug"], name: "index_posts_on_slug", using: :btree t.index ["type"], name: "index_posts_on_type", using: :btree + t.index ["user_id"], name: "index_posts_on_user_id", using: :btree end create_table "role_permissions", force: :cascade do |t| @@ -344,10 +351,11 @@ create_table "roles", force: :cascade do |t| t.string "name" - t.datetime "created_at" - t.datetime "updated_at" t.string "resource_type" - t.string "resource_id" + t.integer "resource_id" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index ["name", "resource_type", "resource_id"], name: "index_roles_on_name_and_resource_type_and_resource_id", using: :btree t.index ["name"], name: "index_roles_on_name", using: :btree end @@ -363,10 +371,10 @@ create_table "taggings", force: :cascade do |t| t.integer "tag_id" + t.string "taggable_type" t.integer "taggable_id" - t.string "taggable_type", limit: 255 + t.string "tagger_type" t.integer "tagger_id" - t.string "tagger_type", limit: 255 t.string "context", limit: 128 t.datetime "created_at" t.index ["context"], name: "index_taggings_on_context", using: :btree @@ -381,9 +389,8 @@ end create_table "tags", force: :cascade do |t| - t.string "name", limit: 255 - t.integer "taggings_count", default: 0 - t.integer "tenant_id", default: 1 + t.string "name" + t.integer "taggings_count", default: 0 t.index ["name"], name: "index_tags_on_name", unique: true, using: :btree end @@ -398,43 +405,47 @@ t.string "contact_email", limit: 200 t.string "contact_phone", limit: 20 t.datetime "deleted_at" - t.string "contract", limit: 255 - t.string "did", limit: 255 + t.string "contract" + t.string "did" t.datetime "active_at" t.datetime "deactive_at" t.integer "owner_id" t.datetime "created_at" t.datetime "updated_at" + t.index ["did"], name: "index_tenants_on_did", using: :btree + t.index ["owner_id"], name: "index_tenants_on_owner_id", using: :btree t.index ["parent_id"], name: "index_tenants_on_parent_id", using: :btree end create_table "users", force: :cascade do |t| - t.string "email", limit: 255, default: "", null: false + t.string "email", default: "", null: false t.datetime "created_at" t.datetime "updated_at" - t.integer "tenant_id", null: false - t.string "encrypted_password", limit: 255, default: "", null: false - t.string "reset_password_token", limit: 255 + t.integer "tenant_id", null: false + t.string "encrypted_password", default: "", null: false + t.string "reset_password_token" t.datetime "reset_password_sent_at" t.datetime "remember_created_at" - t.integer "sign_in_count", default: 0, null: false + t.integer "sign_in_count", default: 0, null: false t.datetime "current_sign_in_at" t.datetime "last_sign_in_at" - t.string "current_sign_in_ip", limit: 255 - t.string "last_sign_in_ip", limit: 255 - t.string "firstname", limit: 255, null: false - t.string "lastname", limit: 255 - t.string "locale", limit: 30, default: "en_US", null: false - t.string "timezone", limit: 30, default: "EST", null: false - t.boolean "admin", default: false, null: false + t.string "current_sign_in_ip" + t.string "last_sign_in_ip" + t.string "firstname", null: false + t.string "lastname" + t.string "locale", limit: 30, default: "en_US", null: false + t.string "timezone", limit: 30, default: "EST", null: false + t.boolean "admin", default: false, null: false t.index ["email"], name: "index_users_on_email", unique: true, using: :btree t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true, using: :btree t.index ["tenant_id"], name: "index_users_on_tenant_id", using: :btree end create_table "users_roles", id: false, force: :cascade do |t| - t.integer "user_id" - t.integer "role_id" + t.integer "user_id" + t.integer "role_id" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false t.index ["user_id", "role_id"], name: "index_users_roles_on_user_id_and_role_id", using: :btree end @@ -457,7 +468,6 @@ t.boolean "noodp", default: false t.boolean "noarchive", default: false t.boolean "noimageindex", default: false - t.text "seo_keywords" t.string "dynamic_yield_sku" t.string "dynamic_yield_category" t.jsonb "tables_widget" From f2697a2962d118c9626bc52ce7efc773765a13fe Mon Sep 17 00:00:00 2001 From: ElliottAYoung Date: Fri, 21 Apr 2017 11:36:19 -0500 Subject: [PATCH 10/18] fix: tag_data method to make featured image optional --- app/helpers/rss_helper.rb | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/app/helpers/rss_helper.rb b/app/helpers/rss_helper.rb index e118113ca..8b8ce5427 100644 --- a/app/helpers/rss_helper.rb +++ b/app/helpers/rss_helper.rb @@ -49,15 +49,20 @@ def media_data(media_hash, rss_content_item) field_name = linked_field_item.field.metadata["field_name"] asset_content_item_id = linked_field_item.data["content_item_id"] + field_item = Field.find_by_name(field_name).field_items.find { |field_item| field_item.content_item_id == asset_content_item_id } - asset_data = Field.find_by_name(field_name).field_items.find { |field_item| field_item.content_item_id == asset_content_item_id }.data["asset"] + if field_item.nil? + {} + else + asset_data = field_item.data["asset"] - { - "url": asset_data["url"], - "type": asset_data["content_type"], - "medium": media_hash["medium"], - "width": media_hash["width"] || asset_data["dimensions"]["width"], - "height": media_hash["height"] || asset_data["dimensions"]["height"] - } + { + "url": asset_data["url"], + "type": asset_data["content_type"], + "medium": media_hash["medium"], + "width": media_hash["width"] || asset_data["dimensions"]["width"], + "height": media_hash["height"] || asset_data["dimensions"]["height"] + } + end end end From d3e47e93652a6f33286fafa8bd4293189626c254 Mon Sep 17 00:00:00 2001 From: ElliottAYoung Date: Mon, 24 Apr 2017 11:37:52 -0500 Subject: [PATCH 11/18] fix: remove box-shadow form tag field --- app/assets/stylesheets/components/form.scss | 1 + 1 file changed, 1 insertion(+) diff --git a/app/assets/stylesheets/components/form.scss b/app/assets/stylesheets/components/form.scss index 0c5c3c12b..796b88864 100644 --- a/app/assets/stylesheets/components/form.scss +++ b/app/assets/stylesheets/components/form.scss @@ -46,6 +46,7 @@ form { border-right: none; border-left: none; border-bottom: 1px solid $color-grey-light; + box-shadow: none; } .cortex-bootstrap .label { border-radius: 0.75em; From 9b410615f4ce0fc5758a06e9c0c6c0d76c803548 Mon Sep 17 00:00:00 2001 From: ElliottAYoung Date: Fri, 21 Apr 2017 10:49:36 -0500 Subject: [PATCH 12/18] feat: add JS for required attribute --- app/assets/javascripts/application.js | 1 + app/assets/javascripts/form.js | 6 ++++++ 2 files changed, 7 insertions(+) create mode 100644 app/assets/javascripts/form.js diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index 861a9acdf..41c2b55dc 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -15,6 +15,7 @@ //= require base //= require datepicker_init +//= require form //= require flash //= require media_dialogs //= require sidebar-toggle diff --git a/app/assets/javascripts/form.js b/app/assets/javascripts/form.js new file mode 100644 index 000000000..a09f9a236 --- /dev/null +++ b/app/assets/javascripts/form.js @@ -0,0 +1,6 @@ +var requiredFormField = function() { + $('input[data-required=true]').attr('required', true); +} + +$(document).ready(requiredFormField); +$(document).on('page:load', requiredFormField); From 091469697be57f3ebd37e6f64a026bd46360001f Mon Sep 17 00:00:00 2001 From: ElliottAYoung Date: Tue, 25 Apr 2017 10:37:11 -0500 Subject: [PATCH 13/18] bump: cortex-plugins-core to 0.11.3 --- Gemfile | 2 +- Gemfile.lock | 4 +- db/schema.rb | 162 ++++++++++++++++++++++++--------------------------- 3 files changed, 79 insertions(+), 89 deletions(-) diff --git a/Gemfile b/Gemfile index b6adbefce..6cfcdd64a 100644 --- a/Gemfile +++ b/Gemfile @@ -12,7 +12,7 @@ gem 'rails', '~> 5.0.1' # Cortex-specific gem 'cortex-exceptions', '= 0.0.4' -gem 'cortex-plugins-core', '= 0.11.2' +gem 'cortex-plugins-core', '= 0.11.3' # API gem 'grape', '~> 0.17' diff --git a/Gemfile.lock b/Gemfile.lock index 137001d14..7836c11f9 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -137,7 +137,7 @@ GEM concurrent-ruby (1.0.4) connection_pool (2.2.1) cortex-exceptions (0.0.4) - cortex-plugins-core (0.11.2) + cortex-plugins-core (0.11.3) cells (~> 4.1) cells-haml (~> 0.0.10) cells-rails (~> 0.0.6) @@ -734,7 +734,7 @@ DEPENDENCIES cells-rails (~> 0.0.7) codeclimate-test-reporter (~> 0.6) cortex-exceptions (= 0.0.4) - cortex-plugins-core (= 0.11.2) + cortex-plugins-core (= 0.11.3) database_cleaner (~> 1.5) deep_cloneable (~> 2.2.2) devise (~> 4.2.0) diff --git a/db/schema.rb b/db/schema.rb index ddaf9127f..db1c93dc3 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.define(version: 20170327182543) do +ActiveRecord::Schema.define(version: 20170417185915) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -58,19 +58,14 @@ end create_table "categories", force: :cascade do |t| - t.string "name" - t.integer "user_id", null: false + t.string "name", limit: 255 + t.integer "user_id", null: false t.integer "parent_id" t.integer "lft" t.integer "rgt" t.integer "depth" t.datetime "created_at" t.datetime "updated_at" - t.index ["depth"], name: "index_categories_on_depth", using: :btree - t.index ["lft"], name: "index_categories_on_lft", using: :btree - t.index ["parent_id"], name: "index_categories_on_parent_id", using: :btree - t.index ["rgt"], name: "index_categories_on_rgt", using: :btree - t.index ["user_id"], name: "index_categories_on_user_id", using: :btree end create_table "categories_posts", id: false, force: :cascade do |t| @@ -213,24 +208,23 @@ end create_table "media", force: :cascade do |t| - t.string "name" + t.string "name", limit: 255 t.integer "user_id" - t.string "attachment_file_name" - t.string "attachment_content_type" + t.string "attachment_file_name", limit: 255 + t.string "attachment_content_type", limit: 255 t.integer "attachment_file_size" t.datetime "attachment_updated_at" - t.string "dimensions" + t.string "dimensions", limit: 255 t.text "description" - t.string "alt" + t.string "alt", limit: 255 t.boolean "active" t.datetime "deactive_at" t.datetime "created_at" t.datetime "updated_at" - t.string "digest" + t.string "digest", limit: 255 t.datetime "deleted_at" t.hstore "meta" - t.string "type", default: "Media", null: false - t.index ["name"], name: "index_media_on_name", using: :btree + t.string "type", limit: 255, default: "Media", null: false t.index ["user_id"], name: "index_media_on_user_id", using: :btree end @@ -240,48 +234,48 @@ end create_table "oauth_access_grants", force: :cascade do |t| - t.integer "resource_owner_id", null: false - t.integer "application_id", null: false - t.string "token", null: false - t.integer "expires_in", null: false - t.text "redirect_uri", null: false - t.datetime "created_at", null: false + t.integer "resource_owner_id", null: false + t.integer "application_id", null: false + t.string "token", limit: 255, null: false + t.integer "expires_in", null: false + t.text "redirect_uri", null: false + t.datetime "created_at", null: false t.datetime "revoked_at" - t.string "scopes" + t.string "scopes", limit: 255 t.index ["token"], name: "index_oauth_access_grants_on_token", unique: true, using: :btree end create_table "oauth_access_tokens", force: :cascade do |t| t.integer "resource_owner_id" t.integer "application_id" - t.string "token", null: false - t.string "refresh_token" + t.string "token", limit: 255, null: false + t.string "refresh_token", limit: 255 t.integer "expires_in" t.datetime "revoked_at" - t.datetime "created_at", null: false - t.string "scopes" + t.datetime "created_at", null: false + t.string "scopes", limit: 255 t.index ["refresh_token"], name: "index_oauth_access_tokens_on_refresh_token", unique: true, using: :btree t.index ["resource_owner_id"], name: "index_oauth_access_tokens_on_resource_owner_id", using: :btree t.index ["token"], name: "index_oauth_access_tokens_on_token", unique: true, using: :btree end create_table "oauth_applications", force: :cascade do |t| - t.string "name", null: false - t.string "uid", null: false - t.string "secret", null: false - t.text "redirect_uri", null: false + t.string "name", limit: 255, null: false + t.string "uid", limit: 255, null: false + t.string "secret", limit: 255, null: false + t.text "redirect_uri", null: false t.datetime "created_at" t.datetime "updated_at" t.integer "owner_id" - t.string "owner_type" - t.string "scopes", default: "", null: false + t.string "owner_type", limit: 255 + t.string "scopes", default: "", null: false t.index ["owner_id", "owner_type"], name: "index_oauth_applications_on_owner_id_and_owner_type", using: :btree t.index ["uid"], name: "index_oauth_applications_on_uid", unique: true, using: :btree end create_table "onet_occupations", force: :cascade do |t| - t.string "soc" - t.string "title" + t.string "soc", limit: 255 + t.string "title", limit: 255 t.text "description" t.datetime "created_at" t.datetime "updated_at" @@ -301,45 +295,44 @@ end create_table "posts", force: :cascade do |t| - t.integer "user_id", null: false - t.string "title" + t.integer "user_id", null: false + t.string "title", limit: 255 t.datetime "published_at" t.datetime "expired_at" t.datetime "deleted_at" - t.boolean "draft", default: true, null: false - t.integer "comment_count", default: 0, null: false + t.boolean "draft", default: true, null: false + t.integer "comment_count", default: 0, null: false t.text "body" t.datetime "created_at" t.datetime "updated_at" - t.string "short_description" - t.integer "job_phase", null: false - t.integer "display", null: false + t.string "short_description", limit: 255 + t.integer "job_phase", null: false + t.integer "display", null: false t.text "notes" - t.string "copyright_owner" - t.string "seo_title" - t.string "seo_description" - t.string "seo_preview" - t.string "custom_author" - t.string "slug", null: false + t.string "copyright_owner", limit: 255 + t.string "seo_title", limit: 255 + t.string "seo_description", limit: 255 + t.string "seo_preview", limit: 255 + t.string "custom_author", limit: 255 + t.string "slug", null: false t.integer "featured_media_id" t.integer "primary_industry_id" t.integer "primary_category_id" t.integer "tile_media_id" t.hstore "meta" - t.string "type", default: "Post", null: false + t.string "type", default: "Post", null: false t.integer "author_id" - t.boolean "is_wysiwyg", default: true - t.boolean "noindex", default: false - t.boolean "nofollow", default: false - t.boolean "nosnippet", default: false - t.boolean "noodp", default: false - t.boolean "noarchive", default: false - t.boolean "noimageindex", default: false - t.boolean "is_sticky", default: false + t.boolean "is_wysiwyg", default: true + t.boolean "noindex", default: false + t.boolean "nofollow", default: false + t.boolean "nosnippet", default: false + t.boolean "noodp", default: false + t.boolean "noarchive", default: false + t.boolean "noimageindex", default: false + t.boolean "is_sticky", default: false t.index ["author_id"], name: "index_posts_on_author_id", using: :btree t.index ["slug"], name: "index_posts_on_slug", using: :btree t.index ["type"], name: "index_posts_on_type", using: :btree - t.index ["user_id"], name: "index_posts_on_user_id", using: :btree end create_table "role_permissions", force: :cascade do |t| @@ -351,11 +344,10 @@ create_table "roles", force: :cascade do |t| t.string "name" + t.datetime "created_at" + t.datetime "updated_at" t.string "resource_type" - t.integer "resource_id" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false - t.index ["name", "resource_type", "resource_id"], name: "index_roles_on_name_and_resource_type_and_resource_id", using: :btree + t.string "resource_id" t.index ["name"], name: "index_roles_on_name", using: :btree end @@ -371,10 +363,10 @@ create_table "taggings", force: :cascade do |t| t.integer "tag_id" - t.string "taggable_type" t.integer "taggable_id" - t.string "tagger_type" + t.string "taggable_type", limit: 255 t.integer "tagger_id" + t.string "tagger_type", limit: 255 t.string "context", limit: 128 t.datetime "created_at" t.index ["context"], name: "index_taggings_on_context", using: :btree @@ -389,8 +381,9 @@ end create_table "tags", force: :cascade do |t| - t.string "name" - t.integer "taggings_count", default: 0 + t.string "name", limit: 255 + t.integer "taggings_count", default: 0 + t.integer "tenant_id", default: 1 t.index ["name"], name: "index_tags_on_name", unique: true, using: :btree end @@ -405,47 +398,43 @@ t.string "contact_email", limit: 200 t.string "contact_phone", limit: 20 t.datetime "deleted_at" - t.string "contract" - t.string "did" + t.string "contract", limit: 255 + t.string "did", limit: 255 t.datetime "active_at" t.datetime "deactive_at" t.integer "owner_id" t.datetime "created_at" t.datetime "updated_at" - t.index ["did"], name: "index_tenants_on_did", using: :btree - t.index ["owner_id"], name: "index_tenants_on_owner_id", using: :btree t.index ["parent_id"], name: "index_tenants_on_parent_id", using: :btree end create_table "users", force: :cascade do |t| - t.string "email", default: "", null: false + t.string "email", limit: 255, default: "", null: false t.datetime "created_at" t.datetime "updated_at" - t.integer "tenant_id", null: false - t.string "encrypted_password", default: "", null: false - t.string "reset_password_token" + t.integer "tenant_id", null: false + t.string "encrypted_password", limit: 255, default: "", null: false + t.string "reset_password_token", limit: 255 t.datetime "reset_password_sent_at" t.datetime "remember_created_at" - t.integer "sign_in_count", default: 0, null: false + t.integer "sign_in_count", default: 0, null: false t.datetime "current_sign_in_at" t.datetime "last_sign_in_at" - t.string "current_sign_in_ip" - t.string "last_sign_in_ip" - t.string "firstname", null: false - t.string "lastname" - t.string "locale", limit: 30, default: "en_US", null: false - t.string "timezone", limit: 30, default: "EST", null: false - t.boolean "admin", default: false, null: false + t.string "current_sign_in_ip", limit: 255 + t.string "last_sign_in_ip", limit: 255 + t.string "firstname", limit: 255, null: false + t.string "lastname", limit: 255 + t.string "locale", limit: 30, default: "en_US", null: false + t.string "timezone", limit: 30, default: "EST", null: false + t.boolean "admin", default: false, null: false t.index ["email"], name: "index_users_on_email", unique: true, using: :btree t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true, using: :btree t.index ["tenant_id"], name: "index_users_on_tenant_id", using: :btree end create_table "users_roles", id: false, force: :cascade do |t| - t.integer "user_id" - t.integer "role_id" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false + t.integer "user_id" + t.integer "role_id" t.index ["user_id", "role_id"], name: "index_users_roles_on_user_id_and_role_id", using: :btree end @@ -468,6 +457,7 @@ t.boolean "noodp", default: false t.boolean "noarchive", default: false t.boolean "noimageindex", default: false + t.text "seo_keywords" t.string "dynamic_yield_sku" t.string "dynamic_yield_category" t.jsonb "tables_widget" From b9d060a85dbdcf08731debafbb5ad6ede0d71fc4 Mon Sep 17 00:00:00 2001 From: Alex Tharp Date: Tue, 25 Apr 2017 22:40:21 -0500 Subject: [PATCH 14/18] feat: supporting functionality for Shrine-backed AssetFieldType rebuild, comments denoting targets for refactor, style fixes and improvements --- .env.example | 11 ++++-- .gitignore | 1 + Gemfile | 2 +- Gemfile.lock | 34 ++++++++++++++----- app/assets/stylesheets/application.scss | 4 ++- app/assets/stylesheets/components/card.scss | 3 +- app/assets/stylesheets/components/dialog.scss | 2 +- app/assets/stylesheets/components/index.scss | 5 +++ .../components/{content.scss => table.scss} | 0 app/cells/index/index.haml | 8 +++-- app/cells/index_cell.rb | 12 +++++-- app/controllers/content_items_controller.rb | 2 +- app/helpers/popup_helper.rb | 4 ++- config/environments/development.rb | 2 +- config/initializers/field_types.rb | 1 - 15 files changed, 66 insertions(+), 25 deletions(-) rename app/assets/stylesheets/components/{content.scss => table.scss} (100%) delete mode 100644 config/initializers/field_types.rb diff --git a/.env.example b/.env.example index cf6e6b2ff..197dd072d 100644 --- a/.env.example +++ b/.env.example @@ -5,8 +5,15 @@ DEVISE_SECRET= # # Asset Host Configuration # -HOST=http://localhost:3000 -S3_HOST_ALIAS= +FOG_HOST=http://localhost:3000 +HOST_ALIAS= + +# S3 +S3_ACCESS_KEY_ID= +S3_SECRET_ACCESS_KEY= +S3_BUCKET_NAME= +S3_PROTOCOL= +S3_REGION= # # Email Configuration diff --git a/.gitignore b/.gitignore index 033088147..c19fd93b4 100644 --- a/.gitignore +++ b/.gitignore @@ -15,6 +15,7 @@ /public/youtubes/ /public/bulk_jobs/ /public/content-snippets-edit +/public/uploads/ # Ignore the default SQLite database. /db/*.sqlite3 diff --git a/Gemfile b/Gemfile index 6cfcdd64a..805049178 100644 --- a/Gemfile +++ b/Gemfile @@ -12,7 +12,7 @@ gem 'rails', '~> 5.0.1' # Cortex-specific gem 'cortex-exceptions', '= 0.0.4' -gem 'cortex-plugins-core', '= 0.11.3' +gem 'cortex-plugins-core', git: 'https://github.com/cortex-cms/cortex-plugins-core.git', branch: 'topic/COR-704-Rebuild-AssetFieldType' # API gem 'grape', '~> 0.17' diff --git a/Gemfile.lock b/Gemfile.lock index 7836c11f9..5f14f4769 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -5,6 +5,24 @@ GIT awesome_nested_set (3.1.2) activerecord (>= 4.0.0, < 5.1) +GIT + remote: https://github.com/cortex-cms/cortex-plugins-core.git + revision: cc5f33441c2d229536ab0776d86aa197e37c9654 + branch: topic/COR-704-Rebuild-AssetFieldType + specs: + cortex-plugins-core (0.11.2) + cells (~> 4.1) + cells-haml (~> 0.0.10) + cells-rails (~> 0.0.6) + fastimage (~> 2.1.0) + image_processing (~> 0.4.1) + jsonb_accessor (~> 1.0.0.beta) + mimemagic (~> 0.3.2) + mini_magick (~> 4.7.0) + rails (>= 4) + react_on_rails (~> 6) + shrine (~> 2.6.1) + GIT remote: https://github.com/toastercup/grape-kaminari.git revision: 661388050eaa97f70006b74fe300e19760b8a132 @@ -137,14 +155,6 @@ GEM concurrent-ruby (1.0.4) connection_pool (2.2.1) cortex-exceptions (0.0.4) - cortex-plugins-core (0.11.3) - cells (~> 4.1) - cells-haml (~> 0.0.10) - cells-rails (~> 0.0.6) - jsonb_accessor (~> 1.0.0.beta) - mimemagic (~> 0.3.2) - rails (>= 4) - react_on_rails (~> 6) database_cleaner (1.5.3) debug_inspector (0.0.2) declarative-builder (0.1.0) @@ -169,6 +179,7 @@ GEM dotenv-rails (2.2.0) dotenv (= 2.2.0) railties (>= 3.2, < 5.1) + down (2.4.3) elasticsearch (5.0.3) elasticsearch-api (= 5.0.3) elasticsearch-transport (= 5.0.3) @@ -205,6 +216,7 @@ GEM i18n (~> 0.5) faraday (0.11.0) multipart-post (>= 1.2, < 3) + fastimage (2.1.0) ffi (1.9.17) fission (0.5.0) CFPropertyList (~> 2.2) @@ -411,6 +423,7 @@ GEM image_optim_pack (0.3.1.20170121) fspath (>= 2.1, < 4) image_optim (~> 0.19) + image_processing (0.4.1) image_size (1.5.0) in_threads (1.3.1) inflecto (0.0.2) @@ -471,6 +484,7 @@ GEM mime-types-data (~> 3.2015) mime-types-data (3.2016.0521) mimemagic (0.3.2) + mini_magick (4.7.0) mini_portile2 (2.1.0) mini_racer (0.1.8) libv8 (~> 5.3) @@ -654,6 +668,8 @@ GEM shellany (0.0.1) shoulda-matchers (3.1.1) activesupport (>= 4.0.0) + shrine (2.6.1) + down (>= 2.3.6) sidekiq (4.2.9) concurrent-ruby (~> 1.0) connection_pool (~> 2.2, >= 2.2.0) @@ -734,7 +750,7 @@ DEPENDENCIES cells-rails (~> 0.0.7) codeclimate-test-reporter (~> 0.6) cortex-exceptions (= 0.0.4) - cortex-plugins-core (= 0.11.3) + cortex-plugins-core! database_cleaner (~> 1.5) deep_cloneable (~> 2.2.2) devise (~> 4.2.0) diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss index e83147b25..121af0a52 100644 --- a/app/assets/stylesheets/application.scss +++ b/app/assets/stylesheets/application.scss @@ -19,7 +19,6 @@ @import 'components/card'; @import 'components/confetti'; -@import 'components/content'; @import 'components/dialog'; @import 'components/flash'; @import 'components/form'; @@ -28,6 +27,9 @@ @import 'components/jumbo-button'; @import 'components/notes'; @import 'components/sidebar'; +@import 'components/table'; @import 'components/ui'; @import 'demo'; + +@import 'cortex-plugins-core/application'; diff --git a/app/assets/stylesheets/components/card.scss b/app/assets/stylesheets/components/card.scss index 5a7f9181b..fe6c39b6d 100644 --- a/app/assets/stylesheets/components/card.scss +++ b/app/assets/stylesheets/components/card.scss @@ -1,8 +1,9 @@ // Overrides .mdl-card { + border: $data-table-dividers; + border-radius: 0; width: auto; - border-radius: 3px; overflow: visible; z-index: auto; } diff --git a/app/assets/stylesheets/components/dialog.scss b/app/assets/stylesheets/components/dialog.scss index 88e65c498..3590f5e48 100644 --- a/app/assets/stylesheets/components/dialog.scss +++ b/app/assets/stylesheets/components/dialog.scss @@ -23,7 +23,7 @@ justify-content: center; align-items: center; - border: 1px solid $color-grey; + border: $data-table-dividers; margin-top: 10px; margin-bottom: 10px; width: 100%; diff --git a/app/assets/stylesheets/components/index.scss b/app/assets/stylesheets/components/index.scss index e29adadc9..a081de437 100644 --- a/app/assets/stylesheets/components/index.scss +++ b/app/assets/stylesheets/components/index.scss @@ -1,3 +1,7 @@ +.index { + width: 100%; +} + .content_item-link { cursor: pointer; @@ -21,3 +25,4 @@ } } } + diff --git a/app/assets/stylesheets/components/content.scss b/app/assets/stylesheets/components/table.scss similarity index 100% rename from app/assets/stylesheets/components/content.scss rename to app/assets/stylesheets/components/table.scss diff --git a/app/cells/index/index.haml b/app/cells/index/index.haml index 0cdc3eb12..54acc0499 100644 --- a/app/cells/index/index.haml +++ b/app/cells/index/index.haml @@ -1,3 +1,5 @@ -%table{ class: 'mdl-data-table mdl-js-data-table', style: 'width: 100%;' } - = cell('index', @index, data: data).(:table_headers) - = cell('index', @index, data: data).(:table_body) +.mdl-grid + .mdl-cell.mdl-cell--12-col + %table.mdl-data-table.mdl-js-data-table.index + = cell('index', @index, data: data).(:table_headers) + = cell('index', @index, data: data).(:table_body) diff --git a/app/cells/index_cell.rb b/app/cells/index_cell.rb index 73c40a2d3..ead2f2593 100644 --- a/app/cells/index_cell.rb +++ b/app/cells/index_cell.rb @@ -20,26 +20,32 @@ def render_table_header(column_data) end def asset_field_item(content_item) + # TODO: This needs to be generic functionality content_item.field_items.find { |field_item| field_item.field.name == 'Asset' } end def content_item_title(content_item) + # TODO: This needs to be generic functionality content_item.field_items.find { |field_item| field_item.field.name == 'Title' }.data['text'] end def content_item_thumb_url(content_item) - asset_field_item(content_item).data['asset']['style_urls']['mini'] + # TODO: The thumb version needs to be configurable, and this needs to be in a plugin + asset_field_item(content_item).data['asset']&.[]('versions')&.[]('mini')&.[]('url') end def content_item_asset_url(content_item) - asset_field_item(content_item).data['asset']['url'] + # TODO: This needs to be in a plugin + asset_field_item(content_item).data['asset']['versions']['original']['url'] end def content_item_asset_type(content_item) - MimeMagic.new(asset_field_item(content_item).data['asset']['content_type']).mediatype + # TODO: This needs to be in a plugin + MimeMagic.new(asset_field_item(content_item).data['asset']['versions']['original']['mime_type']).mediatype end def content_item_asset_alt_text(content_item) + # TODO: This needs to be in a plugin content_item.field_items.find { |field_item| field_item.field.name == 'Alt Tag' }.data['text'] end end diff --git a/app/controllers/content_items_controller.rb b/app/controllers/content_items_controller.rb index f8be887fc..377e992d8 100644 --- a/app/controllers/content_items_controller.rb +++ b/app/controllers/content_items_controller.rb @@ -64,6 +64,6 @@ def create else flash[:success] = "Hooray! #{content_type.name} Created!" redirect_to content_type_content_items_path - end + end end end diff --git a/app/helpers/popup_helper.rb b/app/helpers/popup_helper.rb index d3ab16910..aee55846d 100644 --- a/app/helpers/popup_helper.rb +++ b/app/helpers/popup_helper.rb @@ -1,4 +1,6 @@ module PopupHelper + # TODO: This needs to be in a plugin + def media_content_type @media_content_type ||= ContentType.find_by_name('Media') end @@ -13,7 +15,7 @@ def media_asset_field def media_image_content_items @media_image_content_items ||= media_content_items.select do |content_item| - MimeMagic.new(content_item.field_items.find_by_field_id(media_asset_field).data['asset']['content_type']).mediatype == 'image' + MimeMagic.new(content_item.field_items.find_by_field_id(media_asset_field).data['asset']['versions']['original']['mime_type']).mediatype == 'image' end end diff --git a/config/environments/development.rb b/config/environments/development.rb index 2787dd4fb..43055cb2b 100644 --- a/config/environments/development.rb +++ b/config/environments/development.rb @@ -51,7 +51,7 @@ Paperclip.options[:command_path] = '/usr/local/bin/' config.paperclip_defaults = { storage: :fog, - fog_host: ENV['HOST'], + fog_host: ENV['FOG_HOST'], fog_directory: '', fog_credentials: { provider: 'Local', diff --git a/config/initializers/field_types.rb b/config/initializers/field_types.rb deleted file mode 100644 index 99ec6758a..000000000 --- a/config/initializers/field_types.rb +++ /dev/null @@ -1 +0,0 @@ -Dir["#{Rails.root}/app/models/*_field_type.rb"].each {|file| load file} \ No newline at end of file From 699cad704a08da1503b12d92bdb69c6bb6cdd0fb Mon Sep 17 00:00:00 2001 From: Alex Tharp Date: Wed, 26 Apr 2017 02:40:06 -0500 Subject: [PATCH 15/18] fix: AssetFieldType implementation for RSS Helper and Media Widget Parser Helper --- app/helpers/rss_helper.rb | 4 ++-- app/helpers/widget_parsers/media_helper.rb | 14 ++++++++++---- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/app/helpers/rss_helper.rb b/app/helpers/rss_helper.rb index 8b8ce5427..bd10b2df5 100644 --- a/app/helpers/rss_helper.rb +++ b/app/helpers/rss_helper.rb @@ -54,11 +54,11 @@ def media_data(media_hash, rss_content_item) if field_item.nil? {} else - asset_data = field_item.data["asset"] + asset_data = field_item.data['asset']['versions']['original'] { "url": asset_data["url"], - "type": asset_data["content_type"], + "type": asset_data["mime_type"], "medium": media_hash["medium"], "width": media_hash["width"] || asset_data["dimensions"]["width"], "height": media_hash["height"] || asset_data["dimensions"]["height"] diff --git a/app/helpers/widget_parsers/media_helper.rb b/app/helpers/widget_parsers/media_helper.rb index 1878371e5..578353e65 100644 --- a/app/helpers/widget_parsers/media_helper.rb +++ b/app/helpers/widget_parsers/media_helper.rb @@ -1,7 +1,9 @@ module WidgetParsers module MediaHelper + # This needs to be abstracted to a plugin + def self.parse(body) - body_document = document_for(body) + body_document = document_for body widget_nodes_for(body_document).each do |widget_node| widget_node.inner_html = render_widget_inner widget_node @@ -28,10 +30,10 @@ def self.render_widget_inner(widget) end def self.content_item_element(id) - asset_field_item = ContentItem.find(id).field_items.find { |field_item| field_item.field.field_type == "asset_field_type" } - url = asset_field_item.data["asset"]["url"] + asset_field_item = ContentItem.find(id).field_items.find { |field_item| field_item.field.field_type_instance.is_a?(AssetFieldType) } + url = asset_field_item.data['asset']['versions']['original']['url'] - if asset_field_item.data["asset"]["content_type"].include?("image") + if image? asset_field_item.data['asset']['versions']['original']['mime_type'] element = { src: url } tag_type = 'img' else @@ -41,5 +43,9 @@ def self.content_item_element(id) [element, tag_type] end + + def self.image?(mime_type) + MimeMagic.new(mime_type).mediatype == 'image' + end end end From b051b1abcf357581ada9a3eb1d8a64d4009ba67f Mon Sep 17 00:00:00 2001 From: Alex Tharp Date: Wed, 26 Apr 2017 02:42:58 -0500 Subject: [PATCH 16/18] chore: bump cortex-plugins-core --- Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index 5f14f4769..b8c31d0bb 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -7,7 +7,7 @@ GIT GIT remote: https://github.com/cortex-cms/cortex-plugins-core.git - revision: cc5f33441c2d229536ab0776d86aa197e37c9654 + revision: 233f7faa8fb97ebaa445153868fece219b4f4dc7 branch: topic/COR-704-Rebuild-AssetFieldType specs: cortex-plugins-core (0.11.2) From b7866f5dd23d0fc1ccd17e0a5f71e4befc0e4f33 Mon Sep 17 00:00:00 2001 From: ElliottAYoung Date: Wed, 26 Apr 2017 11:08:40 -0500 Subject: [PATCH 17/18] fix: category max validation - per @justin3thompson --- lib/tasks/employer/blog.rake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/tasks/employer/blog.rake b/lib/tasks/employer/blog.rake index 3effa229f..edcd164e5 100644 --- a/lib/tasks/employer/blog.rake +++ b/lib/tasks/employer/blog.rake @@ -76,7 +76,7 @@ namespace :employer do blog.fields.new(name: 'No ODP', field_type: 'boolean_field_type') blog.fields.new(name: 'No Archive', field_type: 'boolean_field_type') blog.fields.new(name: 'No Image Index', field_type: 'boolean_field_type') - blog.fields.new(name: 'Categories', field_type: 'tree_field_type', metadata: {allowed_values: category_tree}, validations: {maximum: 1, minimum: 1}) + blog.fields.new(name: 'Categories', field_type: 'tree_field_type', metadata: {allowed_values: category_tree}, validations: {maximum: 2, minimum: 1}) blog.fields.new(name: 'Research', field_type: 'tree_field_type', metadata: {allowed_values: research_tree}, validations: {minimum: 1}) blog.fields.new(name: 'Persona', field_type: 'tree_field_type', metadata: {allowed_values: persona_tree}) blog.fields.new(name: 'Featured Image', field_type: 'content_item_field_type', From 663a73fef0fad40114c843778c8841f69b226d88 Mon Sep 17 00:00:00 2001 From: ElliottAYoung Date: Wed, 26 Apr 2017 11:53:48 -0500 Subject: [PATCH 18/18] fix: remove minimum validations - per @justin3thompson --- lib/tasks/employer/blog.rake | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/tasks/employer/blog.rake b/lib/tasks/employer/blog.rake index edcd164e5..1f6560f6c 100644 --- a/lib/tasks/employer/blog.rake +++ b/lib/tasks/employer/blog.rake @@ -60,9 +60,9 @@ namespace :employer do puts "Creating Fields..." blog.fields.new(name: 'Body', field_type: 'text_field_type', metadata: {parse_widgets: true}, validations: { presence: true, length: { minimum: 50} }) - blog.fields.new(name: 'Title', field_type: 'text_field_type', validations: {presence: true, length: { maximum: 100, minimum: 60} }) + blog.fields.new(name: 'Title', field_type: 'text_field_type', validations: {presence: true, length: { maximum: 100 } }) blog.fields.new(name: 'Description', field_type: 'text_field_type', validations: {presence: true, length: { maximum: 200, minimum: 50} }) - blog.fields.new(name: 'Slug', field_type: 'text_field_type', validations: {presence: true, uniqueness: true, length: { maximum: 75, minimum: 30} }) + blog.fields.new(name: 'Slug', field_type: 'text_field_type', validations: {presence: true, uniqueness: true, length: { maximum: 75 } }) blog.fields.new(name: 'Author', field_type: 'author_field_type') blog.fields.new(name: 'Tags', field_type: 'tag_field_type') blog.fields.new(name: 'Publish Date', field_type: 'date_time_field_type')