From fa1ba6791bcdad003783e7aa483183db366f613b Mon Sep 17 00:00:00 2001 From: Robin Ward Date: Thu, 4 Apr 2013 12:59:44 -0400 Subject: [PATCH] Work in Progress: Content Editing in Admin Section --- .../admin_site_content_edit_controller.js | 25 ++++++ .../javascripts/admin/models/site_content.js | 39 ++++++++++ .../admin/models/site_content_type.js | 21 +++++ .../admin/models/site_customization.js | 31 ++++---- .../javascripts/admin/routes/admin_routes.js | 6 ++ .../routes/admin_site_content_edit_route.js | 39 ++++++++++ .../admin/routes/admin_site_contents_route.js | 20 +++++ .../admin/templates/admin.js.handlebars | 5 +- .../templates/site_content_edit.js.handlebars | 36 +++++++++ .../templates/site_contents.js.handlebars | 16 ++++ .../site_contents_empty.js.handlebars | 1 + .../admin/views/ace_editor_view.js | 1 + app/assets/javascripts/discourse.js | 4 + .../preferences_email_controller.js | 1 + .../discourse/helpers/application_helpers.js | 3 +- .../javascripts/discourse/models/user.js | 77 +++++++++---------- .../routes/preferences_email_route.js | 10 +++ .../discourse/routes/preferences_route.js | 1 + .../routes/preferences_username_route.js | 10 +++ .../discourse/routes/user_route.js | 7 +- .../templates/user/preferences.js.handlebars | 2 +- app/assets/stylesheets/admin/admin_base.scss | 76 +++++++++++++++++- .../admin/site_content_types_controller.rb | 7 ++ .../admin/site_contents_controller.rb | 15 ++++ app/controllers/admin/users_controller.rb | 1 + app/models/site_content.rb | 24 ++++++ app/models/site_content_type.rb | 28 +++++++ app/serializers/site_content_serializer.rb | 25 ++++++ .../site_content_type_serializer.rb | 13 ++++ config/locales/client.en.yml | 5 ++ config/locales/server.en.yml | 17 ++++ config/routes.rb | 2 + db/fixtures/site_content_types.rb | 0 .../20130404143437_create_site_contents.rb | 10 +++ lib/site_content_class_methods.rb | 32 ++++++++ .../site_content_types_controller_spec.rb | 27 +++++++ .../admin/site_contents_controller_spec.rb | 29 +++++++ spec/fabricators/site_content_fabricator.rb | 9 +++ spec/models/site_content_spec.rb | 42 ++++++++++ 39 files changed, 653 insertions(+), 64 deletions(-) create mode 100644 app/assets/javascripts/admin/controllers/admin_site_content_edit_controller.js create mode 100644 app/assets/javascripts/admin/models/site_content.js create mode 100644 app/assets/javascripts/admin/models/site_content_type.js create mode 100644 app/assets/javascripts/admin/routes/admin_site_content_edit_route.js create mode 100644 app/assets/javascripts/admin/routes/admin_site_contents_route.js create mode 100644 app/assets/javascripts/admin/templates/site_content_edit.js.handlebars create mode 100644 app/assets/javascripts/admin/templates/site_contents.js.handlebars create mode 100644 app/assets/javascripts/admin/templates/site_contents_empty.js.handlebars create mode 100644 app/controllers/admin/site_content_types_controller.rb create mode 100644 app/controllers/admin/site_contents_controller.rb create mode 100644 app/models/site_content.rb create mode 100644 app/models/site_content_type.rb create mode 100644 app/serializers/site_content_serializer.rb create mode 100644 app/serializers/site_content_type_serializer.rb create mode 100644 db/fixtures/site_content_types.rb create mode 100644 db/migrate/20130404143437_create_site_contents.rb create mode 100644 lib/site_content_class_methods.rb create mode 100644 spec/controllers/admin/site_content_types_controller_spec.rb create mode 100644 spec/controllers/admin/site_contents_controller_spec.rb create mode 100644 spec/fabricators/site_content_fabricator.rb create mode 100644 spec/models/site_content_spec.rb diff --git a/app/assets/javascripts/admin/controllers/admin_site_content_edit_controller.js b/app/assets/javascripts/admin/controllers/admin_site_content_edit_controller.js new file mode 100644 index 00000000000..e4a635eb529 --- /dev/null +++ b/app/assets/javascripts/admin/controllers/admin_site_content_edit_controller.js @@ -0,0 +1,25 @@ +/** + This controller is used for editing site content + + @class AdminSiteContentEditController + @extends Ember.ObjectController + @namespace Discourse + @module Discourse +**/ +Discourse.AdminSiteContentEditController = Discourse.ObjectController.extend({ + + saveDisabled: function() { + if (this.get('saving')) return true; + if (this.blank('content.content')) return true; + return false; + }.property('saving', 'content.content'), + + saveChanges: function() { + var controller = this; + controller.setProperties({saving: true, saved: false}); + this.get('content').save().then(function () { + controller.setProperties({saving: false, saved: true}); + }); + } + +}); \ No newline at end of file diff --git a/app/assets/javascripts/admin/models/site_content.js b/app/assets/javascripts/admin/models/site_content.js new file mode 100644 index 00000000000..03a49417bbf --- /dev/null +++ b/app/assets/javascripts/admin/models/site_content.js @@ -0,0 +1,39 @@ +/** + Our data model for interacting with custom site content + + @class SiteContent + @extends Discourse.Model + @namespace Discourse + @module Discourse +**/ +Discourse.SiteContent = Discourse.Model.extend({ + + markdown: Ember.computed.equal('format', 'markdown'), + plainText: Ember.computed.equal('format', 'plain'), + html: Ember.computed.equal('format', 'html'), + css: Ember.computed.equal('format', 'css'), + + /** + Save the content + + @method save + @return {jqXHR} a jQuery Promise object + **/ + save: function() { + return Discourse.ajax(Discourse.getURL("/admin/site_contents/" + this.get('content_type')), { + type: 'PUT', + data: {content: this.get('content')} + }); + } + +}); + +Discourse.SiteContent.reopenClass({ + + find: function(type) { + return Discourse.ajax(Discourse.getURL("/admin/site_contents/" + type)).then(function (data) { + return Discourse.SiteContent.create(data.site_content); + }); + } + +}); \ No newline at end of file diff --git a/app/assets/javascripts/admin/models/site_content_type.js b/app/assets/javascripts/admin/models/site_content_type.js new file mode 100644 index 00000000000..0b557048515 --- /dev/null +++ b/app/assets/javascripts/admin/models/site_content_type.js @@ -0,0 +1,21 @@ +/** + Our data model that represents types of editing site content + + @class SiteContentType + @extends Discourse.Model + @namespace Discourse + @module Discourse +**/ +Discourse.SiteContentType = Discourse.Model.extend({}); + +Discourse.SiteContentType.reopenClass({ + findAll: function() { + var contentTypes = Em.A(); + Discourse.ajax(Discourse.getURL("/admin/site_content_types")).then(function(data) { + data.forEach(function (ct) { + contentTypes.pushObject(Discourse.SiteContentType.create(ct)); + }); + }); + return contentTypes; + } +}); diff --git a/app/assets/javascripts/admin/models/site_customization.js b/app/assets/javascripts/admin/models/site_customization.js index 35c78300e77..4d5c366d50e 100644 --- a/app/assets/javascripts/admin/models/site_customization.js +++ b/app/assets/javascripts/admin/models/site_customization.js @@ -14,19 +14,17 @@ Discourse.SiteCustomization = Discourse.Model.extend({ return this.startTrackingChanges(); }, - description: (function() { + description: function() { return "" + this.name + (this.enabled ? ' (*)' : ''); - }).property('selected', 'name'), + }.property('selected', 'name'), - changed: (function() { + changed: function() { var _this = this; - if (!this.originals) { - return false; - } + if (!this.originals) return false; return this.trackedProperties.any(function(p) { return _this.originals[p] !== _this.get(p); }); - }).property('override_default_style', 'enabled', 'name', 'stylesheet', 'header', 'originals'), + }.property('override_default_style', 'enabled', 'name', 'stylesheet', 'header', 'originals'), startTrackingChanges: function() { var _this = this; @@ -37,18 +35,17 @@ Discourse.SiteCustomization = Discourse.Model.extend({ }); }, - previewUrl: (function() { + previewUrl: function() { return "/?preview-style=" + (this.get('key')); - }).property('key'), + }.property('key'), - disableSave: (function() { + disableSave: function() { return !this.get('changed'); - }).property('changed'), + }.property('changed'), save: function() { - var data; this.startTrackingChanges(); - data = { + var data = { name: this.name, enabled: this.enabled, stylesheet: this.stylesheet, @@ -66,7 +63,6 @@ Discourse.SiteCustomization = Discourse.Model.extend({ destroy: function() { if (!this.id) return; - return Discourse.ajax({ url: Discourse.getURL("/admin/site_customizations/") + this.id, type: 'DELETE' @@ -76,13 +72,12 @@ Discourse.SiteCustomization = Discourse.Model.extend({ }); var SiteCustomizations = Ember.ArrayProxy.extend({ - selectedItemChanged: (function() { - var selected; - selected = this.get('selectedItem'); + selectedItemChanged: function() { + var selected = this.get('selectedItem'); return this.get('content').each(function(i) { return i.set('selected', selected === i); }); - }).observes('selectedItem') + }.observes('selectedItem') }); Discourse.SiteCustomization.reopenClass({ diff --git a/app/assets/javascripts/admin/routes/admin_routes.js b/app/assets/javascripts/admin/routes/admin_routes.js index b82e89d6483..4dc179dc30c 100644 --- a/app/assets/javascripts/admin/routes/admin_routes.js +++ b/app/assets/javascripts/admin/routes/admin_routes.js @@ -8,6 +8,12 @@ Discourse.Route.buildRoutes(function() { this.resource('admin', { path: '/admin' }, function() { this.route('dashboard', { path: '/' }); this.route('site_settings', { path: '/site_settings' }); + + + this.resource('adminSiteContents', { path: '/site_contents' }, function() { + this.resource('adminSiteContentEdit', {path: '/:content_type'}); + }); + this.route('email_logs', { path: '/email_logs' }); this.route('customize', { path: '/customize' }); this.route('api', {path: '/api'}); diff --git a/app/assets/javascripts/admin/routes/admin_site_content_edit_route.js b/app/assets/javascripts/admin/routes/admin_site_content_edit_route.js new file mode 100644 index 00000000000..3c5103ddb16 --- /dev/null +++ b/app/assets/javascripts/admin/routes/admin_site_content_edit_route.js @@ -0,0 +1,39 @@ +/** + Allows users to customize site content + + @class AdminSiteContentEditRoute + @extends Discourse.Route + @namespace Discourse + @module Discourse +**/ +Discourse.AdminSiteContentEditRoute = Discourse.Route.extend({ + + serialize: function(model) { + return {content_type: model.get('content_type')}; + }, + + model: function(params) { + return {content_type: params.content_type}; + }, + + renderTemplate: function() { + this.render('admin/templates/site_content_edit', {into: 'admin/templates/site_contents'}); + }, + + exit: function() { + this._super(); + this.render('admin/templates/site_contents_empty', {into: 'admin/templates/site_contents'}); + }, + + setupController: function(controller, model) { + controller.set('loaded', false); + controller.setProperties({saving: false, saved: false}); + + Discourse.SiteContent.find(Em.get(model, 'content_type')).then(function (sc) { + controller.set('content', sc); + controller.set('loaded', true); + }) + } + + +}); diff --git a/app/assets/javascripts/admin/routes/admin_site_contents_route.js b/app/assets/javascripts/admin/routes/admin_site_contents_route.js new file mode 100644 index 00000000000..779f060cd68 --- /dev/null +++ b/app/assets/javascripts/admin/routes/admin_site_contents_route.js @@ -0,0 +1,20 @@ +/** + Allows users to customize site content + + @class AdminSiteContentsRoute + @extends Discourse.Route + @namespace Discourse + @module Discourse +**/ +Discourse.AdminSiteContentsRoute = Discourse.Route.extend({ + + model: function() { + return Discourse.SiteContentType.findAll(); + }, + + renderTemplate: function() { + this.render('admin/templates/site_contents', {into: 'admin/templates/admin'}); + this.render('admin/templates/site_contents_empty', {into: 'admin/templates/site_contents'}); + } +}); + diff --git a/app/assets/javascripts/admin/templates/admin.js.handlebars b/app/assets/javascripts/admin/templates/admin.js.handlebars index c52dfa66253..8fa2bf43b39 100644 --- a/app/assets/javascripts/admin/templates/admin.js.handlebars +++ b/app/assets/javascripts/admin/templates/admin.js.handlebars @@ -1,10 +1,11 @@
-
- +
+
- +
diff --git a/app/assets/stylesheets/admin/admin_base.scss b/app/assets/stylesheets/admin/admin_base.scss index edc64e6173b..c34e107762b 100644 --- a/app/assets/stylesheets/admin/admin_base.scss +++ b/app/assets/stylesheets/admin/admin_base.scss @@ -565,4 +565,78 @@ table { ::-webkit-scrollbar-track { border-left: solid 1px #ddd; } -} \ No newline at end of file +} + +.content-list { + + h3 { + color: $darkish_gray; + font-size: 15px; + padding-left: 5px; + } + + ul { + list-style: none; + margin: 0; + + li { + border-bottom: 1px solid #ddd; + } + + li a { + display: block; + padding: 10px; + color: $dark_gray; + + &:hover { + background-color: #eee; + color: $dark_gray; + } + + &.active { + font-weight: bold; + color: $black; + } + } + } +} + +.content-editor { + min-height: 500px; + + p.description { + color: $dark_gray; + } + + .controls { + margin-top: 10px; + } + + #pagedown-editor { + width: 98%; + } + + textarea.plain { + width: 98%; + height: 200px; + } + + #wmd-input { + width: 98%; + height: 200px; + } + + .ace-wrapper { + position: relative; + height: 600px; + width: 100%; + } + .ace_editor { + position: absolute; + left: 0; + right: 0; + top: 0; + bottom: 0; + } + +} diff --git a/app/controllers/admin/site_content_types_controller.rb b/app/controllers/admin/site_content_types_controller.rb new file mode 100644 index 00000000000..fd7eaf44237 --- /dev/null +++ b/app/controllers/admin/site_content_types_controller.rb @@ -0,0 +1,7 @@ +class Admin::SiteContentTypesController < Admin::AdminController + + def index + render_serialized(SiteContent.content_types, SiteContentTypeSerializer) + end + +end diff --git a/app/controllers/admin/site_contents_controller.rb b/app/controllers/admin/site_contents_controller.rb new file mode 100644 index 00000000000..5d4d6124ac0 --- /dev/null +++ b/app/controllers/admin/site_contents_controller.rb @@ -0,0 +1,15 @@ +class Admin::SiteContentsController < Admin::AdminController + + def show + site_content = SiteContent.find_or_new(params[:id].to_s) + render_serialized(site_content, SiteContentSerializer) + end + + def update + site_content = SiteContent.find_or_new(params[:id].to_s) + site_content.content = params[:content] + site_content.save! + + render nothing: true + end +end diff --git a/app/controllers/admin/users_controller.rb b/app/controllers/admin/users_controller.rb index 1e020cd0045..b78c16e6815 100644 --- a/app/controllers/admin/users_controller.rb +++ b/app/controllers/admin/users_controller.rb @@ -25,6 +25,7 @@ class Admin::UsersController < Admin::AdminController @user.delete_all_posts!(guardian) render nothing: true end + def ban @user = User.where(id: params[:user_id]).first guardian.ensure_can_ban!(@user) diff --git a/app/models/site_content.rb b/app/models/site_content.rb new file mode 100644 index 00000000000..5eea42d34fc --- /dev/null +++ b/app/models/site_content.rb @@ -0,0 +1,24 @@ +require_dependency 'site_content_type' +require_dependency 'site_content_class_methods' + +class SiteContent < ActiveRecord::Base + extend SiteContentClassMethods + + set_primary_key :content_type + validates_presence_of :content + + def self.formats + @formats ||= Enum.new(:plain, :markdown, :html, :css) + end + + content_type :usage_tips, :markdown, default_18n_key: 'system_messages.usage_tips.text_body_template' + content_type :welcome_user, :markdown, default_18n_key: 'system_messages.welcome_user.text_body_template' + content_type :welcome_invite, :markdown, default_18n_key: 'system_messages.welcome_invite.text_body_template' + content_type :education_new_topic, :markdown, default_18n_key: 'education.new-topic' + content_type :education_new_reply, :markdown, default_18n_key: 'education.new-reply' + + def site_content_type + @site_content_type ||= SiteContent.content_types.find {|t| t.content_type == content_type.to_sym} + end + +end diff --git a/app/models/site_content_type.rb b/app/models/site_content_type.rb new file mode 100644 index 00000000000..32f42cbf9e8 --- /dev/null +++ b/app/models/site_content_type.rb @@ -0,0 +1,28 @@ +require_dependency 'multisite_i18n' + +class SiteContentType + + attr_accessor :content_type, :format + + def initialize(content_type, format, opts=nil) + @opts = opts || {} + @content_type = content_type + @format = format + end + + def title + I18n.t("content_types.#{content_type}.title") + end + + def description + I18n.t("content_types.#{content_type}.description") + end + + def default_content + if @opts[:default_18n_key].present? + return MultisiteI18n.t(@opts[:default_18n_key]) + end + "" + end + +end \ No newline at end of file diff --git a/app/serializers/site_content_serializer.rb b/app/serializers/site_content_serializer.rb new file mode 100644 index 00000000000..2c6dbf3654b --- /dev/null +++ b/app/serializers/site_content_serializer.rb @@ -0,0 +1,25 @@ +class SiteContentSerializer < ApplicationSerializer + + attributes :content_type, + :title, + :description, + :content, + :format + + def title + object.site_content_type.title + end + + def description + object.site_content_type.description + end + + def format + object.site_content_type.format + end + + def content + return object.content if object.content.present? + object.site_content_type.default_content + end +end diff --git a/app/serializers/site_content_type_serializer.rb b/app/serializers/site_content_type_serializer.rb new file mode 100644 index 00000000000..da906dedbd4 --- /dev/null +++ b/app/serializers/site_content_type_serializer.rb @@ -0,0 +1,13 @@ +class SiteContentTypeSerializer < ApplicationSerializer + + attributes :content_type, :title + + def content_type + object.content_type + end + + def title + object.title + end + +end diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index 6fb281a274a..16166eee20d 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -908,6 +908,11 @@ en: approved_by: "approved by" time_read: "Read Time" + site_content: + none: "Choose a type of content to begin editing." + title: 'Site Content' + edit: "Edit Site Content" + site_settings: show_overriden: 'Only show overridden' title: 'Site Settings' diff --git a/config/locales/server.en.yml b/config/locales/server.en.yml index 910af47e092..4705b80f315 100644 --- a/config/locales/server.en.yml +++ b/config/locales/server.en.yml @@ -310,6 +310,23 @@ en: twitter_config_warning: 'The server is configured to allow signup and log in with Twitter (enable_twitter_logins), but the key and secret values are not set. Go to the Site Settings and update the settings. See this guide to learn more.' github_config_warning: 'The server is configured to allow signup and log in with GitHub (enable_github_logins), but the client id and secret values are not set. Go to the Site Settings and update the settings. See this guide to learn more.' + content_types: + education_new_reply: + title: "New User Education: New Reply" + description: "The pop up text a user sees when replying." + education_new_topic: + title: "New User Education: New Topic" + description: "The pop up text a user sees when creating a topic." + usage_tips: + title: "Usage Tips" + description: "The usage tips a new user receives when welcomed to the forum." + welcome_user: + title: "Welcome: New User" + description: "The system message a new user receives." + welcome_invite: + title: "Welcome: Invited User" + description: "The system message an invited user receives." + site_settings: default_locale: "The default language of this Discourse instance (ISO 639-1 Code)" min_post_length: "Minimum post length in characters" diff --git a/config/routes.rb b/config/routes.rb index 3fe0d627050..4139f2c3fea 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -54,6 +54,8 @@ Discourse::Application.routes.draw do get 'flags/:filter' => 'flags#index' post 'flags/clear/:id' => 'flags#clear' resources :site_customizations + resources :site_contents + resources :site_content_types resources :export get 'version_check' => 'versions#show' resources :dashboard, only: [:index] do diff --git a/db/fixtures/site_content_types.rb b/db/fixtures/site_content_types.rb new file mode 100644 index 00000000000..e69de29bb2d diff --git a/db/migrate/20130404143437_create_site_contents.rb b/db/migrate/20130404143437_create_site_contents.rb new file mode 100644 index 00000000000..c4554c91167 --- /dev/null +++ b/db/migrate/20130404143437_create_site_contents.rb @@ -0,0 +1,10 @@ +class CreateSiteContents < ActiveRecord::Migration + def change + create_table :site_contents, force: true, id: false do |t| + t.string :content_type, null: false + t.text :content, null: false + t.timestamps + end + add_index :site_contents, :content_type, unique: true + end +end diff --git a/lib/site_content_class_methods.rb b/lib/site_content_class_methods.rb new file mode 100644 index 00000000000..7843b0c0be5 --- /dev/null +++ b/lib/site_content_class_methods.rb @@ -0,0 +1,32 @@ +module SiteContentClassMethods + + def content_types + @types || [] + end + + def content_type(content_type, format, opts=nil) + opts ||= {} + @types ||= [] + @types << SiteContentType.new(content_type, format, opts) + end + + def content_for(content_type, replacements=nil) + replacements ||= {} + + site_content = SiteContent.select(:content).where(content_type: content_type).first + return "" if site_content.blank? + + site_content.content % replacements + end + + + def find_or_new(content_type) + site_content = SiteContent.where(content_type: content_type).first + return site_content if site_content.present? + + site_content = SiteContent.new + site_content.content_type = content_type + site_content + end + +end diff --git a/spec/controllers/admin/site_content_types_controller_spec.rb b/spec/controllers/admin/site_content_types_controller_spec.rb new file mode 100644 index 00000000000..4538800eb3e --- /dev/null +++ b/spec/controllers/admin/site_content_types_controller_spec.rb @@ -0,0 +1,27 @@ +require 'spec_helper' + +describe Admin::SiteContentTypesController do + + it "is a subclass of AdminController" do + (Admin::SiteContentTypesController < Admin::AdminController).should be_true + end + + context 'while logged in as an admin' do + before do + @user = log_in(:admin) + end + + context ' .index' do + it 'returns success' do + xhr :get, :index + response.should be_success + end + + it 'returns JSON' do + xhr :get, :index + ::JSON.parse(response.body).should be_present + end + end + end + +end diff --git a/spec/controllers/admin/site_contents_controller_spec.rb b/spec/controllers/admin/site_contents_controller_spec.rb new file mode 100644 index 00000000000..11c49e0ed9b --- /dev/null +++ b/spec/controllers/admin/site_contents_controller_spec.rb @@ -0,0 +1,29 @@ +require 'spec_helper' + +describe Admin::SiteContentsController do + + it "is a subclass of AdminController" do + (Admin::SiteContentsController < Admin::AdminController).should be_true + end + + context 'while logged in as an admin' do + before do + @user = log_in(:admin) + end + + context '.show' do + let(:content_type) { SiteContent.content_types.first.content_type } + + it 'returns success' do + xhr :get, :show, id: content_type + response.should be_success + end + + it 'returns JSON' do + xhr :get, :show, id: content_type + ::JSON.parse(response.body).should be_present + end + end + end + +end diff --git a/spec/fabricators/site_content_fabricator.rb b/spec/fabricators/site_content_fabricator.rb new file mode 100644 index 00000000000..56ce55c05c1 --- /dev/null +++ b/spec/fabricators/site_content_fabricator.rb @@ -0,0 +1,9 @@ +Fabricator(:site_content) do + content_type 'great.poem' + content "%{flower} are red. %{food} are blue." +end + +Fabricator(:site_content_basic, from: :site_content) do + content_type 'breaking.bad' + content "best show ever" +end \ No newline at end of file diff --git a/spec/models/site_content_spec.rb b/spec/models/site_content_spec.rb new file mode 100644 index 00000000000..ed8512d1e29 --- /dev/null +++ b/spec/models/site_content_spec.rb @@ -0,0 +1,42 @@ +require 'spec_helper' + +describe SiteContent do + + it { should validate_presence_of :content } + + + describe "#content_for" do + + it "returns an empty string for a missing content_type" do + SiteContent.content_for('breaking.bad').should == "" + end + + context "without replacements" do + let!(:site_content) { Fabricate(:site_content_basic) } + + it "returns the simple string" do + SiteContent.content_for('breaking.bad').should == "best show ever" + end + + end + + context "with replacements" do + let!(:site_content) { Fabricate(:site_content) } + let(:replacements) { {flower: 'roses', food: 'grapes'} } + + it "returns the correct string with replacements" do + SiteContent.content_for('great.poem', replacements).should == "roses are red. grapes are blue." + end + + it "doesn't mind extra keys in the replacements" do + SiteContent.content_for('great.poem', replacements.merge(extra: 'key')).should == "roses are red. grapes are blue." + end + + it "raises an error with missing keys" do + -> { SiteContent.content_for('great.poem', flower: 'roses') }.should raise_error + end + end + + end + +end