cloudpress 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +10 -0
- data/.travis.yml +3 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +39 -0
- data/Rakefile +30 -0
- data/app/assets/cloudpress/cloudpress.css.sass +1 -0
- data/app/assets/cloudpress/code/railscasts.css +70 -0
- data/app/controllers/cloudpress/application_controller.rb +12 -0
- data/app/controllers/cloudpress/archives_controller.rb +34 -0
- data/app/controllers/cloudpress/posts_controller.rb +23 -0
- data/app/controllers/cloudpress/tags_controller.rb +20 -0
- data/app/helpers/cloudpress/renderer_helper.rb +23 -0
- data/app/jobs/cloudpress/update_posts_job.rb +9 -0
- data/app/models/cloudpress/archive.rb +50 -0
- data/app/models/cloudpress/post.rb +65 -0
- data/app/views/cloudpress/archives/_archive.html.slim +3 -0
- data/app/views/cloudpress/archives/_archives.html.slim +2 -0
- data/app/views/cloudpress/archives/_month.html.slim +2 -0
- data/app/views/cloudpress/archives/show.html.slim +1 -0
- data/app/views/cloudpress/posts/_intro.html.slim +9 -0
- data/app/views/cloudpress/posts/_post.html.slim +8 -0
- data/app/views/cloudpress/posts/index.html.slim +1 -0
- data/app/views/cloudpress/posts/show.html.slim +1 -0
- data/app/views/cloudpress/tags/_tag.html.slim +2 -0
- data/app/views/cloudpress/tags/_tags.html.slim +2 -0
- data/app/views/cloudpress/tags/show.html.slim +1 -0
- data/bin/console +14 -0
- data/bin/rails +12 -0
- data/bin/setup +7 -0
- data/cloudpress.gemspec +35 -0
- data/config/initializers/tag_extensions.rb +4 -0
- data/config/routes.rb +9 -0
- data/db/migrate/20150309115639_create_cloudpress_posts.rb +19 -0
- data/db/migrate/20150315192521_create_tags_table.rb +30 -0
- data/db/migrate/20150315193206_create_friendly_id_slugs.rb +15 -0
- data/db/migrate/20150317121651_add_slug_to_tags.rb +6 -0
- data/db/migrate/20150317122608_add_taggings_counter_cache.rb +14 -0
- data/lib/cloudpress.rb +105 -0
- data/lib/cloudpress/dropbox/cleaner.rb +20 -0
- data/lib/cloudpress/dropbox/client.rb +15 -0
- data/lib/cloudpress/dropbox/connector.rb +24 -0
- data/lib/cloudpress/dropbox/directory.rb +57 -0
- data/lib/cloudpress/dropbox/file.rb +57 -0
- data/lib/cloudpress/engine.rb +10 -0
- data/lib/cloudpress/formatters/html_with_pygments.rb +7 -0
- data/lib/cloudpress/renderers/archive.rb +18 -0
- data/lib/cloudpress/renderers/archives.rb +24 -0
- data/lib/cloudpress/renderers/post.rb +39 -0
- data/lib/cloudpress/renderers/posts.rb +38 -0
- data/lib/cloudpress/renderers/tag.rb +18 -0
- data/lib/cloudpress/renderers/tags.rb +24 -0
- data/lib/cloudpress/version.rb +3 -0
- data/lib/generators/cloudpress/initializer/USAGE +8 -0
- data/lib/generators/cloudpress/initializer/initializer_generator.rb +32 -0
- metadata +283 -0
@@ -0,0 +1 @@
|
|
1
|
+
= render_cloudpress_posts(posts)
|
@@ -0,0 +1,9 @@
|
|
1
|
+
article id="post-#{renderer.post.id}"
|
2
|
+
header
|
3
|
+
h1 = link_to renderer.post.title, post_path(renderer.post)
|
4
|
+
time = renderer.post.publish_date.to_s(:long)
|
5
|
+
= render_cloudpress_tags(renderer.post.tags) if renderer.tags?
|
6
|
+
p
|
7
|
+
= renderer.post.summary
|
8
|
+
footer
|
9
|
+
= link_to 'Read more', post_path(renderer.post)
|
@@ -0,0 +1 @@
|
|
1
|
+
= render_cloudpress_posts(posts)
|
@@ -0,0 +1 @@
|
|
1
|
+
= render_cloudpress_post(post)
|
@@ -0,0 +1 @@
|
|
1
|
+
= render_cloudpress_posts(posts)
|
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "cloudpress"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start
|
data/bin/rails
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# This command will automatically be run when you run "rails" with Rails 4 gems installed from the root of your application.
|
3
|
+
|
4
|
+
ENGINE_ROOT = File.expand_path('../..', __FILE__)
|
5
|
+
ENGINE_PATH = File.expand_path('../../lib/cloudpress/engine', __FILE__)
|
6
|
+
|
7
|
+
# Set up gems listed in the Gemfile.
|
8
|
+
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
|
9
|
+
require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE'])
|
10
|
+
|
11
|
+
require 'rails/all'
|
12
|
+
require 'rails/engine/commands'
|
data/bin/setup
ADDED
data/cloudpress.gemspec
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'cloudpress/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "cloudpress"
|
8
|
+
spec.version = Cloudpress::VERSION
|
9
|
+
spec.authors = ["Adam Carlile"]
|
10
|
+
spec.email = ["adam@benchmedia.co.uk"]
|
11
|
+
|
12
|
+
spec.summary = "A blogging framework that uses dropbox as it's storage engine"
|
13
|
+
spec.homepage = "http://github.com/adamcarlile/cloudpress"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
17
|
+
spec.bindir = "exe"
|
18
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_dependency "dropbox-sdk"
|
22
|
+
spec.add_dependency "metadown"
|
23
|
+
spec.add_dependency "pygments.rb"
|
24
|
+
spec.add_dependency "nokogiri"
|
25
|
+
spec.add_dependency "kaminari"
|
26
|
+
spec.add_dependency "builder"
|
27
|
+
spec.add_dependency "groupdate"
|
28
|
+
spec.add_dependency "slim"
|
29
|
+
spec.add_dependency "acts-as-taggable-on"
|
30
|
+
spec.add_dependency "friendly_id"
|
31
|
+
spec.add_dependency "rails", "~> 4.2.0"
|
32
|
+
|
33
|
+
spec.add_development_dependency "bundler", "~> 1.8"
|
34
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
35
|
+
end
|
data/config/routes.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
class CreateCloudpressPosts < ActiveRecord::Migration
|
2
|
+
def change
|
3
|
+
create_table :cloudpress_posts do |t|
|
4
|
+
t.string :title
|
5
|
+
t.string :slug
|
6
|
+
t.string :file_path
|
7
|
+
t.string :revision
|
8
|
+
t.string :state
|
9
|
+
t.text :body
|
10
|
+
t.json :metadata
|
11
|
+
t.datetime :publish_date
|
12
|
+
t.timestamps null: false
|
13
|
+
end
|
14
|
+
|
15
|
+
add_index :cloudpress_posts, :state
|
16
|
+
add_index :cloudpress_posts, :slug
|
17
|
+
add_index :cloudpress_posts, :file_path
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
class CreateTagsTable < ActiveRecord::Migration
|
2
|
+
def self.up
|
3
|
+
create_table :tags do |t|
|
4
|
+
t.string :name
|
5
|
+
end
|
6
|
+
|
7
|
+
create_table :taggings do |t|
|
8
|
+
t.references :tag
|
9
|
+
|
10
|
+
# You should make sure that the column created is
|
11
|
+
# long enough to store the required class names.
|
12
|
+
t.references :taggable, :polymorphic => true
|
13
|
+
t.references :tagger, :polymorphic => true
|
14
|
+
|
15
|
+
# Limit is created to prevent MySQL error on index
|
16
|
+
# length for MyISAM table type: http://bit.ly/vgW2Ql
|
17
|
+
t.string :context, :limit => 128
|
18
|
+
|
19
|
+
t.datetime :created_at
|
20
|
+
end
|
21
|
+
|
22
|
+
add_index :taggings, :tag_id
|
23
|
+
add_index :taggings, [:taggable_id, :taggable_type, :context]
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.down
|
27
|
+
drop_table :taggings
|
28
|
+
drop_table :tags
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
class CreateFriendlyIdSlugs < ActiveRecord::Migration
|
2
|
+
def change
|
3
|
+
create_table :friendly_id_slugs do |t|
|
4
|
+
t.string :slug, :null => false
|
5
|
+
t.integer :sluggable_id, :null => false
|
6
|
+
t.string :sluggable_type, :limit => 50
|
7
|
+
t.string :scope
|
8
|
+
t.datetime :created_at
|
9
|
+
end
|
10
|
+
add_index :friendly_id_slugs, :sluggable_id
|
11
|
+
add_index :friendly_id_slugs, [:slug, :sluggable_type]
|
12
|
+
add_index :friendly_id_slugs, [:slug, :sluggable_type, :scope], :unique => true
|
13
|
+
add_index :friendly_id_slugs, :sluggable_type
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
class AddTaggingsCounterCache < ActiveRecord::Migration
|
2
|
+
def self.up
|
3
|
+
add_column :tags, :taggings_count, :integer, default: 0
|
4
|
+
|
5
|
+
ActsAsTaggableOn::Tag.reset_column_information
|
6
|
+
ActsAsTaggableOn::Tag.find_each do |tag|
|
7
|
+
ActsAsTaggableOn::Tag.reset_counters(tag.id, :taggings)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.down
|
12
|
+
remove_column :tags, :taggings_count
|
13
|
+
end
|
14
|
+
end
|
data/lib/cloudpress.rb
ADDED
@@ -0,0 +1,105 @@
|
|
1
|
+
require "dropbox_sdk"
|
2
|
+
require "metadown"
|
3
|
+
require "redcarpet"
|
4
|
+
require "pygments"
|
5
|
+
require "kaminari"
|
6
|
+
require "groupdate"
|
7
|
+
require "slim"
|
8
|
+
require "friendly_id"
|
9
|
+
require "acts-as-taggable-on"
|
10
|
+
require "cloudpress/version"
|
11
|
+
require "cloudpress/engine"
|
12
|
+
|
13
|
+
require "cloudpress/formatters/html_with_pygments"
|
14
|
+
require "cloudpress/dropbox/client"
|
15
|
+
require "cloudpress/dropbox/connector"
|
16
|
+
require "cloudpress/dropbox/directory"
|
17
|
+
require "cloudpress/dropbox/file"
|
18
|
+
require "cloudpress/dropbox/cleaner"
|
19
|
+
|
20
|
+
require "cloudpress/renderers/archive"
|
21
|
+
require "cloudpress/renderers/archives"
|
22
|
+
require "cloudpress/renderers/post"
|
23
|
+
require "cloudpress/renderers/posts"
|
24
|
+
require "cloudpress/renderers/tag"
|
25
|
+
require "cloudpress/renderers/tags"
|
26
|
+
|
27
|
+
module Cloudpress
|
28
|
+
|
29
|
+
module_function
|
30
|
+
|
31
|
+
def config
|
32
|
+
@config ? @config : configure
|
33
|
+
end
|
34
|
+
|
35
|
+
def configure &block
|
36
|
+
@config = ActiveSupport::OrderedOptions.new
|
37
|
+
@config.app_key = nil
|
38
|
+
@config.app_secret = nil
|
39
|
+
@config.app_token = nil
|
40
|
+
@config.base_path = 'cloudpress'
|
41
|
+
@config.live_path = 'live'
|
42
|
+
@config.draft_path = 'draft'
|
43
|
+
@config.markdown_renderer = Redcarpet::Markdown.new(Formatters::HTMLWithPygments, fenced_code_blocks: true)
|
44
|
+
yield(@config) if block_given?
|
45
|
+
@config
|
46
|
+
end
|
47
|
+
|
48
|
+
def base_path
|
49
|
+
"/#{config.base_path}"
|
50
|
+
end
|
51
|
+
|
52
|
+
def reload!
|
53
|
+
@file_index = nil
|
54
|
+
end
|
55
|
+
|
56
|
+
def live_path
|
57
|
+
[base_path, config.live_path].join('/')
|
58
|
+
end
|
59
|
+
|
60
|
+
def draft_path
|
61
|
+
[base_path, config.draft_path].join('/')
|
62
|
+
end
|
63
|
+
|
64
|
+
def update!
|
65
|
+
reload!
|
66
|
+
import!
|
67
|
+
purge!
|
68
|
+
end
|
69
|
+
|
70
|
+
def import!
|
71
|
+
file_index.values.each {|x| x.import!}
|
72
|
+
end
|
73
|
+
|
74
|
+
def purge!
|
75
|
+
Cloudpress::Dropbox::Cleaner.new(remote_paths, local_paths).clean!
|
76
|
+
end
|
77
|
+
|
78
|
+
def file_index
|
79
|
+
@file_index ||= {
|
80
|
+
live: Cloudpress::Dropbox::Directory.new(client, live_path, :live),
|
81
|
+
draft: Cloudpress::Dropbox::Directory.new(client, draft_path, :draft)
|
82
|
+
}
|
83
|
+
end
|
84
|
+
|
85
|
+
def client
|
86
|
+
@client ||= Cloudpress::Dropbox::Client.new(config.app_token)
|
87
|
+
end
|
88
|
+
|
89
|
+
def unconfigured?
|
90
|
+
config.app_key.blank? || config.app_secret.blank?
|
91
|
+
end
|
92
|
+
|
93
|
+
def unauthorized?
|
94
|
+
config.app_token.blank?
|
95
|
+
end
|
96
|
+
|
97
|
+
def remote_paths
|
98
|
+
file_index.values.map {|x| x.paths }.flatten
|
99
|
+
end
|
100
|
+
|
101
|
+
def local_paths
|
102
|
+
Cloudpress::Post.pluck(:file_path)
|
103
|
+
end
|
104
|
+
|
105
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Cloudpress
|
2
|
+
module Dropbox
|
3
|
+
class Cleaner
|
4
|
+
|
5
|
+
def initialize(remote_paths, local_paths)
|
6
|
+
@local_paths = local_paths
|
7
|
+
@remote_paths = remote_paths
|
8
|
+
end
|
9
|
+
|
10
|
+
def orphaned_paths
|
11
|
+
@orphaned_paths ||= @local_paths - @remote_paths
|
12
|
+
end
|
13
|
+
|
14
|
+
def clean!
|
15
|
+
Post.where(file_path: orphaned_paths).destroy_all if orphaned_paths.any?
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Cloudpress
|
2
|
+
module Dropbox
|
3
|
+
class Connector
|
4
|
+
|
5
|
+
def initialize(key, secret)
|
6
|
+
@key = key
|
7
|
+
@secret = secret
|
8
|
+
end
|
9
|
+
|
10
|
+
def flow
|
11
|
+
@flow ||= DropboxOAuth2FlowNoRedirect.new(@key, @secret)
|
12
|
+
end
|
13
|
+
|
14
|
+
def authorize_url
|
15
|
+
@authorize_url ||= flow.start
|
16
|
+
end
|
17
|
+
|
18
|
+
def authorize!(code)
|
19
|
+
flow.finish(code)
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module Cloudpress
|
2
|
+
module Dropbox
|
3
|
+
class Directory
|
4
|
+
|
5
|
+
attr_reader :path, :client, :state
|
6
|
+
|
7
|
+
def initialize(client, path, state)
|
8
|
+
@client = client
|
9
|
+
@path = path
|
10
|
+
@state = state
|
11
|
+
end
|
12
|
+
|
13
|
+
def import!
|
14
|
+
files.each { |x| x.import! }
|
15
|
+
subdirectories.each {|x| x.import! }
|
16
|
+
end
|
17
|
+
|
18
|
+
def paths
|
19
|
+
@paths ||= begin
|
20
|
+
files.map {|x| x.path } + subdirectories.map { |x| x.paths }
|
21
|
+
end.flatten.compact.uniq
|
22
|
+
end
|
23
|
+
|
24
|
+
def directory_contents
|
25
|
+
remote_path_metadata.with_indifferent_access[:contents]
|
26
|
+
end
|
27
|
+
|
28
|
+
def files
|
29
|
+
@files ||= directory_contents.select { |x| x[:is_dir] == false }.map do |x|
|
30
|
+
Cloudpress::Dropbox::File.new(x[:path], x[:rev], state)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def subdirectories
|
35
|
+
@subdirectories ||= directory_contents.select { |x| x[:is_dir] == true }.map do |x|
|
36
|
+
Cloudpress::Dropbox::Directory.new(client, x[:path], state)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def create_path!
|
43
|
+
client.connection.file_create_folder path
|
44
|
+
end
|
45
|
+
|
46
|
+
def remote_path_metadata
|
47
|
+
@remote_path_metadata ||= begin
|
48
|
+
client.connection.metadata(path)
|
49
|
+
rescue DropboxError
|
50
|
+
create_path!
|
51
|
+
client.connection.metadata(path)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|