From 528f0379ef7eab407fd4b837d76fcc97bc886de8 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Sun, 4 Sep 2016 23:57:30 -0500 Subject: [PATCH 01/29] Start work on SEO info in header --- Gemfile | 3 ++ Gemfile.lock | 3 ++ app/views/layouts/_seo.html.erb | 50 ++++++++++++++++++++++++++ app/views/layouts/application.html.erb | 4 ++- 4 files changed, 59 insertions(+), 1 deletion(-) create mode 100644 app/views/layouts/_seo.html.erb diff --git a/Gemfile b/Gemfile index 7e2d43b5..ebd700ce 100644 --- a/Gemfile +++ b/Gemfile @@ -26,6 +26,9 @@ gem 'jquery-rails' gem 'jquery-ui-rails' gem 'rails-jquery-autocomplete' +# SEO +gem 'meta-tags' + # Smarts # gem 'serendipitous', :path => "~/Code/indent/serendipitous-gem" gem 'serendipitous', git: 'git://github.com/indentlabs/serendipitous-gem.git' diff --git a/Gemfile.lock b/Gemfile.lock index 9fe868ff..83886477 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -164,6 +164,8 @@ GEM railties (>= 3.2) medium-editor-rails (2.2.0) railties (>= 3.0) + meta-tags (2.2.0) + actionpack (>= 3.2.0) method_source (0.8.2) mime-types (3.0) mime-types-data (~> 3.2015) @@ -317,6 +319,7 @@ DEPENDENCIES jquery-ui-rails material_icons medium-editor-rails + meta-tags paperclip (~> 4.2.0) pg pry diff --git a/app/views/layouts/_seo.html.erb b/app/views/layouts/_seo.html.erb new file mode 100644 index 00000000..60172194 --- /dev/null +++ b/app/views/layouts/_seo.html.erb @@ -0,0 +1,50 @@ +<%# This belongs inside the tag %> + + + +<%= + # Make sure description is no longer than 155 characters + site_name = "Notebook" + site_description = "Notebook is a set of tools for writers, game designers, and roleplayers to create magnificent universes, and everything within them." + site_url = request.host + site_image = "http://www.notebook.ai/assets/card-headers/hero-d5161eb41a02535f6656af83cacbdb8c.jpg" + + display_meta_tags description: site_description, + # Recommended keywords tag length: up to 255 characters, 20 words. + keywords: %w[writing author fiction character universe location nanowrimo], + canonical: site_url, + twitter: { + card: "summary_large_image", + title: site_name, + + # Page description must be less than 200 characters + + description: site_description, + creator: "@IndentLabs", + + # Twitter summary card with large image must be at least 280x150px + image: { + src: site_image + } + }, + og: { + title: site_name, + type: "website", + url: site_url, + image: site_image, + description: site_description, + site_name: site_name, + } + %> + diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb index 5acd21df..a2403b01 100644 --- a/app/views/layouts/application.html.erb +++ b/app/views/layouts/application.html.erb @@ -10,6 +10,9 @@ + + + <%= render 'layouts/seo' %> @@ -29,7 +32,6 @@ <%= render 'layouts/ganalytics' %> - <%= render 'layouts/footer' %> From c629bcf719d548a50e510fecc3f71a572c3ccf10 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Mon, 5 Sep 2016 00:19:08 -0500 Subject: [PATCH 02/29] Use ID-based G+ link for publisher --- app/views/layouts/_seo.html.erb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/layouts/_seo.html.erb b/app/views/layouts/_seo.html.erb index 60172194..ad438722 100644 --- a/app/views/layouts/_seo.html.erb +++ b/app/views/layouts/_seo.html.erb @@ -1,6 +1,6 @@ <%# This belongs inside the tag %> - + <%= # Make sure description is no longer than 155 characters From 92a269185dcfe2b0d12e7b0d617463bb99598209 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Mon, 5 Sep 2016 00:31:00 -0500 Subject: [PATCH 03/29] Add twitter:url, and split out display_meta_tags --- app/views/layouts/_seo.html.erb | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/app/views/layouts/_seo.html.erb b/app/views/layouts/_seo.html.erb index ad438722..b088632d 100644 --- a/app/views/layouts/_seo.html.erb +++ b/app/views/layouts/_seo.html.erb @@ -2,28 +2,25 @@ -<%= +<% # Make sure description is no longer than 155 characters site_name = "Notebook" site_description = "Notebook is a set of tools for writers, game designers, and roleplayers to create magnificent universes, and everything within them." site_url = request.host site_image = "http://www.notebook.ai/assets/card-headers/hero-d5161eb41a02535f6656af83cacbdb8c.jpg" - display_meta_tags description: site_description, + set_meta_tags description: site_description, # Recommended keywords tag length: up to 255 characters, 20 words. keywords: %w[writing author fiction character universe location nanowrimo], canonical: site_url, twitter: { - card: "summary_large_image", + card: "summary", title: site_name, - - # Page description must be less than 200 characters - - description: site_description, + url: site_url, + description: site_description, # Page description must be less than 200 characters creator: "@IndentLabs", - - # Twitter summary card with large image must be at least 280x150px image: { + # Twitter summary card with large image must be at least 280x150px src: site_image } }, @@ -36,6 +33,7 @@ site_name: site_name, } %> + <%= display_meta_tags %> +<%# Default values and pointers here only. +Most content should be set in the pages themselves %> +<%= display_meta_tags site: "Notebook", +publisher: "https://plus.google.com/118076966717703203223", +og: { + title: :title, + site_name: "Notebook", + image: :image_src, + url: request.url, + description: :description, +}, +twitter: { + card: "summary", + title: :title, + image: :image_src, + url: request.url, + description: :description +} %> + diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb index a2403b01..f181e22b 100644 --- a/app/views/layouts/application.html.erb +++ b/app/views/layouts/application.html.erb @@ -1,7 +1,6 @@ - <%= content_for?(:title) ? yield(:title) : 'Notebook' %> <%= stylesheet_link_tag 'application' %> <%= javascript_include_tag 'application' %> <%= csrf_meta_tags %> @@ -11,7 +10,7 @@ - + <%# is set in _seo.html.erb %> <%= render 'layouts/seo' %> </head> <body> diff --git a/app/views/main/index.html.erb b/app/views/main/index.html.erb index 51181999..c7aff17c 100644 --- a/app/views/main/index.html.erb +++ b/app/views/main/index.html.erb @@ -3,11 +3,12 @@ <div class="card"> <div class="card-image"> <%= image_tag 'card-headers/hero.jpg', width: '100%' %> + <% set_meta_tags image_src: image_url('card-headers/hero.jpg') %> <span class="card-title">Your digital notebook is here.</span> </div> <div class="card-content"> <h4> - Notebook is a set of tools for writers, game designers, and roleplayers to create magnificent universes – and everything within them. + <%= description 'Notebook is a set of tools for writers, game designers, and roleplayers to create magnificent universes – and everything within them.' %> </h4> <p> From a simple interface in your browser, on your phone, or on your tablet, you can do everything you'd ever want to do while creating your own little (or big!) world. @@ -19,4 +20,3 @@ </div> </div> </div> - From 9c1f9fdb603cc54ca69996a9b2d402ef3c235c7e Mon Sep 17 00:00:00 2001 From: Robert Richter <robert.c.richter@gmail.com> Date: Mon, 5 Sep 2016 16:53:15 -0500 Subject: [PATCH 06/29] Add keywords to main page --- app/views/main/index.html.erb | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/views/main/index.html.erb b/app/views/main/index.html.erb index c7aff17c..8b676b22 100644 --- a/app/views/main/index.html.erb +++ b/app/views/main/index.html.erb @@ -1,3 +1,6 @@ +<%# Recommended keywords tag length: up to 255 characters, 20 words. %> +<% set_meta_tags keywords: %w[writing author nanowrimo novel character fiction fantasy universe creative dnd roleplay larp game design] %> + <div class="row"> <div class="col s12"> <div class="card"> From 1e5658c77140438775de38cd24fecf5397b69f85 Mon Sep 17 00:00:00 2001 From: Robert Richter <robert.c.richter@gmail.com> Date: Tue, 6 Sep 2016 09:20:55 -0500 Subject: [PATCH 07/29] Add sitemap gem --- .gitignore | 1 + Gemfile | 1 + Gemfile.lock | 3 +++ config/sitemap.rb | 40 ++++++++++++++++++++++++++++++++++++++++ public/robots.txt | 2 ++ 5 files changed, 47 insertions(+) create mode 100644 config/sitemap.rb diff --git a/.gitignore b/.gitignore index f35b9ea9..64f5e1ff 100644 --- a/.gitignore +++ b/.gitignore @@ -28,3 +28,4 @@ set_aws_credentials.sh # Ignore map images uploaded to Locations /locations +public/sitemap.xml.gz diff --git a/Gemfile b/Gemfile index ebd700ce..2a4ec799 100644 --- a/Gemfile +++ b/Gemfile @@ -28,6 +28,7 @@ gem 'rails-jquery-autocomplete' # SEO gem 'meta-tags' +gem 'sitemap_generator' # Smarts # gem 'serendipitous', :path => "~/Code/indent/serendipitous-gem" diff --git a/Gemfile.lock b/Gemfile.lock index 83886477..e3f3aad2 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -263,6 +263,8 @@ GEM json (~> 1.8) simplecov-html (~> 0.10.0) simplecov-html (0.10.0) + sitemap_generator (5.1.0) + builder slop (3.6.0) sprockets (2.12.4) hike (~> 1.2) @@ -334,6 +336,7 @@ DEPENDENCIES selenium-webdriver serendipitous! simplecov + sitemap_generator sqlite3 therubyracer tzinfo-data diff --git a/config/sitemap.rb b/config/sitemap.rb new file mode 100644 index 00000000..30af74e3 --- /dev/null +++ b/config/sitemap.rb @@ -0,0 +1,40 @@ +# Set the host name for URL creation +SitemapGenerator::Sitemap.default_host = 'http://www.notebook.ai' + +SitemapGenerator::Sitemap.create do + # Put links creation logic here. + # + # The root path '/' and sitemap index file are added automatically for you. + # Links are added to the Sitemap in the order they are specified. + # + # Usage: add(path, options={}) + # (default options are used if you don't specify) + # + # Defaults: :priority => 0.5, :changefreq => 'weekly', + # :lastmod => Time.now, :host => default_host + # + # Examples: + # + # Add '/articles' + # + # add articles_path, :priority => 0.7, :changefreq => 'daily' + # + # Add all articles: + # + # Article.find_each do |article| + # add article_path(article), :lastmod => article.updated_at + # end + + # Add all public universes, and characters & locations that belong to them + Universe.where(privacy: 'public').find_each do |universe| + add universe_path(universe), lastmod: universe.updated_at + + Character.where(universe: universe).find_each do |character| + add character_path(character), lastmod: character.updated_at + end + + Location.where(universe: universe).find_each do |location| + add location_path(location), lastmod: location.updated_at + end + end +end diff --git a/public/robots.txt b/public/robots.txt index 085187fa..167e6b0a 100644 --- a/public/robots.txt +++ b/public/robots.txt @@ -3,3 +3,5 @@ # To ban all spiders from the entire site uncomment the next two lines: # User-Agent: * # Disallow: / + +Sitemap: http://www.notebook.ai/sitemap.xml.gz From 2d65d86601b921ba0081c7bcdb3480be9e23a32b Mon Sep 17 00:00:00 2001 From: Robert Richter <robert.c.richter@gmail.com> Date: Tue, 6 Sep 2016 09:25:15 -0500 Subject: [PATCH 08/29] Add user profiles to sitemap --- config/sitemap.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/config/sitemap.rb b/config/sitemap.rb index 30af74e3..4beec779 100644 --- a/config/sitemap.rb +++ b/config/sitemap.rb @@ -37,4 +37,8 @@ SitemapGenerator::Sitemap.create do add location_path(location), lastmod: location.updated_at end end + + User.find_each do |user| + add user_path(user), lastmod: user.updated_at + end end From ccc2aeef24b9ae3f703333836542a4f5ef044961 Mon Sep 17 00:00:00 2001 From: Robert Richter <robert.c.richter@gmail.com> Date: Tue, 6 Sep 2016 10:23:05 -0500 Subject: [PATCH 09/29] Add JSON LD blocks to User pages --- Gemfile | 1 + Gemfile.lock | 4 ++++ app/models/user.rb | 27 +++++++++++++++++++++++++++ app/views/users/show.html.erb | 7 +++++++ config/environments/development.rb | 2 ++ config/environments/production.rb | 2 ++ config/environments/test.rb | 2 ++ 7 files changed, 45 insertions(+) diff --git a/Gemfile b/Gemfile index 2a4ec799..f0f37bad 100644 --- a/Gemfile +++ b/Gemfile @@ -29,6 +29,7 @@ gem 'rails-jquery-autocomplete' # SEO gem 'meta-tags' gem 'sitemap_generator' +gem 'pragmatic_context' # Smarts # gem 'serendipitous', :path => "~/Code/indent/serendipitous-gem" diff --git a/Gemfile.lock b/Gemfile.lock index e3f3aad2..b9b6db1e 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -190,6 +190,9 @@ GEM ast (~> 2.2) pg (0.18.4) powerpack (0.1.1) + pragmatic_context (0.2.1) + activemodel + activesupport pry (0.10.3) coderay (~> 1.1.0) method_source (~> 0.8.1) @@ -324,6 +327,7 @@ DEPENDENCIES meta-tags paperclip (~> 4.2.0) pg + pragmatic_context pry rails rails-jquery-autocomplete diff --git a/app/models/user.rb b/app/models/user.rb index 11d01ba5..de5f0d2a 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -1,6 +1,7 @@ ## # a person using the Indent web application. Owns all other content. class User < ActiveRecord::Base + include PragmaticContext::Contextualizable # Include default devise modules. Others available are: # :confirmable, :lockable, :timeoutable and :omniauthable devise :database_authenticatable, :registerable, @@ -16,6 +17,32 @@ class User < ActiveRecord::Base has_many :magics has_many :universes + # Used for JSON-LD generation + contextualize_as_type 'http://schema.org/Person' + contextualize_with_id { |user| Rails.application.routes.url_helpers.user_url(user) } + contextualize :name, :as => 'http://schema.org/alternateName' + contextualize :email, :as => 'http://schema.org/email' + + # as_json would try to print the password digest, which requires authentication + def as_json(options={}) + excludes = [:password_digest, :old_password] + options = {} if options.nil? + options[:except] ||= excludes + super(options) + end + + def to_json(options={}) + options[:except] ||= [:password_digest, :old_password] + super(options) + end + + # We have "as_json," "to_json," and "to_xml" to worry about. "to_json" doesn't print passwords + + def to_xml(options={}) + options[:except] ||= [:password_digest, :old_password] + super(options) + end + def content { characters: characters, diff --git a/app/views/users/show.html.erb b/app/views/users/show.html.erb index 0e971604..fbabbb5d 100644 --- a/app/views/users/show.html.erb +++ b/app/views/users/show.html.erb @@ -1,3 +1,10 @@ + +<% if @user.present? && @user.respond_to?(:as_jsonld) %> +<script type="application/ld+json"> + <%= @user.as_jsonld.to_json.html_safe %> +</script> +<% end %> + <% tabs = %w(universes characters locations items) diff --git a/config/environments/development.rb b/config/environments/development.rb index 362f7c58..3f340728 100644 --- a/config/environments/development.rb +++ b/config/environments/development.rb @@ -39,4 +39,6 @@ PlanCharacters::Application.configure do secret_access_key: ENV['AWS_SECRET_ACCESS_KEY'] } } + + default_url_options[:host] = 'localhost:3000' end diff --git a/config/environments/production.rb b/config/environments/production.rb index 889f2eec..9afa9692 100644 --- a/config/environments/production.rb +++ b/config/environments/production.rb @@ -91,4 +91,6 @@ Rails.application.configure do # Do not dump schema after migrations. # TODO: double check this config.active_record.dump_schema_after_migration = false + + default_url_options[:host] = 'www.notebook.ai' end diff --git a/config/environments/test.rb b/config/environments/test.rb index da1933d6..c228c40d 100644 --- a/config/environments/test.rb +++ b/config/environments/test.rb @@ -36,4 +36,6 @@ Rails.application.configure do config.active_support.test_order = :random config.active_record.raise_in_transactional_callbacks = true + + default_url_options[:host] = 'localhost:3000' end From b817cdf1fe71811efa65d4e3f9afe24304dce348 Mon Sep 17 00:00:00 2001 From: Robert Richter <robert.c.richter@gmail.com> Date: Tue, 6 Sep 2016 10:36:16 -0500 Subject: [PATCH 10/29] Add JSON-LD to Universes --- app/models/universe.rb | 12 ++++++++++++ app/views/content/_show.html.erb | 7 +++++++ 2 files changed, 19 insertions(+) diff --git a/app/models/universe.rb b/app/models/universe.rb index d0c446fc..86a5a547 100644 --- a/app/models/universe.rb +++ b/app/models/universe.rb @@ -6,6 +6,7 @@ # # contains all canonically-related content created by Users class Universe < ActiveRecord::Base + include PragmaticContext::Contextualizable validates :name, presence: true belongs_to :user @@ -15,6 +16,17 @@ class Universe < ActiveRecord::Base scope :is_public, -> { where(privacy: "public") } + # Used for JSON-LD generation + contextualize_as_type 'http://schema.org/CreativeWork' + contextualize_with_id { |universe| Rails.application.routes.url_helpers.universe_url(universe) } + contextualize :user, as: 'http://schema.org/author' + contextualize :user, as: 'http://schema.org/copyrightHolder' + contextualize :characters, as: 'http://schema.org/character' + contextualize :items, as: 'http://schema.org/hasPart' + contextualize :locations, as: 'http://schema.org/hasPart' + contextualize :name, :as => 'http://schema.org/name' + contextualize :description, :as => 'http://schema.org/description' + def content_count [ characters.length, diff --git a/app/views/content/_show.html.erb b/app/views/content/_show.html.erb index 15d84723..d3ee89de 100644 --- a/app/views/content/_show.html.erb +++ b/app/views/content/_show.html.erb @@ -1,3 +1,10 @@ +<% if @content.present? && @content.respond_to?(:as_jsonld) %> +<script type="application/ld+json"> + <%= @content.as_jsonld.to_json.html_safe %> +</script> +<% end %> + + <% title @content.name %> <% content_for :sidebar_top do %> From 3b11cea630f1f030f82afa587cc936a7b6aa9079 Mon Sep 17 00:00:00 2001 From: Robert Richter <robert.c.richter@gmail.com> Date: Tue, 6 Sep 2016 18:37:15 -0500 Subject: [PATCH 11/29] Remove practmatic_context gem Use some simple hand-written JSON-LD for now --- Gemfile | 1 - app/views/characters/show.html.erb | 13 +++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/Gemfile b/Gemfile index f0f37bad..2a4ec799 100644 --- a/Gemfile +++ b/Gemfile @@ -29,7 +29,6 @@ gem 'rails-jquery-autocomplete' # SEO gem 'meta-tags' gem 'sitemap_generator' -gem 'pragmatic_context' # Smarts # gem 'serendipitous', :path => "~/Code/indent/serendipitous-gem" diff --git a/app/views/characters/show.html.erb b/app/views/characters/show.html.erb index b14974f0..a7b3eda3 100644 --- a/app/views/characters/show.html.erb +++ b/app/views/characters/show.html.erb @@ -1 +1,14 @@ +<%# to_json will escape any values into unicode escape sequences, so we can call html_safe %> + +<script type="application/ld+json"> +<% +content_jsonld = { + '@id': character_url, + '@type': 'http://schema.org/Person', + 'http://schema.org/name': @content.name +} +%> +<%= content_jsonld.to_json.html_safe %> +</script> + <%= render partial: 'content/show', locals: { content: @content } %> From 472bb6125a91c84c958527c6683774bcb6fa28e6 Mon Sep 17 00:00:00 2001 From: Robert Richter <robert.c.richter@gmail.com> Date: Tue, 6 Sep 2016 18:43:18 -0500 Subject: [PATCH 12/29] Remove pragmatic_context from User --- app/models/user.rb | 7 ------- 1 file changed, 7 deletions(-) diff --git a/app/models/user.rb b/app/models/user.rb index de5f0d2a..f9fd6393 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -1,7 +1,6 @@ ## # a person using the Indent web application. Owns all other content. class User < ActiveRecord::Base - include PragmaticContext::Contextualizable # Include default devise modules. Others available are: # :confirmable, :lockable, :timeoutable and :omniauthable devise :database_authenticatable, :registerable, @@ -17,12 +16,6 @@ class User < ActiveRecord::Base has_many :magics has_many :universes - # Used for JSON-LD generation - contextualize_as_type 'http://schema.org/Person' - contextualize_with_id { |user| Rails.application.routes.url_helpers.user_url(user) } - contextualize :name, :as => 'http://schema.org/alternateName' - contextualize :email, :as => 'http://schema.org/email' - # as_json would try to print the password digest, which requires authentication def as_json(options={}) excludes = [:password_digest, :old_password] From a90dda4f275cab68a2bce9f997419ff68275c695 Mon Sep 17 00:00:00 2001 From: Robert Richter <robert.c.richter@gmail.com> Date: Tue, 6 Sep 2016 18:47:21 -0500 Subject: [PATCH 13/29] Add ID and Name JSON LD to all content show pages --- app/views/items/show.html.erb | 11 +++++++++++ app/views/locations/show.html.erb | 10 ++++++++++ app/views/universes/show.html.erb | 12 +++++++++++- app/views/users/show.html.erb | 13 +++++++++---- 4 files changed, 41 insertions(+), 5 deletions(-) diff --git a/app/views/items/show.html.erb b/app/views/items/show.html.erb index b14974f0..4c296455 100644 --- a/app/views/items/show.html.erb +++ b/app/views/items/show.html.erb @@ -1 +1,12 @@ +<script type="application/ld+json"> +<% +content_jsonld = { + '@id': item_url, + '@type': 'http://schema.org/Thing', + 'http://schema.org/name': @content.name +} +%> +<%= content_jsonld.to_json.html_safe %> +</script> + <%= render partial: 'content/show', locals: { content: @content } %> diff --git a/app/views/locations/show.html.erb b/app/views/locations/show.html.erb index b14974f0..8f569b78 100644 --- a/app/views/locations/show.html.erb +++ b/app/views/locations/show.html.erb @@ -1 +1,11 @@ +<script type="application/ld+json"> +<% +content_jsonld = { + '@id': item_url, + '@type': 'http://schema.org/Place', + 'http://schema.org/name': @content.name +} +%> +<%= content_jsonld.to_json.html_safe %> + <%= render partial: 'content/show', locals: { content: @content } %> diff --git a/app/views/universes/show.html.erb b/app/views/universes/show.html.erb index 42b8b9f4..689bf468 100644 --- a/app/views/universes/show.html.erb +++ b/app/views/universes/show.html.erb @@ -1,3 +1,13 @@ +<script type="application/ld+json"> +<% +content_jsonld = { + '@id': item_url, + '@type': 'http://schema.org/Place', + 'http://schema.org/name': @content.name +} +%> +<%= content_jsonld.to_json.html_safe %> + <%= render partial: 'content/show', locals: { content: @content } %> <div class="col s12 m12 l4"> @@ -10,4 +20,4 @@ <div class="col s12 m12 l4"> <%= render partial: 'content/cards/in_universe_content_list', locals: { content_type: :item, content_list: @content.items } %> -</div> \ No newline at end of file +</div> diff --git a/app/views/users/show.html.erb b/app/views/users/show.html.erb index fbabbb5d..2bf8cbde 100644 --- a/app/views/users/show.html.erb +++ b/app/views/users/show.html.erb @@ -1,9 +1,14 @@ - -<% if @user.present? && @user.respond_to?(:as_jsonld) %> <script type="application/ld+json"> - <%= @user.as_jsonld.to_json.html_safe %> +<% +content_jsonld = { + '@id': user_url, + '@type': 'http://schema.org/Person', + 'http://schema.org/name': @user.name, + 'http://schema.org/description': "#{@user.name}'s profile on notebook.ai" +} +%> +<%= content_jsonld.to_json.html_safe %> %> </script> -<% end %> <% tabs = %w(universes characters locations items) From b17f3fb108288ca01a113d9a80931cb36da8e004 Mon Sep 17 00:00:00 2001 From: Robert Richter <robert.c.richter@gmail.com> Date: Tue, 6 Sep 2016 18:50:42 -0500 Subject: [PATCH 14/29] Remove pragmatic_context from Universes --- app/models/universe.rb | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/app/models/universe.rb b/app/models/universe.rb index 86a5a547..d0c446fc 100644 --- a/app/models/universe.rb +++ b/app/models/universe.rb @@ -6,7 +6,6 @@ # # contains all canonically-related content created by Users class Universe < ActiveRecord::Base - include PragmaticContext::Contextualizable validates :name, presence: true belongs_to :user @@ -16,17 +15,6 @@ class Universe < ActiveRecord::Base scope :is_public, -> { where(privacy: "public") } - # Used for JSON-LD generation - contextualize_as_type 'http://schema.org/CreativeWork' - contextualize_with_id { |universe| Rails.application.routes.url_helpers.universe_url(universe) } - contextualize :user, as: 'http://schema.org/author' - contextualize :user, as: 'http://schema.org/copyrightHolder' - contextualize :characters, as: 'http://schema.org/character' - contextualize :items, as: 'http://schema.org/hasPart' - contextualize :locations, as: 'http://schema.org/hasPart' - contextualize :name, :as => 'http://schema.org/name' - contextualize :description, :as => 'http://schema.org/description' - def content_count [ characters.length, From 8998a0fbf3de2bd0ca4da3e2f5202db3d42687da Mon Sep 17 00:00:00 2001 From: Andrew Brown <drusepth@gmail.com> Date: Wed, 14 Sep 2016 22:12:37 -0500 Subject: [PATCH 15/29] Update footer link to source code, fixes #34 --- app/views/layouts/_footer.html.erb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/layouts/_footer.html.erb b/app/views/layouts/_footer.html.erb index b3d952cf..cb77e1fe 100644 --- a/app/views/layouts/_footer.html.erb +++ b/app/views/layouts/_footer.html.erb @@ -19,7 +19,7 @@ <div class="col s12"> <div class="grey-text"> <a href="/about/privacy" class="white-text">Privacy Policy</a> / - <a href="https://github.com/indentlabs/Indent" class="white-text">Source Code</a> + <a href="https://github.com/indentlabs/notebook" class="white-text">Source Code</a> </div> </div> </div> From 96a35cbb8c0763db1d26d815e4cb977c7865ac83 Mon Sep 17 00:00:00 2001 From: Ashley Sullins <ashley.sullins@gmail.com> Date: Sun, 18 Sep 2016 23:06:30 -0500 Subject: [PATCH 16/29] Edit readme --- README.rdoc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.rdoc b/README.rdoc index 8e9eed25..cd103b01 100644 --- a/README.rdoc +++ b/README.rdoc @@ -61,6 +61,10 @@ Install gems bundle install +Run initial database migrations + + rake db:migrate + Optional: To enable the uploading and editing of images (used in Locations management, etc), you will need to create a file named set_aws_credentials.rb with the following content: [[ $_ != $0 ]] && echo "Ready to run your server!" || echo "This script needs to be sourced!" From 15b6f0d9377567e2616e7d98db91f9800e014fa1 Mon Sep 17 00:00:00 2001 From: Robert Richter <robert.c.richter@gmail.com> Date: Mon, 19 Sep 2016 21:16:29 -0500 Subject: [PATCH 17/29] Bundle update --- Gemfile.lock | 4 ---- 1 file changed, 4 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index b9b6db1e..e3f3aad2 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -190,9 +190,6 @@ GEM ast (~> 2.2) pg (0.18.4) powerpack (0.1.1) - pragmatic_context (0.2.1) - activemodel - activesupport pry (0.10.3) coderay (~> 1.1.0) method_source (~> 0.8.1) @@ -327,7 +324,6 @@ DEPENDENCIES meta-tags paperclip (~> 4.2.0) pg - pragmatic_context pry rails rails-jquery-autocomplete From 6fec224fd0831bf7b99ff59580922808d0ca2ab5 Mon Sep 17 00:00:00 2001 From: Robert Richter <robert.c.richter@gmail.com> Date: Mon, 19 Sep 2016 21:16:52 -0500 Subject: [PATCH 18/29] Close a tag I missed --- app/views/locations/show.html.erb | 1 + 1 file changed, 1 insertion(+) diff --git a/app/views/locations/show.html.erb b/app/views/locations/show.html.erb index 8f569b78..96ba891e 100644 --- a/app/views/locations/show.html.erb +++ b/app/views/locations/show.html.erb @@ -7,5 +7,6 @@ content_jsonld = { } %> <%= content_jsonld.to_json.html_safe %> +</script> <%= render partial: 'content/show', locals: { content: @content } %> From cd820206aa2384a5aefb93d494b562830614776b Mon Sep 17 00:00:00 2001 From: Robert Richter <robert.c.richter@gmail.com> Date: Mon, 19 Sep 2016 21:58:40 -0500 Subject: [PATCH 19/29] Close another tag I missed --- app/views/universes/show.html.erb | 1 + 1 file changed, 1 insertion(+) diff --git a/app/views/universes/show.html.erb b/app/views/universes/show.html.erb index 689bf468..2dcdb0f2 100644 --- a/app/views/universes/show.html.erb +++ b/app/views/universes/show.html.erb @@ -7,6 +7,7 @@ content_jsonld = { } %> <%= content_jsonld.to_json.html_safe %> +</script> <%= render partial: 'content/show', locals: { content: @content } %> From aa83c3a723d647bc4e422138f7aac438ad04a2da Mon Sep 17 00:00:00 2001 From: Robert Richter <robert.c.richter@gmail.com> Date: Mon, 19 Sep 2016 22:00:07 -0500 Subject: [PATCH 20/29] Remove sitemap stuff, for now --- Gemfile | 1 - Gemfile.lock | 3 --- config/sitemap.rb | 44 -------------------------------------------- public/robots.txt | 2 -- 4 files changed, 50 deletions(-) delete mode 100644 config/sitemap.rb diff --git a/Gemfile b/Gemfile index 2a4ec799..ebd700ce 100644 --- a/Gemfile +++ b/Gemfile @@ -28,7 +28,6 @@ gem 'rails-jquery-autocomplete' # SEO gem 'meta-tags' -gem 'sitemap_generator' # Smarts # gem 'serendipitous', :path => "~/Code/indent/serendipitous-gem" diff --git a/Gemfile.lock b/Gemfile.lock index e3f3aad2..83886477 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -263,8 +263,6 @@ GEM json (~> 1.8) simplecov-html (~> 0.10.0) simplecov-html (0.10.0) - sitemap_generator (5.1.0) - builder slop (3.6.0) sprockets (2.12.4) hike (~> 1.2) @@ -336,7 +334,6 @@ DEPENDENCIES selenium-webdriver serendipitous! simplecov - sitemap_generator sqlite3 therubyracer tzinfo-data diff --git a/config/sitemap.rb b/config/sitemap.rb deleted file mode 100644 index 4beec779..00000000 --- a/config/sitemap.rb +++ /dev/null @@ -1,44 +0,0 @@ -# Set the host name for URL creation -SitemapGenerator::Sitemap.default_host = 'http://www.notebook.ai' - -SitemapGenerator::Sitemap.create do - # Put links creation logic here. - # - # The root path '/' and sitemap index file are added automatically for you. - # Links are added to the Sitemap in the order they are specified. - # - # Usage: add(path, options={}) - # (default options are used if you don't specify) - # - # Defaults: :priority => 0.5, :changefreq => 'weekly', - # :lastmod => Time.now, :host => default_host - # - # Examples: - # - # Add '/articles' - # - # add articles_path, :priority => 0.7, :changefreq => 'daily' - # - # Add all articles: - # - # Article.find_each do |article| - # add article_path(article), :lastmod => article.updated_at - # end - - # Add all public universes, and characters & locations that belong to them - Universe.where(privacy: 'public').find_each do |universe| - add universe_path(universe), lastmod: universe.updated_at - - Character.where(universe: universe).find_each do |character| - add character_path(character), lastmod: character.updated_at - end - - Location.where(universe: universe).find_each do |location| - add location_path(location), lastmod: location.updated_at - end - end - - User.find_each do |user| - add user_path(user), lastmod: user.updated_at - end -end diff --git a/public/robots.txt b/public/robots.txt index 167e6b0a..085187fa 100644 --- a/public/robots.txt +++ b/public/robots.txt @@ -3,5 +3,3 @@ # To ban all spiders from the entire site uncomment the next two lines: # User-Agent: * # Disallow: / - -Sitemap: http://www.notebook.ai/sitemap.xml.gz From f18404290acd51d1e6a3bd4e95f8e92e967cde6d Mon Sep 17 00:00:00 2001 From: Robert Richter <robert.c.richter@gmail.com> Date: Tue, 20 Sep 2016 18:31:26 -0500 Subject: [PATCH 21/29] Write a universes integration test --- test/integration/universe_stories_test.rb | 43 +++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 test/integration/universe_stories_test.rb diff --git a/test/integration/universe_stories_test.rb b/test/integration/universe_stories_test.rb new file mode 100644 index 00000000..ab3704e6 --- /dev/null +++ b/test/integration/universe_stories_test.rb @@ -0,0 +1,43 @@ +require 'test_helper' + +# Tests scenarios related to interacting with Universes +class UniverseStoriesTest < ActionDispatch::IntegrationTest + setup do + @user = log_in_as_user + @universe = create(:universe, user: @user) + end + + test 'universe is displayed on universes list' do + visit universes_path + assert page.has_content?(@universe.name), + "Page body didn't contain universe name: "\ + "#{@universe.name} not found in \n#{page.body}" + end + + test 'universe list edit button edits universe' do + visit universe_path(@universe) + click_on 'Edit this universe' + assert_equal edit_universe_path(@universe), current_path + end + + test 'universe list view button shows universe' do + visit universes_path + within(:css, '.collection-item:first') do + click_on @universe.name + end + assert_equal universe_path(@universe), current_path, + "Not on universe path for universe #{@universe.name}: "\ + "#{@universe.name} not found in \n#{page.body}" + end + + test 'a user can create a new universe' do + new_universe = build(:universe) + visit universes_path + click_on 'Create another universe' + fill_in 'universe_name', with: new_universe.name + click_on 'Create Universe' + + assert_equal universe_path(Universe.where(name: new_universe.name).first), + current_path + end +end From e8dc289ff800e51f9179ed909f86157c442bb6f6 Mon Sep 17 00:00:00 2001 From: Robert Richter <robert.c.richter@gmail.com> Date: Tue, 20 Sep 2016 18:32:08 -0500 Subject: [PATCH 22/29] Restructure meta tags for content --- app/views/layouts/_seo.html.erb | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/app/views/layouts/_seo.html.erb b/app/views/layouts/_seo.html.erb index 88b0805d..9d79ae6e 100644 --- a/app/views/layouts/_seo.html.erb +++ b/app/views/layouts/_seo.html.erb @@ -1,22 +1,38 @@ <%# This belongs inside the <head> tag %> -<!-- Begin SEO partial --> <%# Default values and pointers here only. Most content should be set in the pages themselves %> -<%= display_meta_tags site: "Notebook", + +<% +# default & site-wide values + +set_meta_tags site: "Notebook", publisher: "https://plus.google.com/118076966717703203223", +image_src: image_url('card-headers/hero.png'), og: { title: :title, site_name: "Notebook", - image: :image_src, url: request.url, + image: :image_src, description: :description, }, twitter: { card: "summary", title: :title, + site: '@IndentLabs', image: :image_src, url: request.url, description: :description -} %> +} + +# Content-specific values. These MUST be set before display_meta_tags, or else +# they won't make it into the HTML + +if @content.present? + set_meta_tags(title: @content.name) if @content.respond_to?(:name) + set_meta_tags(description: @content.description) if @content.respond_to?(:description) +end +%> + +<%= display_meta_tags %> <!-- End SEO partial --> From a7441a3b9a2032b5e789288034db7e7a44ad1e6b Mon Sep 17 00:00:00 2001 From: Robert Richter <robert.c.richter@gmail.com> Date: Wed, 21 Sep 2016 11:13:44 -0500 Subject: [PATCH 23/29] Restructured meta tags --- app/views/content/_show.html.erb | 5 ++++- app/views/layouts/_seo.html.erb | 33 ++++++++++++-------------------- 2 files changed, 16 insertions(+), 22 deletions(-) diff --git a/app/views/content/_show.html.erb b/app/views/content/_show.html.erb index d3ee89de..8f12979a 100644 --- a/app/views/content/_show.html.erb +++ b/app/views/content/_show.html.erb @@ -4,8 +4,11 @@ </script> <% end %> +<% +set_meta_tags title: content.name, description: content.description +%> + -<% title @content.name %> <% content_for :sidebar_top do %> <%= render partial: 'cards/serendipitous/content_question', locals: { question: @question, content: @content } %> diff --git a/app/views/layouts/_seo.html.erb b/app/views/layouts/_seo.html.erb index 9d79ae6e..47cd75cf 100644 --- a/app/views/layouts/_seo.html.erb +++ b/app/views/layouts/_seo.html.erb @@ -1,38 +1,29 @@ -<%# This belongs inside the <head> tag %> +<!-- SEO --> +<%= +# This belongs inside the <head> tag. +# Default values and pointers here only. +# Most content should be set in the pages themselves. +# Any values set here can be overridden. -<%# Default values and pointers here only. -Most content should be set in the pages themselves %> +# Default & site-wide values -<% -# default & site-wide values - -set_meta_tags site: "Notebook", -publisher: "https://plus.google.com/118076966717703203223", +display_meta_tags site: 'Notebook', +publisher: 'https://plus.google.com/118076966717703203223', image_src: image_url('card-headers/hero.png'), og: { title: :title, - site_name: "Notebook", + site_name: 'Notebook', url: request.url, image: :image_src, description: :description, }, twitter: { - card: "summary", + card: 'summary', title: :title, site: '@IndentLabs', image: :image_src, url: request.url, description: :description } - -# Content-specific values. These MUST be set before display_meta_tags, or else -# they won't make it into the HTML - -if @content.present? - set_meta_tags(title: @content.name) if @content.respond_to?(:name) - set_meta_tags(description: @content.description) if @content.respond_to?(:description) -end %> - -<%= display_meta_tags %> -<!-- End SEO partial --> +<!-- End SEO --> From 961dc903fc85e5a188d644c5c2589558a62bc3a4 Mon Sep 17 00:00:00 2001 From: Robert Richter <robert.c.richter@gmail.com> Date: Wed, 21 Sep 2016 11:29:04 -0500 Subject: [PATCH 24/29] Add newline to end of file --- app/views/main/dashboard.html.erb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/main/dashboard.html.erb b/app/views/main/dashboard.html.erb index 88419bd3..26223218 100644 --- a/app/views/main/dashboard.html.erb +++ b/app/views/main/dashboard.html.erb @@ -211,4 +211,4 @@ </div> </div> -</div> \ No newline at end of file +</div> From 37a5898b654658491c9e49f6a23a4873a153b46f Mon Sep 17 00:00:00 2001 From: Robert Richter <robert.c.richter@gmail.com> Date: Wed, 21 Sep 2016 11:30:10 -0500 Subject: [PATCH 25/29] Add meta info to privacy policy --- app/views/main/privacyinfo.html.erb | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/app/views/main/privacyinfo.html.erb b/app/views/main/privacyinfo.html.erb index b818af3a..4febb104 100644 --- a/app/views/main/privacyinfo.html.erb +++ b/app/views/main/privacyinfo.html.erb @@ -1,3 +1,8 @@ +<% +set_meta_tags title: 'Privacy Policy', +description: 'Notebook will always do its best to maintain the security and privacy of your data, in order to ensure that it is you and only you that has access to view, modify, or remove it, unless you explicitly designate otherwise.' +%> + <div class="row"> <div class="col s12 m12 l12"> <div class="card hoverable" style="padding: 30px;"> @@ -26,4 +31,4 @@ <div class="card-comments"></div> </div> </div> -</div> \ No newline at end of file +</div> From 67a3cfa3b7ec088e200895794df89db57f21f56a Mon Sep 17 00:00:00 2001 From: Robert Richter <robert.c.richter@gmail.com> Date: Wed, 21 Sep 2016 11:35:37 -0500 Subject: [PATCH 26/29] Move description and keywords into layout --- app/views/layouts/_seo.html.erb | 3 +++ app/views/main/index.html.erb | 6 +----- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/app/views/layouts/_seo.html.erb b/app/views/layouts/_seo.html.erb index 47cd75cf..11b13053 100644 --- a/app/views/layouts/_seo.html.erb +++ b/app/views/layouts/_seo.html.erb @@ -10,6 +10,9 @@ display_meta_tags site: 'Notebook', publisher: 'https://plus.google.com/118076966717703203223', image_src: image_url('card-headers/hero.png'), +description: 'Notebook is a set of tools for writers, game designers, and roleplayers to create magnificent universes — and everything within them.', +# Recommended keywords tag length: up to 255 characters, 20 words. +keywords: %w[writing author nanowrimo novel character fiction fantasy universe creative dnd roleplay larp game design], og: { title: :title, site_name: 'Notebook', diff --git a/app/views/main/index.html.erb b/app/views/main/index.html.erb index 8b676b22..92981e3e 100644 --- a/app/views/main/index.html.erb +++ b/app/views/main/index.html.erb @@ -1,17 +1,13 @@ -<%# Recommended keywords tag length: up to 255 characters, 20 words. %> -<% set_meta_tags keywords: %w[writing author nanowrimo novel character fiction fantasy universe creative dnd roleplay larp game design] %> - <div class="row"> <div class="col s12"> <div class="card"> <div class="card-image"> <%= image_tag 'card-headers/hero.jpg', width: '100%' %> - <% set_meta_tags image_src: image_url('card-headers/hero.jpg') %> <span class="card-title">Your digital notebook is here.</span> </div> <div class="card-content"> <h4> - <%= description 'Notebook is a set of tools for writers, game designers, and roleplayers to create magnificent universes – and everything within them.' %> + Notebook is a set of tools for writers, game designers, and roleplayers to create magnificent universes – and everything within them. </h4> <p> From a simple interface in your browser, on your phone, or on your tablet, you can do everything you'd ever want to do while creating your own little (or big!) world. From 0487cc09b2ad424b5bf93814f908aa4d7cb1ce1e Mon Sep 17 00:00:00 2001 From: Robert Richter <robert.c.richter@gmail.com> Date: Wed, 21 Sep 2016 11:44:08 -0500 Subject: [PATCH 27/29] Extract blacklisted User attributes into a method --- app/models/user.rb | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/app/models/user.rb b/app/models/user.rb index f9fd6393..5110ea7f 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -16,23 +16,22 @@ class User < ActiveRecord::Base has_many :magics has_many :universes - # as_json would try to print the password digest, which requires authentication + # as_json creates a hash structure, which you then pass to ActiveSupport::json.encode to actually encode the object as a JSON string. + # This is different from to_json, which converts it straight to an escaped JSON string, + # which is undesireable in a case like this, when we want to modify it def as_json(options={}) - excludes = [:password_digest, :old_password] - options = {} if options.nil? - options[:except] ||= excludes + options[:except] ||= blacklisted_attributes super(options) end + # Returns this object as an escaped JSON string def to_json(options={}) - options[:except] ||= [:password_digest, :old_password] + options[:except] ||= blacklisted_attributes super(options) end - # We have "as_json," "to_json," and "to_xml" to worry about. "to_json" doesn't print passwords - def to_xml(options={}) - options[:except] ||= [:password_digest, :old_password] + options[:except] ||= blacklisted_attributes super(options) end @@ -57,4 +56,18 @@ class User < ActiveRecord::Base universes.length ].sum end + + private + + # Attributes that are non-public, and should be blacklisted from any public + # export (ex. in the JSON api, or SEO meta info about the user) + def blacklisted_attributes + [ + :password_digest, + :old_password, + :encrypted_password, + :reset_password_token, + :email + ] + end end From b8449a16ebb2daf0acad044eb35d76deda212f58 Mon Sep 17 00:00:00 2001 From: Robert Richter <robert.c.richter@gmail.com> Date: Wed, 21 Sep 2016 11:50:00 -0500 Subject: [PATCH 28/29] Add user-specific meta tags to User profile --- app/views/users/show.html.erb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/views/users/show.html.erb b/app/views/users/show.html.erb index 2bf8cbde..db0a0e34 100644 --- a/app/views/users/show.html.erb +++ b/app/views/users/show.html.erb @@ -1,10 +1,12 @@ <script type="application/ld+json"> <% +set_meta_tags title: @user.name, description: "#{@user.name}’s profile on notebook.ai" + content_jsonld = { '@id': user_url, '@type': 'http://schema.org/Person', 'http://schema.org/name': @user.name, - 'http://schema.org/description': "#{@user.name}'s profile on notebook.ai" + 'http://schema.org/description': "#{@user.name}’s profile on notebook.ai" } %> <%= content_jsonld.to_json.html_safe %> %> From 911f1f2ed0d72107b198c6ae954c3f5cf579a79e Mon Sep 17 00:00:00 2001 From: Robert Richter <robert.c.richter@gmail.com> Date: Wed, 21 Sep 2016 11:53:29 -0500 Subject: [PATCH 29/29] Update website domain name in analytics --- app/views/layouts/_ganalytics.html.erb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/layouts/_ganalytics.html.erb b/app/views/layouts/_ganalytics.html.erb index 839a9917..5bcc7fd9 100644 --- a/app/views/layouts/_ganalytics.html.erb +++ b/app/views/layouts/_ganalytics.html.erb @@ -2,7 +2,7 @@ var _gaq = _gaq || []; _gaq.push(['_setAccount', 'UA-39217500-1']); - _gaq.push(['_setDomainName', 'indentapp.com']); + _gaq.push(['_setDomainName', 'notebook.ai']); _gaq.push(['_trackPageview']); (function() { @@ -11,4 +11,4 @@ var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s); })(); -</script> \ No newline at end of file +</script>