ecrire 0.20.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +20 -0
- data/Gemfile +4 -0
- data/LICENCE +9 -0
- data/README.md +62 -0
- data/Rakefile +72 -0
- data/bin/ecrire +42 -0
- data/ecrire.gemspec +26 -0
- data/lib/ecrire/app/assets/javascripts/admin/editor/content.coffee +319 -0
- data/lib/ecrire/app/assets/javascripts/admin/editor/ext.coffee +94 -0
- data/lib/ecrire/app/assets/javascripts/admin/editor/extensions/clipboard.coffee +98 -0
- data/lib/ecrire/app/assets/javascripts/admin/editor/extensions/image.coffee +19 -0
- data/lib/ecrire/app/assets/javascripts/admin/editor/navigation/delete.js.coffee +11 -0
- data/lib/ecrire/app/assets/javascripts/admin/editor/navigation/draft.js.coffee +42 -0
- data/lib/ecrire/app/assets/javascripts/admin/editor/navigation/help.js.coffee +6 -0
- data/lib/ecrire/app/assets/javascripts/admin/editor/navigation/save.js.coffee +61 -0
- data/lib/ecrire/app/assets/javascripts/admin/editor/navigation/sticky.js.coffee +11 -0
- data/lib/ecrire/app/assets/javascripts/admin/editor/navigation/toggle.js.coffee +10 -0
- data/lib/ecrire/app/assets/javascripts/admin/editor/parsers/code.coffee +39 -0
- data/lib/ecrire/app/assets/javascripts/admin/editor/parsers/heading.coffee +19 -0
- data/lib/ecrire/app/assets/javascripts/admin/editor/parsers/image.coffee +129 -0
- data/lib/ecrire/app/assets/javascripts/admin/editor/parsers/link.coffee +44 -0
- data/lib/ecrire/app/assets/javascripts/admin/editor/parsers/lists.coffee +48 -0
- data/lib/ecrire/app/assets/javascripts/admin/editor/parsers/word.coffee +56 -0
- data/lib/ecrire/app/assets/javascripts/admin/posts/header.coffee +69 -0
- data/lib/ecrire/app/assets/javascripts/admin/posts/new.js.coffee +7 -0
- data/lib/ecrire/app/assets/javascripts/admin/posts/title.coffee +15 -0
- data/lib/ecrire/app/assets/javascripts/admin.js +5 -0
- data/lib/ecrire/app/assets/javascripts/application.js +21 -0
- data/lib/ecrire/app/assets/javascripts/shared/overlay.js.coffee +29 -0
- data/lib/ecrire/app/assets/javascripts/shared/popup.js.coffee +7 -0
- data/lib/ecrire/app/assets/javascripts/vendor/moment.js +3043 -0
- data/lib/ecrire/app/assets/javascripts/vendor/prism/prism.ruby.js +25 -0
- data/lib/ecrire/app/assets/javascripts/vendor/prism.js +578 -0
- data/lib/ecrire/app/assets/stylesheets/admin/base.css.scss +98 -0
- data/lib/ecrire/app/assets/stylesheets/admin/documentation.css.scss +28 -0
- data/lib/ecrire/app/assets/stylesheets/admin/editor/base.css.scss +41 -0
- data/lib/ecrire/app/assets/stylesheets/admin/editor/content.css.scss +57 -0
- data/lib/ecrire/app/assets/stylesheets/admin/editor/header.css.scss +62 -0
- data/lib/ecrire/app/assets/stylesheets/admin/editor/image.css.scss +58 -0
- data/lib/ecrire/app/assets/stylesheets/admin/editor/publish.css.scss +40 -0
- data/lib/ecrire/app/assets/stylesheets/admin/editor/save.css.scss +44 -0
- data/lib/ecrire/app/assets/stylesheets/admin/images.css.scss +64 -0
- data/lib/ecrire/app/assets/stylesheets/admin/loading.css.scss +48 -0
- data/lib/ecrire/app/assets/stylesheets/admin/mixins/animations.css.scss +30 -0
- data/lib/ecrire/app/assets/stylesheets/admin/mixins/form.css.scss +22 -0
- data/lib/ecrire/app/assets/stylesheets/admin/navigation.css.scss +96 -0
- data/lib/ecrire/app/assets/stylesheets/admin/posts.css.scss +46 -0
- data/lib/ecrire/app/assets/stylesheets/admin/variables.css.scss +7 -0
- data/lib/ecrire/app/assets/stylesheets/admin.css.scss +5 -0
- data/lib/ecrire/app/assets/stylesheets/application.css.scss +12 -0
- data/lib/ecrire/app/assets/stylesheets/sessions.css.scss +97 -0
- data/lib/ecrire/app/assets/stylesheets/shared/main.css.scss +5 -0
- data/lib/ecrire/app/assets/stylesheets/shared/popup.css.scss +76 -0
- data/lib/ecrire/app/assets/stylesheets/vendor/prism/ruby.scss +11 -0
- data/lib/ecrire/app/assets/stylesheets/vendor/prism.scss +149 -0
- data/lib/ecrire/app/controllers/admin/application_controller.rb +16 -0
- data/lib/ecrire/app/controllers/admin/configurations/images_controller.rb +28 -0
- data/lib/ecrire/app/controllers/admin/images_controller.rb +35 -0
- data/lib/ecrire/app/controllers/admin/labels_controller.rb +18 -0
- data/lib/ecrire/app/controllers/admin/partials_controller.rb +43 -0
- data/lib/ecrire/app/controllers/admin/posts_controller.rb +90 -0
- data/lib/ecrire/app/controllers/admin/properties_controller.rb +35 -0
- data/lib/ecrire/app/controllers/application_controller.rb +29 -0
- data/lib/ecrire/app/controllers/concerns/.keep +0 -0
- data/lib/ecrire/app/controllers/ecrire/posts_controller.rb +42 -0
- data/lib/ecrire/app/controllers/images_controller.rb +2 -0
- data/lib/ecrire/app/controllers/onboarding/databases_controller.rb +67 -0
- data/lib/ecrire/app/controllers/onboarding/users_controller.rb +32 -0
- data/lib/ecrire/app/controllers/onboarding_controller.rb +20 -0
- data/lib/ecrire/app/controllers/partials_controller.rb +8 -0
- data/lib/ecrire/app/controllers/sessions_controller.rb +23 -0
- data/lib/ecrire/app/controllers/static_controller.rb +5 -0
- data/lib/ecrire/app/forms/admin/image_builder.rb +24 -0
- data/lib/ecrire/app/forms/admin/partial_builder.rb +105 -0
- data/lib/ecrire/app/forms/admin/post_builder.rb +47 -0
- data/lib/ecrire/app/helpers/admin/images_helper.rb +60 -0
- data/lib/ecrire/app/helpers/admin/labels_helper.rb +26 -0
- data/lib/ecrire/app/helpers/admin/posts_helper.rb +26 -0
- data/lib/ecrire/app/helpers/application_helper.rb +64 -0
- data/lib/ecrire/app/helpers/content_tag_helper.rb +91 -0
- data/lib/ecrire/app/helpers/open_graph_helper.rb +45 -0
- data/lib/ecrire/app/helpers/posts_helper.rb +19 -0
- data/lib/ecrire/app/models/admin/image.rb +108 -0
- data/lib/ecrire/app/models/admin/partial.rb +4 -0
- data/lib/ecrire/app/models/admin/post.rb +56 -0
- data/lib/ecrire/app/models/concerns/.keep +0 -0
- data/lib/ecrire/app/models/image.rb +5 -0
- data/lib/ecrire/app/models/label.rb +3 -0
- data/lib/ecrire/app/models/partial.rb +3 -0
- data/lib/ecrire/app/models/post.rb +90 -0
- data/lib/ecrire/app/models/property/image.rb +30 -0
- data/lib/ecrire/app/models/property/label.rb +28 -0
- data/lib/ecrire/app/models/user.rb +31 -0
- data/lib/ecrire/app/strategies/password_strategy.rb +17 -0
- data/lib/ecrire/app/views/admin/configurations/images/complete.html.erb +6 -0
- data/lib/ecrire/app/views/admin/configurations/images/show.html.erb +14 -0
- data/lib/ecrire/app/views/admin/images/_errors.html.erb +14 -0
- data/lib/ecrire/app/views/admin/images/_form.html.erb +15 -0
- data/lib/ecrire/app/views/admin/images/destroy.js.erb +0 -0
- data/lib/ecrire/app/views/admin/images/errors.js.erb +1 -0
- data/lib/ecrire/app/views/admin/images/update.js.erb +1 -0
- data/lib/ecrire/app/views/admin/posts/_documentation.html.erb +61 -0
- data/lib/ecrire/app/views/admin/posts/_list.html.erb +18 -0
- data/lib/ecrire/app/views/admin/posts/_post.html.erb +3 -0
- data/lib/ecrire/app/views/admin/posts/edit.html.erb +73 -0
- data/lib/ecrire/app/views/admin/posts/help.js.erb +1 -0
- data/lib/ecrire/app/views/admin/posts/index.js.erb +1 -0
- data/lib/ecrire/app/views/admin/posts/title.html.erb +10 -0
- data/lib/ecrire/app/views/admin/posts/update/content.js.erb +1 -0
- data/lib/ecrire/app/views/admin/posts/update/title.js.erb +1 -0
- data/lib/ecrire/app/views/admin/properties/image/create.js.erb +14 -0
- data/lib/ecrire/app/views/admin/properties/image/destroy.js.erb +6 -0
- data/lib/ecrire/app/views/admin/properties/label/create.js.erb +8 -0
- data/lib/ecrire/app/views/admin/properties/label/destroy.js.erb +2 -0
- data/lib/ecrire/app/views/layouts/admin/application.html.erb +47 -0
- data/lib/ecrire/app/views/partials/show.html.erb +14 -0
- data/lib/ecrire/app/views/sessions/_form.html.erb +18 -0
- data/lib/ecrire/app/views/sessions/_navigation.html.erb +24 -0
- data/lib/ecrire/app/views/sessions/new.html.erb +1 -0
- data/lib/ecrire/application.rb +18 -0
- data/lib/ecrire/commands/base.rb +9 -0
- data/lib/ecrire/commands/console.rb +21 -0
- data/lib/ecrire/commands/new.rb +47 -0
- data/lib/ecrire/commands/server.rb +27 -0
- data/lib/ecrire/commands.rb +19 -0
- data/lib/ecrire/config/environment/development.rb +12 -0
- data/lib/ecrire/config/environment/production.rb +12 -0
- data/lib/ecrire/config/environment/test.rb +3 -0
- data/lib/ecrire/config/environment.rb +46 -0
- data/lib/ecrire/config/onboarding_routes.rb +11 -0
- data/lib/ecrire/config/routes.rb +32 -0
- data/lib/ecrire/db/migrate/20131111222709_create_posts.rb +16 -0
- data/lib/ecrire/db/migrate/20131113200949_create_users.rb +12 -0
- data/lib/ecrire/db/migrate/20131114205041_add_excerpt_to_post.rb +5 -0
- data/lib/ecrire/db/migrate/20131221181640_add_javascript_to_posts.rb +5 -0
- data/lib/ecrire/db/migrate/20131221195338_create_partials.rb +12 -0
- data/lib/ecrire/db/migrate/20140115215122_create_images.rb +12 -0
- data/lib/ecrire/db/migrate/20140209144412_add_favorite_flag_to_image.rb +5 -0
- data/lib/ecrire/db/migrate/20140617224837_create_labels.rb +12 -0
- data/lib/ecrire/db/migrate/20140618321984_add_properties_to_posts.rb +6 -0
- data/lib/ecrire/db/migrate/20150113839713_convert_markdown_in_post_content.rb +6 -0
- data/lib/ecrire/db/migrate/20150120093481_add_preview_to_posts.rb +8 -0
- data/lib/ecrire/db/schema.rb +76 -0
- data/lib/ecrire/locales/admin/configurations/images/en.yml +3 -0
- data/lib/ecrire/locales/admin/en.yml +26 -0
- data/lib/ecrire/locales/admin/images/en.yml +5 -0
- data/lib/ecrire/locales/admin/partials/en.yml +18 -0
- data/lib/ecrire/locales/admin/posts/en.yml +14 -0
- data/lib/ecrire/locales/en.yml +9 -0
- data/lib/ecrire/onboarding/assets/images/.keep +0 -0
- data/lib/ecrire/onboarding/assets/images/background.png +0 -0
- data/lib/ecrire/onboarding/assets/images/github-logo.png +0 -0
- data/lib/ecrire/onboarding/assets/images/profile.png +0 -0
- data/lib/ecrire/onboarding/assets/images/twitter-logo.png +0 -0
- data/lib/ecrire/onboarding/assets/javascripts/base.js +2 -0
- data/lib/ecrire/onboarding/assets/javascripts/databases/information.js.coffee +17 -0
- data/lib/ecrire/onboarding/assets/javascripts/message.js.coffee +5 -0
- data/lib/ecrire/onboarding/assets/stylesheets/base.css.scss +80 -0
- data/lib/ecrire/onboarding/assets/stylesheets/complete.css.scss +3 -0
- data/lib/ecrire/onboarding/assets/stylesheets/fonts.css.scss +17 -0
- data/lib/ecrire/onboarding/assets/stylesheets/form.css.scss +25 -0
- data/lib/ecrire/onboarding/assets/stylesheets/message.css.scss +11 -0
- data/lib/ecrire/onboarding/assets/stylesheets/terminal.css.scss +16 -0
- data/lib/ecrire/onboarding/assets/stylesheets/variables.css.scss +3 -0
- data/lib/ecrire/onboarding/assets/stylesheets/welcome.css.scss +62 -0
- data/lib/ecrire/onboarding/views/layouts/application.html.erb +16 -0
- data/lib/ecrire/onboarding/views/onboarding/complete.html.erb +6 -0
- data/lib/ecrire/onboarding/views/onboarding/databases/index.html.erb +34 -0
- data/lib/ecrire/onboarding/views/onboarding/users/index.html.erb +16 -0
- data/lib/ecrire/onboarding/views/onboarding/welcome.html.erb +12 -0
- data/lib/ecrire/railtie/onboarding.rb +63 -0
- data/lib/ecrire/railtie/theme.rb +69 -0
- data/lib/ecrire/railtie.rb +30 -0
- data/lib/ecrire/tasks/assets.rake +15 -0
- data/lib/ecrire/tasks/routes.rake +6 -0
- data/lib/ecrire/template/Gemfile +31 -0
- data/lib/ecrire/template/Rakefile +4 -0
- data/lib/ecrire/template/assets/images/.keep +0 -0
- data/lib/ecrire/template/assets/javascripts/base.js.coffee +0 -0
- data/lib/ecrire/template/assets/javascripts/post.js.coffee +0 -0
- data/lib/ecrire/template/assets/stylesheets/base.css.scss +86 -0
- data/lib/ecrire/template/assets/stylesheets/code.css.scss +24 -0
- data/lib/ecrire/template/assets/stylesheets/footer.css.scss +5 -0
- data/lib/ecrire/template/assets/stylesheets/header.css.scss +18 -0
- data/lib/ecrire/template/assets/stylesheets/home.css.scss +35 -0
- data/lib/ecrire/template/config.ru +4 -0
- data/lib/ecrire/template/controllers/posts_controller.rb +2 -0
- data/lib/ecrire/template/helpers/blog_helper.rb +2 -0
- data/lib/ecrire/template/views/layouts/application.html.erb +35 -0
- data/lib/ecrire/template/views/posts/_post.html.erb +9 -0
- data/lib/ecrire/template/views/posts/index.html.erb +13 -0
- data/lib/ecrire/template/views/posts/show.html.erb +7 -0
- data/lib/ecrire/template/views/static/about.html +0 -0
- data/lib/ecrire/template/views/static/customize/_helper.html +7 -0
- data/lib/ecrire/template/views/static/customize/_helper_used.html +6 -0
- data/lib/ecrire/template/views/static/customize/_image.html +1 -0
- data/lib/ecrire/template/views/static/customize/_index.html +1 -0
- data/lib/ecrire/template/views/static/customize/_javascript.html +1 -0
- data/lib/ecrire/template/views/static/customize/_layout.html.erb +15 -0
- data/lib/ecrire/template/views/static/customize/_post.html +3 -0
- data/lib/ecrire/template/views/static/customize.html +95 -0
- data/lib/ecrire/version.rb +3 -0
- data/lib/ecrire.rb +24 -0
- data/test/editor/controllers/admin/images_controller_test.rb +6 -0
- data/test/editor/controllers/admin/posts_controller_test.rb +90 -0
- data/test/editor/controllers/base_controller_test.rb +26 -0
- data/test/editor/controllers/images_controller_test.rb +2 -0
- data/test/editor/controllers/partials_controller_test.rb +2 -0
- data/test/editor/controllers/posts_controller_test.rb +21 -0
- data/test/editor/controllers/sessions_controller_test.rb +21 -0
- data/test/editor/helpers/base_helper_test.rb +19 -0
- data/test/editor/helpers/posts_helper_test.rb +3 -0
- data/test/editor/models/image_test.rb +33 -0
- data/test/editor/models/partial_test.rb +4 -0
- data/test/editor/models/post_test.rb +109 -0
- data/test/editor/models/user_test.rb +4 -0
- data/test/editor/test_helper.rb +28 -0
- data/test/fixtures/images.yml +11 -0
- data/test/fixtures/partials.yml +9 -0
- data/test/fixtures/posts.yml +16 -0
- data/test/fixtures/users.yml +9 -0
- data/test/initializations/railtie_test.rb +49 -0
- data/test/isolation.rb +16 -0
- data/test/themes/template/Gemfile +28 -0
- data/test/themes/template/assets/javascripts/blog.js.coffee +0 -0
- data/test/themes/template/assets/javascripts/post.js.coffee +0 -0
- data/test/themes/template/assets/stylesheets/blog.css.scss +0 -0
- data/test/themes/template/assets/stylesheets/post.css.scss +0 -0
- data/test/themes/template/config.ru +0 -0
- data/test/themes/template/views/layouts/application.html.erb +1 -0
- data/test/themes/template/views/posts/index.html.erb +0 -0
- metadata +275 -0
@@ -0,0 +1,108 @@
|
|
1
|
+
require 's3'
|
2
|
+
|
3
|
+
module Admin
|
4
|
+
class Image < ::Image
|
5
|
+
belongs_to :post, class_name: Admin::Post
|
6
|
+
before_save :update_file
|
7
|
+
|
8
|
+
attr_reader :s3
|
9
|
+
|
10
|
+
def s3
|
11
|
+
@s3 ||= S3.new(Rails.application.secrets.s3 || {})
|
12
|
+
end
|
13
|
+
|
14
|
+
def file=(file)
|
15
|
+
@file = s3.bucket.objects.build path(file)
|
16
|
+
@file.content = file
|
17
|
+
end
|
18
|
+
|
19
|
+
def clear!
|
20
|
+
return if self.url.nil?
|
21
|
+
|
22
|
+
s3.bucket.objects.find(key).destroy
|
23
|
+
self.url = nil
|
24
|
+
self.key = nil
|
25
|
+
save!
|
26
|
+
end
|
27
|
+
|
28
|
+
protected
|
29
|
+
|
30
|
+
def update_file
|
31
|
+
unless @file.nil?
|
32
|
+
begin
|
33
|
+
@file.save
|
34
|
+
self.url = @file.url
|
35
|
+
self.key = @file.key
|
36
|
+
rescue StandardError => e
|
37
|
+
errors.add :remote, e
|
38
|
+
return false
|
39
|
+
end
|
40
|
+
return true
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def remove_file
|
45
|
+
end
|
46
|
+
|
47
|
+
def path(file)
|
48
|
+
items = [post.id, file.original_filename]
|
49
|
+
|
50
|
+
items.prepend(s3.path) unless s3.path.blank?
|
51
|
+
|
52
|
+
items.join("/")
|
53
|
+
end
|
54
|
+
|
55
|
+
class S3
|
56
|
+
include ::S3
|
57
|
+
|
58
|
+
attr_reader :bucket, :access_key, :secret_key, :path, :errors
|
59
|
+
|
60
|
+
def initialize(options={})
|
61
|
+
@errors = ActiveModel::Errors.new(self)
|
62
|
+
@access_key = options.fetch('access_key', "")
|
63
|
+
@secret_key = options.fetch('secret_key', "")
|
64
|
+
@path = options.fetch('path', "")
|
65
|
+
|
66
|
+
@bucket = service.bucket(options.fetch('bucket', 'ecrire'))
|
67
|
+
end
|
68
|
+
|
69
|
+
def configuration_hash
|
70
|
+
config = {
|
71
|
+
'access_key' => access_key,
|
72
|
+
'secret_key' => secret_key,
|
73
|
+
'bucket' => bucket.name
|
74
|
+
}
|
75
|
+
|
76
|
+
unless path.blank?
|
77
|
+
config['path'] = path
|
78
|
+
end
|
79
|
+
|
80
|
+
config
|
81
|
+
end
|
82
|
+
|
83
|
+
def connect
|
84
|
+
begin
|
85
|
+
@bucket.retrieve
|
86
|
+
@connected = true
|
87
|
+
rescue Error::ResponseError, ArgumentError, SocketError => e
|
88
|
+
errors.add :remote, e
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
def service
|
93
|
+
@service ||= Service.new(access_key_id: access_key,
|
94
|
+
secret_access_key: secret_key,
|
95
|
+
use_ssl: true
|
96
|
+
)
|
97
|
+
end
|
98
|
+
|
99
|
+
def connected?
|
100
|
+
if @connected.nil?
|
101
|
+
connect
|
102
|
+
end
|
103
|
+
!!@connected
|
104
|
+
end
|
105
|
+
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'kramdown'
|
2
|
+
|
3
|
+
module Admin
|
4
|
+
class Post < ::Post
|
5
|
+
|
6
|
+
class Callbacks
|
7
|
+
def after_create(record)
|
8
|
+
Admin::Image.create(post: record)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
has_one :header, class_name: Admin::Image
|
13
|
+
before_save :compile!, prepend: true
|
14
|
+
before_save :excerptize!
|
15
|
+
after_create Callbacks.new
|
16
|
+
|
17
|
+
def publish!(params = {})
|
18
|
+
self.assign_attributes(params)
|
19
|
+
self.published_at = DateTime.now
|
20
|
+
self.save!
|
21
|
+
end
|
22
|
+
|
23
|
+
def unpublish!(params = {})
|
24
|
+
self.assign_attributes(params)
|
25
|
+
self.published_at = nil
|
26
|
+
self.save!
|
27
|
+
end
|
28
|
+
|
29
|
+
def stylesheet
|
30
|
+
super || ""
|
31
|
+
end
|
32
|
+
|
33
|
+
def javascript
|
34
|
+
super || ""
|
35
|
+
end
|
36
|
+
|
37
|
+
def content
|
38
|
+
read_attribute(:content) || ""
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def compile!
|
44
|
+
self.compiled_content = Kramdown::Document.new(self.content).to_html
|
45
|
+
end
|
46
|
+
|
47
|
+
def excerptize!
|
48
|
+
html = Nokogiri::HTML(self.compiled_content)
|
49
|
+
html.xpath("//img").each do |img|
|
50
|
+
img.remove
|
51
|
+
end
|
52
|
+
self.compiled_excerpt = html.xpath('//body').children[0..20].to_s
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
end
|
File without changes
|
@@ -0,0 +1,90 @@
|
|
1
|
+
require 'nokogiri'
|
2
|
+
|
3
|
+
class Post < ActiveRecord::Base
|
4
|
+
has_one :header, class_name: Image
|
5
|
+
|
6
|
+
store_accessor :properties, :labels
|
7
|
+
|
8
|
+
scope :status, lambda {|status|
|
9
|
+
if status.eql?("published")
|
10
|
+
where "posts.published_at IS NOT NULL"
|
11
|
+
else
|
12
|
+
where "posts.published_at IS NULL"
|
13
|
+
end
|
14
|
+
}
|
15
|
+
|
16
|
+
scope :published, lambda { status("published") }
|
17
|
+
scope :drafted, lambda { status("drafted") }
|
18
|
+
scope :slug, lambda { |slug| where("posts.slug is ?", slug) }
|
19
|
+
scope :without, lambda { |post| where("posts.id != ?", post.id) }
|
20
|
+
|
21
|
+
validates :title, presence: true, uniqueness: true
|
22
|
+
validates :slug, presence: true, uniqueness: true
|
23
|
+
|
24
|
+
before_validation :create_slug_if_nil
|
25
|
+
|
26
|
+
def status=(new_status)
|
27
|
+
if new_status.eql? "publish"
|
28
|
+
publish!
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def publish!
|
33
|
+
return unless published_at.nil?
|
34
|
+
self.published_at = DateTime.now
|
35
|
+
save!
|
36
|
+
end
|
37
|
+
|
38
|
+
def published?
|
39
|
+
!draft?
|
40
|
+
end
|
41
|
+
|
42
|
+
def draft?
|
43
|
+
published_at.nil?
|
44
|
+
end
|
45
|
+
|
46
|
+
def to_param
|
47
|
+
if self.instance_of?(Admin::Post)
|
48
|
+
id.to_s
|
49
|
+
else
|
50
|
+
slug
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def content
|
55
|
+
(self.compiled_content || super || '').html_safe
|
56
|
+
end
|
57
|
+
|
58
|
+
def excerpt
|
59
|
+
(self.compiled_excerpt || "").html_safe
|
60
|
+
end
|
61
|
+
|
62
|
+
|
63
|
+
def title=(new_title)
|
64
|
+
super
|
65
|
+
if self.draft?
|
66
|
+
self.slug = nil
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def header?
|
71
|
+
!self.header.nil? && !self.header.url.blank?
|
72
|
+
end
|
73
|
+
|
74
|
+
def labels
|
75
|
+
ids = super || ''
|
76
|
+
Label.where(id: ids.split(',')).to_a
|
77
|
+
end
|
78
|
+
|
79
|
+
def labels=(labels)
|
80
|
+
super(labels.map(&:id).join(','))
|
81
|
+
end
|
82
|
+
|
83
|
+
protected
|
84
|
+
|
85
|
+
def create_slug_if_nil
|
86
|
+
return unless self.slug.blank?
|
87
|
+
self.slug = self.title.parameterize
|
88
|
+
end
|
89
|
+
|
90
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Property
|
2
|
+
class Image
|
3
|
+
attr_accessor :post
|
4
|
+
|
5
|
+
def name
|
6
|
+
"image"
|
7
|
+
end
|
8
|
+
|
9
|
+
def create(params)
|
10
|
+
unless post.header.nil?
|
11
|
+
post.header.destroy
|
12
|
+
end
|
13
|
+
img = post.images.build
|
14
|
+
img.file = params[:admin_image][:file]
|
15
|
+
img.save
|
16
|
+
post.header = img
|
17
|
+
post.save
|
18
|
+
end
|
19
|
+
|
20
|
+
# TODO:
|
21
|
+
# 3. Remove id in post properties
|
22
|
+
def destroy(value)
|
23
|
+
return if post.header.nil?
|
24
|
+
img = post.header
|
25
|
+
img.destroy
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Property
|
2
|
+
class Label
|
3
|
+
attr_accessor :post
|
4
|
+
|
5
|
+
def name
|
6
|
+
"label"
|
7
|
+
end
|
8
|
+
|
9
|
+
def create(params)
|
10
|
+
new_label = ::Label.find_or_create_by!(name: params[:value])
|
11
|
+
labels = post.labels
|
12
|
+
labels << new_label
|
13
|
+
post.labels = labels
|
14
|
+
post.save!
|
15
|
+
new_label
|
16
|
+
end
|
17
|
+
|
18
|
+
def destroy(params)
|
19
|
+
label = ::Label.find_by!(name: params[:value])
|
20
|
+
labels = post.labels
|
21
|
+
labels.delete(label)
|
22
|
+
post.labels = labels
|
23
|
+
post.save!
|
24
|
+
label
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'bcrypt'
|
2
|
+
|
3
|
+
class User < ActiveRecord::Base
|
4
|
+
include BCrypt
|
5
|
+
|
6
|
+
attr_accessor :password_confirmation
|
7
|
+
|
8
|
+
validates_presence_of :email
|
9
|
+
|
10
|
+
validate do |record|
|
11
|
+
record.errors.add(:password, :blank) unless record.encrypted_password.present?
|
12
|
+
end
|
13
|
+
|
14
|
+
validates_confirmation_of :password, if: ->{ password.present? }
|
15
|
+
|
16
|
+
def password
|
17
|
+
return if self.encrypted_password.blank?
|
18
|
+
@password ||= Password.new(self.encrypted_password)
|
19
|
+
end
|
20
|
+
|
21
|
+
def password=(new_password)
|
22
|
+
if new_password.nil?
|
23
|
+
self.encrypted_password = nil
|
24
|
+
elsif new_password.present?
|
25
|
+
@password = Password.create(new_password)
|
26
|
+
self.encrypted_password = @password
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
|
31
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
class PasswordStrategy < Warden::Strategies::Base
|
2
|
+
def valid?
|
3
|
+
return false if request.get?
|
4
|
+
user_data = params.fetch("session", {})
|
5
|
+
user_data.has_key?("email") && user_data.has_key?("password")
|
6
|
+
end
|
7
|
+
|
8
|
+
def authenticate!
|
9
|
+
user = User.find_by_email(params["session"].fetch("email"))
|
10
|
+
if !user.nil? && user.password == params["session"].fetch("password")
|
11
|
+
success! user
|
12
|
+
else
|
13
|
+
env['warden'].errors.add :general, "Sorry, couldn't log you in."
|
14
|
+
fail!
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
<section class="configure">
|
2
|
+
<%= images_config_title %>
|
3
|
+
|
4
|
+
<%= form_for :s3 do |f| %>
|
5
|
+
|
6
|
+
<%= f.text_field :access_key, value: @s3.access_key, placeholder: "Access key" %>
|
7
|
+
<%= f.text_field :secret_key, value: @s3.secret_key, placeholder: "Secret key" %>
|
8
|
+
<%= f.text_field :bucket, value: @s3.bucket.name, placeholder: "Bucket name" %>
|
9
|
+
<%= f.text_field :path, value: @s3.path, placeholder: "Root path (Optional)" %>
|
10
|
+
|
11
|
+
<%= f.button "Connect & Save" %>
|
12
|
+
|
13
|
+
<% end %>
|
14
|
+
</section>
|
@@ -0,0 +1,14 @@
|
|
1
|
+
<div class='overlay' as='Overlay'>
|
2
|
+
<div class='popup errors' id='Failure'>
|
3
|
+
<header>
|
4
|
+
<h5>Oops, something wrong just happened</h5>
|
5
|
+
</header>
|
6
|
+
|
7
|
+
<ol class='errors'>
|
8
|
+
<% errors.each do |attr, message| %>
|
9
|
+
<%= content_tag :li, message.to_s.capitalize %>
|
10
|
+
<% end %>
|
11
|
+
</ol>
|
12
|
+
|
13
|
+
</div>
|
14
|
+
</div>
|
@@ -0,0 +1,15 @@
|
|
1
|
+
<%= form_for post.header, url: admin_post_image_path(post), as: :image, html: {class: %w(update)} do |f| %>
|
2
|
+
|
3
|
+
<div class='drop zone'>
|
4
|
+
</div>
|
5
|
+
|
6
|
+
<p>You can drop an image here to set a header image for this post.</p>
|
7
|
+
|
8
|
+
<%= f.file_field :file %>
|
9
|
+
|
10
|
+
<% end %>
|
11
|
+
|
12
|
+
<%= form_for post.header, url: admin_post_image_path(post), remote: true, method: :delete, html: {class: %w(clear)} do |f| %>
|
13
|
+
Do you want to remove this header? <%= f.button 'Remove' %>
|
14
|
+
<% end %>
|
15
|
+
|
File without changes
|
@@ -0,0 +1 @@
|
|
1
|
+
e.ErrorHTML = "<%= j render('errors', errors: @image.errors ) %>".toHTML()
|
@@ -0,0 +1 @@
|
|
1
|
+
e.headerURL = "<%= j @image.url %>"
|
@@ -0,0 +1,61 @@
|
|
1
|
+
<div class='overlay' as='Overlay'>
|
2
|
+
<div class='popup' id="Documentation">
|
3
|
+
<header>
|
4
|
+
<h5>Available syntax when writing your post</h5>
|
5
|
+
</header>
|
6
|
+
|
7
|
+
<section class='words'>
|
8
|
+
<h3>Headers</h3>
|
9
|
+
<div>
|
10
|
+
<h1># Header 1</h1>
|
11
|
+
<h2># Header 2</h2>
|
12
|
+
<h3># Header 3</h3>
|
13
|
+
<h4># Header 4</h4>
|
14
|
+
<h5># Header 5</h5>
|
15
|
+
</div>
|
16
|
+
</section>
|
17
|
+
|
18
|
+
<section class='words'>
|
19
|
+
<h3>Italic & bold</h3>
|
20
|
+
<p>You <em>*can*</em> use asterisks(*) to style <strong>**words**</strong>.</p>
|
21
|
+
|
22
|
+
</section>
|
23
|
+
|
24
|
+
<section class='code'>
|
25
|
+
<h3>Code block</h3>
|
26
|
+
<pre><code>~~~ language
|
27
|
+
[1,2,3].each do |i|
|
28
|
+
puts i
|
29
|
+
end
|
30
|
+
~~~</code></pre>
|
31
|
+
</section>
|
32
|
+
|
33
|
+
<section class='image'>
|
34
|
+
<h3>Images</h3>
|
35
|
+
<p>Images are block level in Ecrire. You can only add an image if it's at the start of a line.</p>
|
36
|
+
<p><strong>You can only use images if you have configured Ecrire to upload to your S3 bucket.</strong></p>
|
37
|
+
<picture>
|
38
|
+
<div style="background-image: url(https://www.google.com/images/srpr/logo11w.png);"></div>
|
39
|
+
<em name="An image">![An image](https://www.google.com/images/srpr/logo11w.png)</em>
|
40
|
+
</picture>
|
41
|
+
</section>
|
42
|
+
|
43
|
+
<section class='list'>
|
44
|
+
<h3>Ordered list</h3>
|
45
|
+
<ol>
|
46
|
+
<li>1. First</li>
|
47
|
+
<li>1. Second</li>
|
48
|
+
<li>1. Third</li>
|
49
|
+
</ol>
|
50
|
+
|
51
|
+
<h3>Unordered list</h3>
|
52
|
+
<ul>
|
53
|
+
<li>- First</li>
|
54
|
+
<li>- Second</li>
|
55
|
+
<li>- Third</li>
|
56
|
+
</ul>
|
57
|
+
</section>
|
58
|
+
</div>
|
59
|
+
</div>
|
60
|
+
|
61
|
+
|
@@ -0,0 +1,18 @@
|
|
1
|
+
<div class='overlay' as='Overlay'>
|
2
|
+
<div class='popup' id='PostsListPopup'>
|
3
|
+
<header>
|
4
|
+
<%= content_tag :h5, params[:type].capitalize %>
|
5
|
+
</header>
|
6
|
+
<% if posts.any? %>
|
7
|
+
<ol>
|
8
|
+
<%= render posts %>
|
9
|
+
</ol>
|
10
|
+
<% else %>
|
11
|
+
<div class='empty'>
|
12
|
+
<p>You don't have any <%= params[:type] %> post.</p>
|
13
|
+
|
14
|
+
<p><%= link_to 'Do you want to create a new post?', new_title_admin_posts_path, class: %w(new button) %></p>
|
15
|
+
</div>
|
16
|
+
<% end %>
|
17
|
+
</div>
|
18
|
+
</div>
|
@@ -0,0 +1,73 @@
|
|
1
|
+
<header>
|
2
|
+
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" class='toggle', as='Navigation.Toggle' x="0px" y="0px" viewBox="0 0 20 20" enable-background="new 0 0 20 20" xml:space="preserve">
|
3
|
+
<path d="M4.516,7.548c0.436-0.446,1.043-0.481,1.576,0L10,11.295l3.908-3.747c0.533-0.481,1.141-0.446,1.574,0 c0.436,0.445,0.408,1.197,0,1.615c-0.406,0.418-4.695,4.502-4.695,4.502C10.57,13.888,10.285,14,10,14s-0.57-0.112-0.789-0.335 c0,0-4.287-4.084-4.695-4.502C4.107,8.745,4.08,7.993,4.516,7.548z"/>
|
4
|
+
</svg>
|
5
|
+
|
6
|
+
<%= form_for @post,
|
7
|
+
as: 'post',
|
8
|
+
remote: true,
|
9
|
+
html: {as: 'Posts.Title', class: %w(post title settings autosave)} do |f| %>
|
10
|
+
<%= hidden_field_tag :context, :title %>
|
11
|
+
|
12
|
+
<%= f.text_field :title, class: %w(title), autocomplete: :off %>
|
13
|
+
<% end %>
|
14
|
+
</header>
|
15
|
+
|
16
|
+
<section as='Post.Documentation'>
|
17
|
+
|
18
|
+
<%= content_tag :div, class: %w(publish state), href: admin_post_path(@post.id), as: 'Post.Sticky' do %>
|
19
|
+
|
20
|
+
<% if @post.published? %>
|
21
|
+
|
22
|
+
<%= form_for @post, method: :put, html: { class: %w(hide button destroy) } do |f| %>
|
23
|
+
<%= f.button 'Retract', value: 'unpublish'%>
|
24
|
+
<% end %>
|
25
|
+
|
26
|
+
<% else %>
|
27
|
+
|
28
|
+
<%= form_for @post, method: :put, html: { id: 'PublishPost', class: %w(button publish) } do |f| %>
|
29
|
+
<%= f.button 'Publish', value: 'publish'%>
|
30
|
+
<% end %>
|
31
|
+
|
32
|
+
<%= form_for @post, method: :delete, html: { id: 'DeletePost', class: %w(destroy button), as: 'Post.Delete' } do |f| %>
|
33
|
+
<%= f.button disabled: true do %>
|
34
|
+
<%= check_box_tag 'delete' %>
|
35
|
+
Delete this post
|
36
|
+
<% end %>
|
37
|
+
<% end %>
|
38
|
+
|
39
|
+
<% end %>
|
40
|
+
|
41
|
+
<% end %>
|
42
|
+
|
43
|
+
<article>
|
44
|
+
<%= content_tag :header, as: "Post.Header" do |header| %>
|
45
|
+
<% if @post.header? %>
|
46
|
+
<% header[:style] = "background-image: url(#{@post.header.url});" %>
|
47
|
+
<% end %>
|
48
|
+
|
49
|
+
<%= render 'admin/images/form', post: @post %>
|
50
|
+
<% end %>
|
51
|
+
|
52
|
+
<%= post_edit_content(@post) %>
|
53
|
+
</article>
|
54
|
+
|
55
|
+
<div class='save' as='Post.Sticky'>
|
56
|
+
<%= form_for @post, method: :put, remote: true, html: {as: 'Editor.Save', class: %w(save button)} do |f| %>
|
57
|
+
<%= f.button '', dirty: 'Update', persisted: 'Up to date', disabled: true %>
|
58
|
+
<%= content_tag :div, class: %w(update) do %>
|
59
|
+
Last updated
|
60
|
+
<%= content_tag :p, nil, time: @post.updated_at.iso8601 %>
|
61
|
+
<% end %>
|
62
|
+
<% end %>
|
63
|
+
|
64
|
+
<%= link_to 'Syntax', help_admin_posts_path, remote: true, class: %w(help) %>
|
65
|
+
|
66
|
+
<% unless Rails.application.secrets.has_key?(:s3) %>
|
67
|
+
<div class='s3 configuration missing'>
|
68
|
+
<%= link_to 'Configure S3 to upload images.', admin_configurations_images_path %>
|
69
|
+
</div>
|
70
|
+
<% end %>
|
71
|
+
</div>
|
72
|
+
|
73
|
+
</section>
|
@@ -0,0 +1 @@
|
|
1
|
+
e.HTML = "<%= j render('documentation') %>".toHTML()
|
@@ -0,0 +1 @@
|
|
1
|
+
e.HTML = "<%= j render('list', posts: @posts) %>".toHTML()
|
@@ -0,0 +1,10 @@
|
|
1
|
+
<%= form_for Admin::Post.new, as: 'post', html: { class: %w(post new title), as: 'Posts.New' } do |f| %>
|
2
|
+
|
3
|
+
<fieldset class="transparent">
|
4
|
+
<%= f.text_field :title, placeholder: t('admin.posts.new.title') %>
|
5
|
+
</fieldset>
|
6
|
+
<%= content_tag :p, t('admin.posts.new.editable'), class: %w(transparent) %>
|
7
|
+
|
8
|
+
<%= f.button :submit, class: %w(hidden) %>
|
9
|
+
|
10
|
+
<% end %>
|
@@ -0,0 +1 @@
|
|
1
|
+
e.UpdatedAtTime = "<%= j @post.updated_at.iso8601 %>"
|
@@ -0,0 +1 @@
|
|
1
|
+
e.HTML = "<%= j @post.title%>"
|
@@ -0,0 +1,14 @@
|
|
1
|
+
$header = $('aside.preview header')
|
2
|
+
$old_form = $header.find('form.image.header')
|
3
|
+
$form = $('<%= j render('admin/images/header', post: post) %>')
|
4
|
+
$old_form.replaceWith($form)
|
5
|
+
$image = $('aside.preview > div.image')
|
6
|
+
|
7
|
+
if ($image.length) {
|
8
|
+
$image.attr('style', "background-image: url('<%= post.header.url %>')")
|
9
|
+
}
|
10
|
+
else {
|
11
|
+
$('aside.preview').prepend("<%= j editor_image_tag(post) %>")
|
12
|
+
}
|
13
|
+
|
14
|
+
$header.find('p.handler').click()
|