schnitzelpress 0.1.1 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGES.md +20 -3
- data/README.md +4 -2
- data/bin/schnitzelpress +1 -1
- data/lib/assets/js/jquery-1.7.1.js +673 -0
- data/lib/assets/js/jquery-ujs.js +373 -0
- data/lib/assets/js/jquery.cookie.js +47 -0
- data/lib/{public → assets}/js/schnitzelpress.js +7 -2
- data/lib/public/font/fontawesome-webfont.eot +0 -0
- data/lib/public/font/fontawesome-webfont.svg +175 -0
- data/lib/public/font/fontawesome-webfont.svgz +0 -0
- data/lib/public/font/fontawesome-webfont.ttf +0 -0
- data/lib/public/font/fontawesome-webfont.woff +0 -0
- data/lib/schnitzelpress.rb +21 -5
- data/lib/schnitzelpress/actions/admin.rb +21 -1
- data/lib/schnitzelpress/actions/assets.rb +36 -0
- data/lib/schnitzelpress/actions/auth.rb +16 -3
- data/lib/schnitzelpress/actions/blog.rb +10 -12
- data/lib/schnitzelpress/app.rb +16 -19
- data/lib/schnitzelpress/cache_control.rb +17 -0
- data/lib/schnitzelpress/cli.rb +40 -9
- data/lib/schnitzelpress/config.rb +43 -0
- data/lib/schnitzelpress/env.rb +5 -0
- data/lib/schnitzelpress/helpers.rb +168 -4
- data/lib/schnitzelpress/markdown_renderer.rb +2 -2
- data/lib/schnitzelpress/post.rb +2 -6
- data/lib/schnitzelpress/static.rb +1 -1
- data/lib/schnitzelpress/version.rb +2 -2
- data/lib/templates/new_blog/Gemfile +4 -5
- data/lib/templates/new_blog/Gemfile.lock.tt +137 -0
- data/lib/templates/new_blog/Procfile +1 -1
- data/lib/templates/new_blog/config.ru.tt +6 -17
- data/lib/views/admin/admin.haml +3 -2
- data/lib/views/admin/config.haml +27 -0
- data/lib/views/atom.haml +3 -3
- data/lib/views/index.haml +1 -1
- data/lib/views/layout.haml +15 -11
- data/lib/views/login.haml +4 -0
- data/lib/views/partials/_admin_post_list.haml +8 -8
- data/lib/views/partials/_disqus.haml +1 -1
- data/lib/views/partials/_gauges.haml +1 -1
- data/lib/views/partials/_google_analytics.haml +1 -1
- data/lib/views/partials/_post.haml +6 -5
- data/lib/views/partials/_post_form.haml +3 -1
- data/lib/views/post.haml +4 -1
- data/lib/views/schnitzelpress.scss +67 -3
- data/schnitzelpress.gemspec +5 -2
- data/spec/app_spec.rb +5 -11
- data/spec/assets_spec.rb +26 -0
- data/spec/factories.rb +1 -1
- data/spec/post_spec.rb +9 -2
- data/spec/spec_helper.rb +2 -1
- metadata +115 -71
- data/lib/schnitzelpress/rake.rb +0 -20
- data/lib/templates/new_blog/Rakefile +0 -2
- data/lib/templates/new_blog/app.rb.tt +0 -34
- data/lib/templates/new_blog/config/unicorn.rb +0 -5
- data/lib/templates/new_blog/public/.gitkeep +0 -0
Binary file
|
Binary file
|
Binary file
|
data/lib/schnitzelpress.rb
CHANGED
@@ -6,6 +6,7 @@ require 'sass'
|
|
6
6
|
require 'redcarpet'
|
7
7
|
require 'schnitzelstyle'
|
8
8
|
require 'rack/contrib'
|
9
|
+
require 'rack/cache'
|
9
10
|
require 'mongoid'
|
10
11
|
require 'chronic'
|
11
12
|
|
@@ -13,10 +14,14 @@ require 'active_support/inflector'
|
|
13
14
|
require 'active_support/core_ext/class'
|
14
15
|
require 'active_support/concern'
|
15
16
|
|
17
|
+
require 'schnitzelpress/cache_control'
|
18
|
+
require 'schnitzelpress/env'
|
16
19
|
require 'schnitzelpress/static'
|
17
20
|
require 'schnitzelpress/helpers'
|
18
21
|
require 'schnitzelpress/markdown_renderer'
|
22
|
+
require 'schnitzelpress/config'
|
19
23
|
require 'schnitzelpress/post'
|
24
|
+
require 'schnitzelpress/actions/assets'
|
20
25
|
require 'schnitzelpress/actions/blog'
|
21
26
|
require 'schnitzelpress/actions/auth'
|
22
27
|
require 'schnitzelpress/actions/admin'
|
@@ -27,18 +32,29 @@ Sass::Engine::DEFAULT_OPTIONS[:load_paths].unshift(File.expand_path("./views"))
|
|
27
32
|
|
28
33
|
Mongoid.logger.level = 3
|
29
34
|
|
30
|
-
module
|
35
|
+
module Schnitzelpress
|
31
36
|
mattr_reader :mongo_uri
|
32
37
|
|
33
38
|
class << self
|
34
39
|
def mongo_uri=(uri)
|
35
40
|
Mongoid::Config.from_hash("uri" => uri)
|
36
|
-
|
41
|
+
Schnitzelpress::Post.create_indexes
|
37
42
|
@@mongo_uri = uri
|
38
43
|
end
|
39
44
|
|
40
|
-
def
|
41
|
-
(
|
45
|
+
def init!
|
46
|
+
# Mongoid.load!("./config/mongo.yml")
|
47
|
+
if mongo_uri = ENV['MONGOLAB_URI'] || ENV['MONGOHQ_URL'] || ENV['MONGO_URL']
|
48
|
+
self.mongo_uri = mongo_uri
|
49
|
+
else
|
50
|
+
raise "Please set MONGO_URL, MONGOHQ_URL or MONGOLAB_URI to your MongoDB connection string."
|
51
|
+
end
|
52
|
+
Schnitzelpress::Post.create_indexes
|
53
|
+
end
|
54
|
+
|
55
|
+
def omnomnom!
|
56
|
+
init!
|
57
|
+
App.with_local_files
|
42
58
|
end
|
43
59
|
end
|
44
60
|
end
|
@@ -48,7 +64,7 @@ module Haml::Filters::Redcarpet
|
|
48
64
|
include Haml::Filters::Base
|
49
65
|
|
50
66
|
def render(text)
|
51
|
-
Redcarpet::Markdown.new(
|
67
|
+
Redcarpet::Markdown.new(Schnitzelpress::MarkdownRenderer,
|
52
68
|
:autolink => true, :space_after_headers => true, :fenced_code_blocks => true).
|
53
69
|
render(text)
|
54
70
|
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
module
|
1
|
+
module Schnitzelpress
|
2
2
|
module Actions
|
3
3
|
module Admin
|
4
4
|
extend ActiveSupport::Concern
|
@@ -15,6 +15,20 @@ module SchnitzelPress
|
|
15
15
|
haml :'admin/admin'
|
16
16
|
end
|
17
17
|
|
18
|
+
get '/admin/config/?' do
|
19
|
+
haml :'admin/config'
|
20
|
+
end
|
21
|
+
|
22
|
+
post '/admin/config' do
|
23
|
+
config.attributes = params[:config]
|
24
|
+
if config.save
|
25
|
+
CacheControl.bust!
|
26
|
+
redirect '/admin'
|
27
|
+
else
|
28
|
+
haml :'admin/config'
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
18
32
|
get '/admin/new/?' do
|
19
33
|
@post = Post.new
|
20
34
|
haml :'admin/new'
|
@@ -43,6 +57,12 @@ module SchnitzelPress
|
|
43
57
|
haml :'admin/edit'
|
44
58
|
end
|
45
59
|
end
|
60
|
+
|
61
|
+
delete '/admin/edit/:id/?' do
|
62
|
+
@post = Post.find(params[:id])
|
63
|
+
@post.destroy
|
64
|
+
redirect '/admin'
|
65
|
+
end
|
46
66
|
end
|
47
67
|
end
|
48
68
|
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'packr'
|
2
|
+
|
3
|
+
|
4
|
+
module Schnitzelpress
|
5
|
+
class JavascriptPacker
|
6
|
+
def self.pack_javascripts!(files)
|
7
|
+
plain = files.map do |filename|
|
8
|
+
File.read(File.expand_path("../lib/assets/js/#{filename}", settings.root))
|
9
|
+
end.join("\n")
|
10
|
+
|
11
|
+
Packr.pack(plain)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
module Actions
|
16
|
+
module Assets
|
17
|
+
extend ActiveSupport::Concern
|
18
|
+
|
19
|
+
ASSET_TIMESTAMP = Time.now.to_i
|
20
|
+
JAVASCRIPT_ASSETS = ['jquery-1.7.1.js', 'jquery.cookie.js', 'schnitzelpress.js', 'jquery-ujs.js']
|
21
|
+
|
22
|
+
included do
|
23
|
+
get '/assets/schnitzelpress.:timestamp.css' do
|
24
|
+
cache_control :public, :max_age => 1.year.to_i
|
25
|
+
scss :blog
|
26
|
+
end
|
27
|
+
|
28
|
+
get '/assets/schnitzelpress.:timestamp.js' do
|
29
|
+
cache_control :public, :max_age => 1.year.to_i
|
30
|
+
content_type 'text/javascript; charset=utf-8'
|
31
|
+
JavascriptPacker.pack_javascripts!(JAVASCRIPT_ASSETS)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -1,18 +1,29 @@
|
|
1
1
|
require 'omniauth'
|
2
2
|
require 'omniauth-browserid'
|
3
3
|
|
4
|
-
module
|
4
|
+
module Schnitzelpress
|
5
5
|
module Actions
|
6
6
|
module Auth
|
7
7
|
extend ActiveSupport::Concern
|
8
8
|
|
9
9
|
included do
|
10
|
-
use OmniAuth::
|
10
|
+
use OmniAuth::Builder do
|
11
|
+
provider :browser_id
|
12
|
+
if Schnitzelpress.env.development?
|
13
|
+
provider :developer , :fields => [:email], :uid_field => :email
|
14
|
+
end
|
15
|
+
end
|
11
16
|
|
12
17
|
post '/auth/:provider/callback' do
|
13
18
|
auth = request.env['omniauth.auth']
|
14
19
|
session[:auth] = {:provider => auth['provider'], :uid => auth['uid']}
|
15
|
-
|
20
|
+
|
21
|
+
if admin_logged_in?
|
22
|
+
response.set_cookie('show_admin', :value => true, :path => '/')
|
23
|
+
redirect '/admin/'
|
24
|
+
else
|
25
|
+
redirect '/'
|
26
|
+
end
|
16
27
|
end
|
17
28
|
|
18
29
|
get '/login' do
|
@@ -21,6 +32,8 @@ module SchnitzelPress
|
|
21
32
|
|
22
33
|
get '/logout' do
|
23
34
|
session[:auth] = nil
|
35
|
+
response.delete_cookie('show_admin')
|
36
|
+
|
24
37
|
redirect '/login'
|
25
38
|
end
|
26
39
|
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
module
|
1
|
+
module Schnitzelpress
|
2
2
|
module Actions
|
3
3
|
module Blog
|
4
4
|
extend ActiveSupport::Concern
|
@@ -31,25 +31,21 @@ module SchnitzelPress
|
|
31
31
|
render_posts
|
32
32
|
end
|
33
33
|
|
34
|
-
get '/blog.css' do
|
35
|
-
cache_for 1.hour
|
36
|
-
scss :blog
|
37
|
-
end
|
38
|
-
|
39
34
|
# /posts.atom is now deprecated.
|
40
35
|
get '/posts.atom' do
|
41
36
|
redirect '/blog.atom', 301
|
42
37
|
end
|
43
38
|
|
44
39
|
get '/blog.atom' do
|
45
|
-
|
40
|
+
cache_control :public, :must_revalidate, :s_maxage => 2, :max_age => 3.minutes.to_i
|
41
|
+
|
46
42
|
@posts = Post.latest.limit(10)
|
47
43
|
content_type 'application/atom+xml; charset=utf-8'
|
48
44
|
haml :atom, :format => :xhtml, :layout => false
|
49
45
|
end
|
50
46
|
|
51
47
|
get '/feed/?' do
|
52
|
-
redirect
|
48
|
+
redirect config.blog_feed_url, 307
|
53
49
|
end
|
54
50
|
|
55
51
|
get %r{^/(\d{4})/(\d{1,2})/(\d{1,2})/?$} do
|
@@ -90,10 +86,12 @@ module SchnitzelPress
|
|
90
86
|
if enforce_canonical_url && request.path != url_for(@post)
|
91
87
|
redirect url_for(@post)
|
92
88
|
else
|
93
|
-
fresh_when :last_modified => @post.updated_at,
|
94
|
-
|
89
|
+
fresh_when :last_modified => @post.updated_at,
|
90
|
+
:etag => CacheControl.etag(@post.updated_at)
|
95
91
|
|
96
92
|
@show_description = @post.home_page?
|
93
|
+
|
94
|
+
cache_control :public, :must_revalidate, :s_maxage => 2, :max_age => 60
|
97
95
|
haml :post
|
98
96
|
end
|
99
97
|
else
|
@@ -104,10 +102,10 @@ module SchnitzelPress
|
|
104
102
|
def render_posts
|
105
103
|
if freshest_post = @posts.where(:updated_at.ne => nil).desc(:updated_at).first
|
106
104
|
fresh_when :last_modified => freshest_post.updated_at,
|
107
|
-
:etag => freshest_post.
|
108
|
-
cache_for 60
|
105
|
+
:etag => CacheControl.etag(freshest_post.updated_at)
|
109
106
|
end
|
110
107
|
|
108
|
+
cache_control :public, :must_revalidate, :s_maxage => 2, :max_age => 60
|
111
109
|
haml :index
|
112
110
|
end
|
113
111
|
end
|
data/lib/schnitzelpress/app.rb
CHANGED
@@ -1,10 +1,13 @@
|
|
1
|
-
|
1
|
+
require "sinatra/content_for"
|
2
|
+
|
3
|
+
module Schnitzelpress
|
2
4
|
class App < Sinatra::Base
|
3
5
|
STATIC_PATHS = ["/favicon.ico", "/img", "/js"]
|
4
6
|
|
5
7
|
set :views, ['./views/', File.expand_path('../../views/', __FILE__)]
|
6
8
|
set :public_folder, File.expand_path('../../public/', __FILE__)
|
7
9
|
|
10
|
+
use Rack::Cache if Schnitzelpress.env.production?
|
8
11
|
use Rack::ShowExceptions
|
9
12
|
use Rack::StaticCache,
|
10
13
|
:urls => STATIC_PATHS,
|
@@ -12,31 +15,25 @@ module SchnitzelPress
|
|
12
15
|
use Rack::MethodOverride
|
13
16
|
use Rack::Session::Cookie
|
14
17
|
|
15
|
-
helpers
|
18
|
+
helpers Sinatra::ContentFor
|
19
|
+
helpers Schnitzelpress::Helpers
|
16
20
|
include Rack::Utils
|
17
|
-
include
|
18
|
-
include
|
19
|
-
include
|
21
|
+
include Schnitzelpress::Actions::Auth
|
22
|
+
include Schnitzelpress::Actions::Assets
|
23
|
+
include Schnitzelpress::Actions::Admin
|
24
|
+
include Schnitzelpress::Actions::Blog
|
20
25
|
|
21
26
|
configure do
|
22
|
-
set :blog_title, "My SchnitzelPress Blog"
|
23
|
-
set :blog_description, ""
|
24
|
-
set :author_name, "Author"
|
25
|
-
set :disqus_name, nil
|
26
|
-
set :google_analytics_id, nil
|
27
|
-
set :gauges_id, nil
|
28
|
-
set :read_more, "Read Complete Article"
|
29
|
-
set :twitter_id, nil
|
30
|
-
set :footer, ""
|
31
|
-
set :administrator, nil
|
32
|
-
set :feed_url, '/blog.atom'
|
33
|
-
|
34
27
|
disable :protection
|
35
28
|
set :logging, true
|
36
29
|
end
|
37
30
|
|
38
|
-
|
39
|
-
|
31
|
+
before do
|
32
|
+
# Reload configuration before every request. I know this isn't ideal,
|
33
|
+
# but right now it's the easiest way to get the configuration in synch
|
34
|
+
# across multiple instances of the app.
|
35
|
+
#
|
36
|
+
Config.instance.reload
|
40
37
|
end
|
41
38
|
|
42
39
|
def fresh_when(options)
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Schnitzelpress
|
2
|
+
module CacheControl
|
3
|
+
class << self
|
4
|
+
def timestamp
|
5
|
+
Schnitzelpress::Config.get 'cache_timestamp'
|
6
|
+
end
|
7
|
+
|
8
|
+
def bust!
|
9
|
+
Schnitzelpress::Config.set 'cache_timestamp', Time.now
|
10
|
+
end
|
11
|
+
|
12
|
+
def etag(*args)
|
13
|
+
Digest::MD5.hexdigest("-#{timestamp.to_i}-#{args.join '-'}-")
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
data/lib/schnitzelpress/cli.rb
CHANGED
@@ -1,27 +1,58 @@
|
|
1
1
|
require "thor"
|
2
2
|
|
3
|
-
module
|
3
|
+
module Schnitzelpress
|
4
4
|
class Cli < Thor
|
5
5
|
include Thor::Actions
|
6
6
|
|
7
7
|
source_root(File.expand_path('../../templates', __FILE__))
|
8
8
|
|
9
|
-
desc "create NAME", "Creates a new
|
10
|
-
|
11
|
-
method_option :git, :aliases => "-g", :default => false,
|
9
|
+
desc "create NAME", "Creates a new Schnitzelpress blog."
|
10
|
+
method_option :git, :aliases => "-g", :default => false, :type => :boolean,
|
12
11
|
:desc => "Initialize a git repository in your blog's directory."
|
13
12
|
|
14
|
-
method_option :bundle, :aliases => "-b", :default => false,
|
15
|
-
:desc => "Run 'bundle install' after generating your new blog."
|
16
|
-
|
17
13
|
def create(name)
|
18
14
|
@name = name
|
19
15
|
self.destination_root = name
|
20
16
|
directory 'new_blog', '.'
|
21
17
|
|
22
18
|
in_root do
|
23
|
-
|
24
|
-
|
19
|
+
if options[:git]
|
20
|
+
run "git init"
|
21
|
+
run "git add ."
|
22
|
+
run "git commit -m 'Created new Schnitzelpress blog'"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
desc "update", "Update your blog's bundled Schnitzelpress version."
|
28
|
+
def update
|
29
|
+
run "bundle update schnitzelpress"
|
30
|
+
end
|
31
|
+
|
32
|
+
desc "console", "Run the Schnitzelpress console."
|
33
|
+
def console
|
34
|
+
require 'schnitzelpress'
|
35
|
+
require 'pry'
|
36
|
+
Schnitzelpress.init!
|
37
|
+
ARGV.clear
|
38
|
+
pry Schnitzelpress
|
39
|
+
end
|
40
|
+
|
41
|
+
desc "mongo_pull", "Pulls contents of remote MongoDB into your local MongoDB"
|
42
|
+
def mongo_pull
|
43
|
+
if uri = YAML.load_file('./config/mongo.yml')['development']['uri']
|
44
|
+
system "MONGO_URL=\"#{uri}\" heroku mongo:pull"
|
45
|
+
else
|
46
|
+
abort "URI is missing :("
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
desc "mongo_push", "Pushes contents of your local MongoDB to remote MongoDB"
|
51
|
+
def mongo_push
|
52
|
+
if uri = YAML.load_file('./config/mongo.yml')['development']['uri']
|
53
|
+
system "MONGO_URL=\"#{uri}\" heroku mongo:push"
|
54
|
+
else
|
55
|
+
abort "URI is missing :("
|
25
56
|
end
|
26
57
|
end
|
27
58
|
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module Schnitzelpress
|
2
|
+
class Config
|
3
|
+
include Mongoid::Document
|
4
|
+
include Mongoid::Timestamps
|
5
|
+
identity :type => String
|
6
|
+
store_in :config
|
7
|
+
|
8
|
+
field :blog_title, :type => String, :default => "A New Schnitzelpress Blog"
|
9
|
+
field :blog_description, :type => String, :default => ""
|
10
|
+
field :blog_footer, :type => String, :default => "powered by [Schnitzelpress](http://schnitzelpress.org)"
|
11
|
+
field :blog_feed_url, :type => String, :default => "/blog.atom"
|
12
|
+
|
13
|
+
field :author_name, :type => String, :default => "Joe Schnitzel"
|
14
|
+
|
15
|
+
field :disqus_id, :type => String
|
16
|
+
field :google_analytics_id, :type => String
|
17
|
+
field :gauges_id, :type => String
|
18
|
+
field :twitter_id, :type => String
|
19
|
+
|
20
|
+
field :cache_timestamp, :type => DateTime
|
21
|
+
|
22
|
+
validates :blog_title, :author_name, :presence => true
|
23
|
+
|
24
|
+
class << self
|
25
|
+
def instance
|
26
|
+
@@instance ||= find_or_create_by(:id => 'schnitzelpress')
|
27
|
+
end
|
28
|
+
|
29
|
+
def forget_instance
|
30
|
+
@@instance = nil
|
31
|
+
end
|
32
|
+
|
33
|
+
def get(k)
|
34
|
+
instance.send(k)
|
35
|
+
end
|
36
|
+
|
37
|
+
def set(k, v)
|
38
|
+
instance.update_attributes!(k => v)
|
39
|
+
v
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|