commit: e5282e4ec0e9dab62dde9481284b0cfd30690fb9
parent: 53eb31f124b8cb366f45ac0aec36e346115e334f
Author: Matt Jankowski <mjankowski@thoughtbot.com>
Date: Sun, 9 Apr 2017 08:47:25 -0400
Clean up about page (#1282)
* Add InstancePresenter to expose site details
* Clean up about controller, use instance presenter
Diffstat:
9 files changed, 254 insertions(+), 134 deletions(-)
diff --git a/app/controllers/about_controller.rb b/app/controllers/about_controller.rb
@@ -2,30 +2,25 @@
class AboutController < ApplicationController
before_action :set_body_classes
+ before_action :set_instance_presenter, only: [:show, :more]
- def index
- @description = Setting.site_description
- @open_registrations = Setting.open_registrations
- @closed_registrations_message = Setting.closed_registrations_message
+ def show; end
- @user = User.new
- @user.build_account
- end
-
- def more
- @description = Setting.site_description
- @extended_description = Setting.site_extended_description
- @contact_account = Account.find_local(Setting.site_contact_username)
- @contact_email = Setting.site_contact_email
- @user_count = Rails.cache.fetch('user_count') { User.count }
- @status_count = Rails.cache.fetch('local_status_count') { Status.local.count }
- @domain_count = Rails.cache.fetch('distinct_domain_count') { Account.distinct.count(:domain) }
- end
+ def more; end
def terms; end
private
+ def new_user
+ User.new.tap(&:build_account)
+ end
+ helper_method :new_user
+
+ def set_instance_presenter
+ @instance_presenter = InstancePresenter.new
+ end
+
def set_body_classes
@body_classes = 'about-body'
end
diff --git a/app/presenters/instance_presenter.rb b/app/presenters/instance_presenter.rb
@@ -0,0 +1,28 @@
+# frozen_string_literal: true
+
+class InstancePresenter
+ delegate(
+ :closed_registrations_message,
+ :contact_email,
+ :open_registrations,
+ :site_description,
+ :site_extended_description,
+ to: Setting
+ )
+
+ def contact_account
+ Account.find_local(Setting.site_contact_username)
+ end
+
+ def user_count
+ Rails.cache.fetch('user_count') { User.count }
+ end
+
+ def status_count
+ Rails.cache.fetch('local_status_count') { Status.local.count }
+ end
+
+ def domain_count
+ Rails.cache.fetch('distinct_domain_count') { Account.distinct.count(:domain) }
+ end
+end
diff --git a/app/views/about/_registration.html.haml b/app/views/about/_registration.html.haml
@@ -0,0 +1,30 @@
+= simple_form_for(new_user, url: user_registration_path) do |f|
+ = f.simple_fields_for :account do |account_fields|
+ = account_fields.input :username,
+ autofocus: true,
+ placeholder: t('simple_form.labels.defaults.username'),
+ required: true,
+ input_html: { 'aria-label' => t('simple_form.labels.defaults.username') }
+
+ = f.input :email,
+ placeholder: t('simple_form.labels.defaults.email'),
+ required: true,
+ input_html: { 'aria-label' => t('simple_form.labels.defaults.email') }
+ = f.input :password,
+ autocomplete: "off",
+ placeholder: t('simple_form.labels.defaults.password'),
+ required: true,
+ input_html: { 'aria-label' => t('simple_form.labels.defaults.password') }
+ = f.input :password_confirmation,
+ autocomplete: "off",
+ placeholder: t('simple_form.labels.defaults.confirm_password'),
+ required: true,
+ input_html: { 'aria-label' => t('simple_form.labels.defaults.confirm_password') }
+
+ .actions
+ = f.button :button, t('about.get_started'), type: :submit
+
+ .info
+ = link_to t('auth.login'), new_user_session_path, class: 'webapp-btn'
+ ·
+ = link_to t('about.about_this'), about_more_path
diff --git a/app/views/about/index.html.haml b/app/views/about/index.html.haml
@@ -1,100 +0,0 @@
-- content_for :header_tags do
- = javascript_include_tag 'application_public'
-
-- content_for :page_title do
- = Rails.configuration.x.local_domain
-
-- content_for :header_tags do
- %meta{ property: 'og:site_name', content: site_title }/
- %meta{ property: 'og:type', content: 'website' }/
- %meta{ property: 'og:title', content: Rails.configuration.x.local_domain }/
- %meta{ property: 'og:description', content: @description.blank? ? "Mastodon is a free, open-source social network server. A decentralized alternative to commercial platforms, it avoids the risks of a single company monopolizing your communication. Anyone can run Mastodon and participate in the social network seamlessly" : strip_tags(@description) }/
- %meta{ property: 'og:image', content: asset_url('mastodon_small.jpg') }/
- %meta{ property: 'og:image:width', content: '400' }/
- %meta{ property: 'og:image:height', content: '400' }/
- %meta{ property: 'twitter:card', content: 'summary' }/
-
-.wrapper
- %h1
- = image_tag 'logo.png'
- Mastodon
-
- %p= t('about.about_mastodon').html_safe
-
- .screenshot-with-signup
- .mascot= image_tag 'fluffy-elephant-friend.png'
-
- - if @open_registrations
- = simple_form_for(@user, url: user_registration_path) do |f|
- = f.simple_fields_for :account do |ff|
- = ff.input :username, autofocus: true, placeholder: t('simple_form.labels.defaults.username'), required: true, input_html: { 'aria-label' => t('simple_form.labels.defaults.username') }
-
- = f.input :email, placeholder: t('simple_form.labels.defaults.email'), required: true, input_html: { 'aria-label' => t('simple_form.labels.defaults.email') }
- = f.input :password, autocomplete: "off", placeholder: t('simple_form.labels.defaults.password'), required: true, input_html: { 'aria-label' => t('simple_form.labels.defaults.password') }
- = f.input :password_confirmation, autocomplete: "off", placeholder: t('simple_form.labels.defaults.confirm_password'), required: true, input_html: { 'aria-label' => t('simple_form.labels.defaults.confirm_password') }
-
- .actions
- = f.button :button, t('about.get_started'), type: :submit
-
- .info
- = link_to t('auth.login'), new_user_session_path, class: 'webapp-btn'
- ·
- = link_to t('about.about_this'), about_more_path
- - else
- .closed-registrations-message
- - if @closed_registrations_message.blank?
- %p= t('about.closed_registrations')
- - else
- = @closed_registrations_message.html_safe
- .info
- = link_to t('auth.login'), new_user_session_path, class: 'webapp-btn'
- ·
- = link_to t('about.other_instances'), 'https://github.com/tootsuite/mastodon/blob/master/docs/Using-Mastodon/List-of-Mastodon-instances.md'
- ·
- = link_to t('about.about_this'), about_more_path
-
- %h3= t('about.features_headline')
-
- .features-list
- .features-list__column
- %ul.fa-ul
- %li
- = fa_icon('li check-square')
- = t 'about.features.chronology'
- %li
- = fa_icon('li check-square')
- = t 'about.features.public'
- %li
- = fa_icon('li check-square')
- = t 'about.features.characters'
- %li
- = fa_icon('li check-square')
- = t 'about.features.gifv'
- .features-list__column
- %ul.fa-ul
- %li
- = fa_icon('li check-square')
- = t 'about.features.privacy'
- %li
- = fa_icon('li check-square')
- = t 'about.features.blocks'
- %li
- = fa_icon('li check-square')
- = t 'about.features.ethics'
- %li
- = fa_icon('li check-square')
- = t 'about.features.api'
-
- - unless @description.blank?
- %h3= t('about.description_headline', domain: Rails.configuration.x.local_domain)
- %p= @description.html_safe
-
- .actions
- .info
- = link_to t('about.terms'), terms_path
- ·
- = link_to t('about.apps'), 'https://github.com/tootsuite/mastodon/blob/master/docs/Using-Mastodon/Apps.md'
- ·
- = link_to t('about.source_code'), 'https://github.com/tootsuite/mastodon'
- ·
- = link_to t('about.other_instances'), 'https://github.com/tootsuite/mastodon/blob/master/docs/Using-Mastodon/List-of-Mastodon-instances.md'
diff --git a/app/views/about/more.html.haml b/app/views/about/more.html.haml
@@ -7,42 +7,42 @@
.panel
%h2= Rails.configuration.x.local_domain
- - unless @description.blank?
- %p= @description.html_safe
+ - unless @instance_presenter.site_description.blank?
+ %p= @instance_presenter.site_description.html_safe
.information-board
.section
%span= t 'about.user_count_before'
- %strong= number_with_delimiter @user_count
+ %strong= number_with_delimiter @instance_presenter.user_count
%span= t 'about.user_count_after'
.section
%span= t 'about.status_count_before'
- %strong= number_with_delimiter @status_count
+ %strong= number_with_delimiter @instance_presenter.status_count
%span= t 'about.status_count_after'
.section
%span= t 'about.domain_count_before'
- %strong= number_with_delimiter @domain_count
+ %strong= number_with_delimiter @instance_presenter.domain_count
%span= t 'about.domain_count_after'
- - unless @extended_description.blank?
- .panel= @extended_description.html_safe
+ - unless @instance_presenter.site_extended_description.blank?
+ .panel= @instance_presenter.site_extended_description.html_safe
.sidebar
.panel
.panel-header= t 'about.contact'
.panel-body
- - if @contact_account
+ - if @instance_presenter.contact_account
.owner
- .avatar= image_tag @contact_account.avatar.url
+ .avatar= image_tag @instance_presenter.contact_account.avatar.url
.name
- = link_to TagManager.instance.url_for(@contact_account) do
- %span.display_name.emojify= display_name(@contact_account)
- %span.username= "@#{@contact_account.acct}"
+ = link_to TagManager.instance.url_for(@instance_presenter.contact_account) do
+ %span.display_name.emojify= display_name(@instance_presenter.contact_account)
+ %span.username= "@#{@instance_presenter.contact_account.acct}"
- - unless @contact_email.blank?
+ - unless @instance_presenter.contact_email.blank?
.contact-email
= t 'about.business_email'
- %strong= @contact_email
+ %strong= @instance_presenter.contact_email
.panel
.panel-header= t 'about.links'
.panel-list
diff --git a/app/views/about/show.html.haml b/app/views/about/show.html.haml
@@ -0,0 +1,86 @@
+- content_for :header_tags do
+ = javascript_include_tag 'application_public'
+
+- content_for :page_title do
+ = Rails.configuration.x.local_domain
+
+- content_for :header_tags do
+ %meta{ property: 'og:site_name', content: site_title }/
+ %meta{ property: 'og:type', content: 'website' }/
+ %meta{ property: 'og:title', content: Rails.configuration.x.local_domain }/
+ %meta{ property: 'og:description', content: strip_tags(@instance_presenter.site_description.blank? ? t('about.about_mastodon') : @instance_presenter.site_description) }/
+ %meta{ property: 'og:image', content: asset_url('mastodon_small.jpg') }/
+ %meta{ property: 'og:image:width', content: '400' }/
+ %meta{ property: 'og:image:height', content: '400' }/
+ %meta{ property: 'twitter:card', content: 'summary' }/
+
+.wrapper
+ %h1
+ = image_tag 'logo.png'
+ Mastodon
+
+ %p= t('about.about_mastodon').html_safe
+
+ .screenshot-with-signup
+ .mascot= image_tag 'fluffy-elephant-friend.png'
+
+ - if @instance_presenter.open_registrations
+ = render 'registration'
+ - else
+ .closed-registrations-message
+ - if @instance_presenter.closed_registrations_message.blank?
+ %p= t('about.closed_registrations')
+ - else
+ = @instance_presenter.closed_registrations_message.html_safe
+ .info
+ = link_to t('auth.login'), new_user_session_path, class: 'webapp-btn'
+ ·
+ = link_to t('about.other_instances'), 'https://github.com/tootsuite/mastodon/blob/master/docs/Using-Mastodon/List-of-Mastodon-instances.md'
+ ·
+ = link_to t('about.about_this'), about_more_path
+
+ %h3= t('about.features_headline')
+
+ .features-list
+ .features-list__column
+ %ul.fa-ul
+ %li
+ = fa_icon('li check-square')
+ = t 'about.features.chronology'
+ %li
+ = fa_icon('li check-square')
+ = t 'about.features.public'
+ %li
+ = fa_icon('li check-square')
+ = t 'about.features.characters'
+ %li
+ = fa_icon('li check-square')
+ = t 'about.features.gifv'
+ .features-list__column
+ %ul.fa-ul
+ %li
+ = fa_icon('li check-square')
+ = t 'about.features.privacy'
+ %li
+ = fa_icon('li check-square')
+ = t 'about.features.blocks'
+ %li
+ = fa_icon('li check-square')
+ = t 'about.features.ethics'
+ %li
+ = fa_icon('li check-square')
+ = t 'about.features.api'
+
+ - unless @instance_presenter.site_description.blank?
+ %h3= t('about.description_headline', domain: Rails.configuration.x.local_domain)
+ %p= @instance_presenter.site_description.html_safe
+
+ .actions
+ .info
+ = link_to t('about.terms'), terms_path
+ ·
+ = link_to t('about.apps'), 'https://github.com/tootsuite/mastodon/blob/master/docs/Using-Mastodon/Apps.md'
+ ·
+ = link_to t('about.source_code'), 'https://github.com/tootsuite/mastodon'
+ ·
+ = link_to t('about.other_instances'), 'https://github.com/tootsuite/mastodon/blob/master/docs/Using-Mastodon/List-of-Mastodon-instances.md'
diff --git a/config/routes.rb b/config/routes.rb
@@ -188,7 +188,7 @@ Rails.application.routes.draw do
get '/web/(*any)', to: 'home#index', as: :web
- get '/about', to: 'about#index'
+ get '/about', to: 'about#show'
get '/about/more', to: 'about#more'
get '/terms', to: 'about#terms'
diff --git a/spec/controllers/about_controller_spec.rb b/spec/controllers/about_controller_spec.rb
@@ -3,9 +3,16 @@ require 'rails_helper'
RSpec.describe AboutController, type: :controller do
render_views
- describe 'GET #index' do
+ describe 'GET #show' do
it 'returns http success' do
- get :index
+ get :show
+ expect(response).to have_http_status(:success)
+ end
+ end
+
+ describe 'GET #more' do
+ it 'returns http success' do
+ get :more
expect(response).to have_http_status(:success)
end
end
diff --git a/spec/presenters/instance_presenter_spec.rb b/spec/presenters/instance_presenter_spec.rb
@@ -0,0 +1,74 @@
+require 'rails_helper'
+
+describe InstancePresenter do
+ let(:instance_presenter) { InstancePresenter.new }
+
+ it "delegates site_description to Setting" do
+ Setting.site_description = "Site desc"
+
+ expect(instance_presenter.site_description).to eq "Site desc"
+ end
+
+ it "delegates site_extended_description to Setting" do
+ Setting.site_extended_description = "Extended desc"
+
+ expect(instance_presenter.site_extended_description).to eq "Extended desc"
+ end
+
+ it "delegates open_registrations to Setting" do
+ Setting.open_registrations = false
+
+ expect(instance_presenter.open_registrations).to eq false
+ end
+
+ it "delegates closed_registrations_message to Setting" do
+ Setting.closed_registrations_message = "Closed message"
+
+ expect(instance_presenter.closed_registrations_message).to eq "Closed message"
+ end
+
+ it "delegates contact_email to Setting" do
+ Setting.contact_email = "admin@example.com"
+
+ expect(instance_presenter.contact_email).to eq "admin@example.com"
+ end
+
+ describe "contact_account" do
+ it "returns the account for the site contact username" do
+ Setting.site_contact_username = "aaa"
+ account = Fabricate(:account, username: "aaa")
+
+ expect(instance_presenter.contact_account).to eq(account)
+ end
+ end
+
+ describe "user_count" do
+ it "returns the number of site users" do
+ cache = double
+ allow(Rails).to receive(:cache).and_return(cache)
+ allow(cache).to receive(:fetch).with("user_count").and_return(123)
+
+ expect(instance_presenter.user_count).to eq(123)
+ end
+ end
+
+ describe "status_count" do
+ it "returns the number of local statuses" do
+ cache = double
+ allow(Rails).to receive(:cache).and_return(cache)
+ allow(cache).to receive(:fetch).with("local_status_count").and_return(234)
+
+ expect(instance_presenter.status_count).to eq(234)
+ end
+ end
+
+ describe "domain_count" do
+ it "returns the number of known domains" do
+ cache = double
+ allow(Rails).to receive(:cache).and_return(cache)
+ allow(cache).to receive(:fetch).with("distinct_domain_count").and_return(345)
+
+ expect(instance_presenter.domain_count).to eq(345)
+ end
+ end
+end