schnitzelpress 0.0.5

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.
Files changed (51) hide show
  1. data/.gitignore +21 -0
  2. data/.rspec +1 -0
  3. data/.travis.yml +9 -0
  4. data/.watchr +15 -0
  5. data/Gemfile +4 -0
  6. data/LICENSE +22 -0
  7. data/README.md +5 -0
  8. data/Rakefile +7 -0
  9. data/bin/schnitzelpress +5 -0
  10. data/lib/public/.gitkeep +0 -0
  11. data/lib/public/favicon.ico +0 -0
  12. data/lib/schnitzelpress.rb +30 -0
  13. data/lib/schnitzelpress/actions/admin.rb +49 -0
  14. data/lib/schnitzelpress/actions/auth.rb +29 -0
  15. data/lib/schnitzelpress/actions/blog.rb +70 -0
  16. data/lib/schnitzelpress/app.rb +45 -0
  17. data/lib/schnitzelpress/cli.rb +28 -0
  18. data/lib/schnitzelpress/helpers.rb +72 -0
  19. data/lib/schnitzelpress/post.rb +168 -0
  20. data/lib/schnitzelpress/rake.rb +23 -0
  21. data/lib/schnitzelpress/static.rb +17 -0
  22. data/lib/schnitzelpress/version.rb +3 -0
  23. data/lib/templates/new_blog/.gitignore +5 -0
  24. data/lib/templates/new_blog/Gemfile +19 -0
  25. data/lib/templates/new_blog/Rakefile +2 -0
  26. data/lib/templates/new_blog/app.rb.tt +28 -0
  27. data/lib/templates/new_blog/config.ru.tt +2 -0
  28. data/lib/templates/new_blog/public/.gitkeep +0 -0
  29. data/lib/views/404.haml +4 -0
  30. data/lib/views/admin/admin.haml +12 -0
  31. data/lib/views/admin/edit.haml +3 -0
  32. data/lib/views/admin/new.haml +3 -0
  33. data/lib/views/atom.haml +23 -0
  34. data/lib/views/blog.scss +1 -0
  35. data/lib/views/index.haml +6 -0
  36. data/lib/views/layout.haml +25 -0
  37. data/lib/views/partials/_admin_post_list.haml +11 -0
  38. data/lib/views/partials/_disqus.haml +17 -0
  39. data/lib/views/partials/_form_field.haml +29 -0
  40. data/lib/views/partials/_gauges.haml +12 -0
  41. data/lib/views/partials/_google_analytics.haml +10 -0
  42. data/lib/views/partials/_post.haml +44 -0
  43. data/lib/views/partials/_post_form.haml +18 -0
  44. data/lib/views/post.haml +7 -0
  45. data/lib/views/schnitzelpress.scss +106 -0
  46. data/schnitzelpress.gemspec +60 -0
  47. data/spec/app_spec.rb +56 -0
  48. data/spec/factories.rb +28 -0
  49. data/spec/post_spec.rb +78 -0
  50. data/spec/spec_helper.rb +36 -0
  51. metadata +426 -0
