schnitzelpress 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
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