data/.gitignore ADDED
@@ -0,0 +1,21 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ .rbfu-version
7
+ .powenv
8
+ .sass-cache
9
+ InstalledFiles
10
+ _yardoc
11
+ coverage
12
+ doc/
13
+ lib/bundler/man
14
+ pkg
15
+ rdoc
16
+ spec/reports
17
+ test/tmp
18
+ test/version_tmp
19
+ tmp
20
+ *.sublime*
21
+ Gemfile.lock
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/.travis.yml ADDED
@@ -0,0 +1,9 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.2
4
+ - 1.9.3
5
+ #- jruby-19mode # JRuby in 1.9 mode
6
+ # - rbx-18mode
7
+ # - rbx-19mode # currently in active development, may or may not work for your project
8
+ # uncomment this line if your project needs to run something other than `rake`:
9
+ # script: bundle exec rspec spec
data/.watchr ADDED
@@ -0,0 +1,15 @@
1
+ def run(cmd, msg = nil)
2
+ puts "=== %s" % msg if msg
3
+ puts "=== %s" % cmd
4
+ system cmd
5
+ puts "\n"
6
+ end
7
+
8
+ watch("spec/.*_spec\.rb") { |m| run("bundle exec rspec %s" % m[0]) }
9
+ watch("lib/schnitzelpress/(.*)\.rb") { |m| run("bundle exec rspec spec/%s_spec.rb" % m[1]) }
10
+ watch('^spec/(spec_helper|factories)\.rb') { |f| run "bundle exec rake spec", "%s.rb has been modified" % f }
11
+
12
+ # Ctrl-\
13
+ Signal.trap('QUIT') { run("bundle exec rake spec") }
14
+ # Ctrl-C
15
+ Signal.trap('INT') { abort("\nQuitting.") }
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in schnitzelpress.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Hendrik Mans
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,5 @@
1
+ # SchnitzelPress
2
+
3
+ ## A lean, mean blogging machine for hackers and fools.
4
+
5
+ [![Build Status](https://secure.travis-ci.org/teamschnitzel/schnitzelpress.png?branch=master)](http://travis-ci.org/teamschnitzel/schnitzelpress)
data/Rakefile ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
3
+
4
+ # integrate rspec
5
+ require 'rspec/core/rake_task'
6
+ RSpec::Core::RakeTask.new('spec')
7
+ task :default => :spec
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+ require "rubygems"
3
+ require "schnitzelpress/cli"
4
+
5
+ SchnitzelPress::Cli.start
File without changes
Binary file
@@ -0,0 +1,30 @@
1
+ require 'schnitzelpress/version'
2
+
3
+ require 'sinatra'
4
+ require 'haml'
5
+ require 'sass'
6
+ require 'redcarpet'
7
+ require 'schnitzelstyle'
8
+ require 'rack-cache'
9
+ require 'mongoid'
10
+ require 'chronic'
11
+
12
+ require 'active_support/inflector'
13
+ require 'active_support/core_ext/class'
14
+ require 'active_support/concern'
15
+
16
+ require 'schnitzelpress/app'
17
+
18
+ Sass::Engine::DEFAULT_OPTIONS[:load_paths].unshift(File.expand_path("../views", __FILE__))
19
+ Sass::Engine::DEFAULT_OPTIONS[:load_paths].unshift(File.expand_path("./views"))
20
+
21
+ Mongoid.logger.level = 3
22
+
23
+ module SchnitzelPress
24
+ mattr_reader :mongo_uri
25
+
26
+ def self.mongo_uri=(uri)
27
+ Mongoid::Config.from_hash("uri" => uri)
28
+ @@mongo_uri = uri
29
+ end
30
+ end
@@ -0,0 +1,49 @@
1
+ module SchnitzelPress
2
+ module Actions
3
+ module Admin
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ before '/admin/?*' do
8
+ admin_only!
9
+ end
10
+
11
+ get '/admin/?' do
12
+ @posts = Post.published.posts.desc(:published_at)
13
+ @pages = Post.published.pages
14
+ @drafts = Post.drafts
15
+ haml :'admin/admin'
16
+ end
17
+
18
+ get '/admin/new/?' do
19
+ @post = Post.new
20
+ haml :'admin/new'
21
+ end
22
+
23
+ post '/admin/new/?' do
24
+ @post = Post.new(params[:post])
25
+ if @post.save
26
+ redirect url_for(@post)
27
+ else
28
+ haml :'admin/new'
29
+ end
30
+ end
31
+
32
+ get '/admin/edit/:id/?' do
33
+ @post = Post.find(params[:id])
34
+ haml :'admin/edit'
35
+ end
36
+
37
+ post '/admin/edit/:id/?' do
38
+ @post = Post.find(params[:id])
39
+ @post.attributes = params[:post]
40
+ if @post.save
41
+ redirect url_for(@post)
42
+ else
43
+ haml :'admin/edit'
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,29 @@
1
+ require 'omniauth'
2
+ require 'omniauth-browserid'
3
+
4
+ module SchnitzelPress
5
+ module Actions
6
+ module Auth
7
+ extend ActiveSupport::Concern
8
+
9
+ included do
10
+ use OmniAuth::Strategies::BrowserID
11
+
12
+ post '/auth/:provider/callback' do
13
+ auth = request.env['omniauth.auth']
14
+ session[:user] = "#{auth['provider']}:#{auth['uid']}"
15
+ redirect admin_logged_in? ? '/admin/' : '/'
16
+ end
17
+
18
+ get '/login' do
19
+ redirect '/auth/browser_id'
20
+ end
21
+
22
+ get '/logout' do
23
+ session[:user] = nil
24
+ redirect '/'
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,70 @@
1
+ module SchnitzelPress
2
+ module Actions
3
+ module Blog
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ get '/' do
8
+ # cache_for 5.minutes
9
+ @posts = Post.latest.skip(params[:page].to_i * 10).limit(10)
10
+ @show_description = true
11
+ haml :index
12
+ end
13
+
14
+ get '/blog.css' do
15
+ cache_for 1.hour
16
+ scss :blog
17
+ end
18
+
19
+ get '/posts.atom' do
20
+ cache_for 3.minutes
21
+ @posts = Post.latest.limit(10)
22
+ content_type 'application/atom+xml; charset=utf-8'
23
+ haml :atom, :format => :xhtml, :layout => false
24
+ end
25
+
26
+ get '/feed/?' do
27
+ redirect settings.feed_url
28
+ end
29
+
30
+ get %r{^/(\d{4})/(\d{1,2})/?$} do
31
+ year, month = params[:captures]
32
+ @posts = Post.for_month(year.to_i, month.to_i)
33
+ haml :index
34
+ end
35
+
36
+ get %r{^/(\d{4})/?$} do
37
+ year = params[:captures].first
38
+ @posts = Post.for_year(year.to_i)
39
+ haml :index
40
+ end
41
+
42
+ get '/:year/:month/:day/:slug/?' do |year, month, day, slug|
43
+ @post = Post.
44
+ for_day(year.to_i, month.to_i, day.to_i).
45
+ where(slugs: slug).first
46
+
47
+ render_post
48
+ end
49
+
50
+ get '/:slug/?' do |slug|
51
+ @post = Post.where(slugs: slug).first
52
+ render_post
53
+ end
54
+
55
+ def render_post
56
+ if @post
57
+ # enforce canonical URL
58
+ if request.path != url_for(@post)
59
+ redirect url_for(@post)
60
+ else
61
+ haml :post
62
+ end
63
+ else
64
+ halt 404
65
+ end
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,45 @@
1
+ require 'schnitzelpress/static'
2
+ require 'schnitzelpress/helpers'
3
+ require 'schnitzelpress/post'
4
+ require 'schnitzelpress/actions/blog'
5
+ require 'schnitzelpress/actions/auth'
6
+ require 'schnitzelpress/actions/admin'
7
+
8
+ module SchnitzelPress
9
+ class App < Sinatra::Base
10
+ set :views, ['./views/', File.expand_path('../../views/', __FILE__)]
11
+ set :public_folder, File.expand_path('../../public/', __FILE__)
12
+
13
+ use SchnitzelPress::Static
14
+ use Rack::ShowExceptions
15
+ use Rack::Cache
16
+ use Rack::Session::Cookie
17
+
18
+ helpers SchnitzelPress::Helpers
19
+ include SchnitzelPress::Actions::Auth
20
+ include SchnitzelPress::Actions::Admin
21
+ include SchnitzelPress::Actions::Blog
22
+
23
+ configure do
24
+ set :blog_title, "My SchnitzelPress Blog"
25
+ set :blog_description, ""
26
+ set :author_name, "Author"
27
+ set :disqus_name, nil
28
+ set :google_analytics_id, nil
29
+ set :gauges_id, nil
30
+ set :read_more, "Read Complete Article"
31
+ set :twitter_id, nil
32
+ set :footer, ""
33
+ set :administrator, nil
34
+ set :feed_url, '/posts.atom'
35
+ end
36
+
37
+ def cache_for(time)
38
+ cache_control :public, :must_revalidate, :max_age => time.to_i
39
+ end
40
+
41
+ not_found do
42
+ haml :"404"
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,28 @@
1
+ require "thor"
2
+
3
+ module SchnitzelPress
4
+ class Cli < Thor
5
+ include Thor::Actions
6
+
7
+ source_root(File.expand_path('../../templates', __FILE__))
8
+
9
+ desc "create NAME", "Creates a new SchnitzelPress blog."
10
+
11
+ method_option :git, :aliases => "-g", :default => false,
12
+ :desc => "Initialize a git repository in your blog's directory."
13
+
14
+ method_option :bundle, :aliases => "-b", :default => false,
15
+ :desc => "Run 'bundle install' after generating your new blog."
16
+
17
+ def create(name)
18
+ @name = name
19
+ self.destination_root = name
20
+ directory 'new_blog', '.'
21
+
22
+ in_root do
23
+ run "bundle" if options[:bundle]
24
+ run "git init" if options[:git]
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,72 @@
1
+ module SchnitzelPress
2
+ module Helpers
3
+ def find_template(views, name, engine, &block)
4
+ Array(views).each { |v| super(v, name, engine, &block) }
5
+ end
6
+
7
+ def base_url
8
+ "#{env['rack.url_scheme']}://#{env['HTTP_HOST']}/"
9
+ end
10
+
11
+ def partial(thing, locals = {})
12
+ name = case thing
13
+ when String then thing
14
+ else thing.class.to_s.demodulize.underscore
15
+ end
16
+
17
+ haml :"partials/_#{name}", :locals => { name.to_sym => thing }.merge(locals)
18
+ end
19
+
20
+ def set_page_title(title)
21
+ @page_title = title
22
+ end
23
+
24
+ def url_for(thing, options = {})
25
+ url = thing.respond_to?(:to_url) ? thing.to_url : thing.to_s
26
+ url = "#{base_url.sub(/\/$/, '')}#{url}" if options[:absolute]
27
+ url
28
+ end
29
+
30
+ def show_disqus?
31
+ settings.disqus_name.present?
32
+ end
33
+
34
+ def production?
35
+ settings.environment.to_sym == :production
36
+ end
37
+
38
+ def user_logged_in?
39
+ session[:user].present?
40
+ end
41
+
42
+ def admin_logged_in?
43
+ user_logged_in? && session[:user] == settings.administrator
44
+ end
45
+
46
+ def admin_only!
47
+ redirect '/login' unless admin_logged_in?
48
+ end
49
+
50
+ def form_field(object, attribute, options = {})
51
+ options = {
52
+ label: attribute.to_s.humanize,
53
+ value: object.send(attribute),
54
+ errors: object.errors[attribute.to_sym],
55
+ class_name: object.class.to_s.demodulize.underscore
56
+ }.merge(options)
57
+
58
+ options[:name] ||= "#{options[:class_name]}[#{attribute}]"
59
+ options[:id] ||= object.new_record? ?
60
+ "new_#{options[:class_name]}_#{attribute}" :
61
+ "#{options[:class_name]}_#{object.id}_#{attribute}"
62
+ options[:class] ||= "#{options[:class_name]}_#{attribute}"
63
+
64
+ options[:type] ||= case options[:value]
65
+ when DateTime, Time, Date then :datetime
66
+ else :text
67
+ end
68
+
69
+ partial 'form_field', object: object, attribute: attribute, options: options
70
+ end
71
+ end
72
+ end