mini_blog 0.1.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.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +34 -0
- data/Rakefile +36 -0
- data/app/assets/config/mini_blog_manifest.js +2 -0
- data/app/assets/javascripts/mini_blog/application.js +27 -0
- data/app/assets/stylesheets/mini_blog/application.scss +30 -0
- data/app/controllers/mini_blog/application_controller.rb +5 -0
- data/app/controllers/mini_blog/articles_controller.rb +56 -0
- data/app/controllers/mini_blog/users/confirmations_controller.rb +34 -0
- data/app/controllers/mini_blog/users/omniauth_callbacks_controller.rb +34 -0
- data/app/controllers/mini_blog/users/passwords_controller.rb +39 -0
- data/app/controllers/mini_blog/users/registrations_controller.rb +66 -0
- data/app/controllers/mini_blog/users/sessions_controller.rb +32 -0
- data/app/controllers/mini_blog/users/unlocks_controller.rb +34 -0
- data/app/helpers/mini_blog/application_helper.rb +4 -0
- data/app/jobs/mini_blog/application_job.rb +4 -0
- data/app/mailers/mini_blog/application_mailer.rb +6 -0
- data/app/models/mini_blog/application_record.rb +5 -0
- data/app/models/mini_blog/article.rb +10 -0
- data/app/models/mini_blog/article_tag_relation.rb +9 -0
- data/app/models/mini_blog/image.rb +6 -0
- data/app/models/mini_blog/tag.rb +8 -0
- data/app/models/mini_blog/user.rb +10 -0
- data/app/uploaders/mini_blog/image_content_uploader.rb +49 -0
- data/app/views/kaminari/bootstrap4/_first_page.html.slim +2 -0
- data/app/views/kaminari/bootstrap4/_gap.html.slim +2 -0
- data/app/views/kaminari/bootstrap4/_last_page.html.slim +2 -0
- data/app/views/kaminari/bootstrap4/_next_page.html.slim +2 -0
- data/app/views/kaminari/bootstrap4/_page.html.slim +6 -0
- data/app/views/kaminari/bootstrap4/_paginator.html.slim +12 -0
- data/app/views/kaminari/bootstrap4/_prev_page.html.slim +2 -0
- data/app/views/layouts/mini_blog/application.html.slim +28 -0
- data/app/views/mini_blog/articles/_form.html.slim +9 -0
- data/app/views/mini_blog/articles/edit.html.slim +1 -0
- data/app/views/mini_blog/articles/index.html.slim +14 -0
- data/app/views/mini_blog/articles/new.html.slim +1 -0
- data/app/views/mini_blog/articles/show.json.ruby +3 -0
- data/app/views/mini_blog/users/confirmations/new.html.erb +16 -0
- data/app/views/mini_blog/users/mailer/confirmation_instructions.html.erb +5 -0
- data/app/views/mini_blog/users/mailer/email_changed.html.erb +7 -0
- data/app/views/mini_blog/users/mailer/password_change.html.erb +3 -0
- data/app/views/mini_blog/users/mailer/reset_password_instructions.html.erb +8 -0
- data/app/views/mini_blog/users/mailer/unlock_instructions.html.erb +7 -0
- data/app/views/mini_blog/users/passwords/edit.html.slim +22 -0
- data/app/views/mini_blog/users/passwords/new.html.slim +10 -0
- data/app/views/mini_blog/users/registrations/edit.html.erb +43 -0
- data/app/views/mini_blog/users/registrations/new.html.erb +29 -0
- data/app/views/mini_blog/users/sessions/new.html.slim +17 -0
- data/app/views/mini_blog/users/shared/_links.html.erb +25 -0
- data/app/views/mini_blog/users/unlocks/new.html.erb +16 -0
- data/config/initializers/devise.rb +279 -0
- data/config/locales/devise.en.yml +64 -0
- data/config/routes.rb +7 -0
- data/db/migrate/20180224022923_create_mini_blog_articles.rb +12 -0
- data/db/migrate/20180224025140_create_mini_blog_images.rb +9 -0
- data/db/migrate/20180224090210_devise_create_mini_blog_users.rb +45 -0
- data/db/migrate/20180224112101_create_mini_blog_tags.rb +9 -0
- data/db/migrate/20180224113006_create_mini_blog_article_tag_relations.rb +12 -0
- data/lib/mini_blog.rb +11 -0
- data/lib/mini_blog/engine.rb +5 -0
- data/lib/mini_blog/version.rb +3 -0
- data/lib/tasks/mini_blog_tasks.rake +4 -0
- metadata +260 -0
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module MiniBlog
|
4
|
+
module Users
|
5
|
+
class UnlocksController < Devise::UnlocksController
|
6
|
+
# GET /resource/unlock/new
|
7
|
+
# def new
|
8
|
+
# super
|
9
|
+
# end
|
10
|
+
|
11
|
+
# POST /resource/unlock
|
12
|
+
# def create
|
13
|
+
# super
|
14
|
+
# end
|
15
|
+
|
16
|
+
# GET /resource/unlock?unlock_token=abcdef
|
17
|
+
# def show
|
18
|
+
# super
|
19
|
+
# end
|
20
|
+
|
21
|
+
# protected
|
22
|
+
|
23
|
+
# The path used after sending unlock password instructions
|
24
|
+
# def after_sending_unlock_instructions_path_for(resource)
|
25
|
+
# super(resource)
|
26
|
+
# end
|
27
|
+
|
28
|
+
# The path used after unlocking the resource
|
29
|
+
# def after_unlock_path_for(resource)
|
30
|
+
# super(resource)
|
31
|
+
# end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
module MiniBlog
|
2
|
+
class Article < ApplicationRecord
|
3
|
+
has_many :article_tag_relations, dependent: :destroy
|
4
|
+
has_many :tags, through: :article_tag_relations
|
5
|
+
|
6
|
+
validates :title, presence: true
|
7
|
+
validates :body, presence: true
|
8
|
+
validates :status, presence: true
|
9
|
+
end
|
10
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
module MiniBlog
|
2
|
+
class User < ApplicationRecord
|
3
|
+
# Include default devise modules. Others available are:
|
4
|
+
# :confirmable, :lockable, :timeoutable and :omniauthable
|
5
|
+
devise :database_authenticatable, :recoverable,
|
6
|
+
:rememberable, :trackable, :validatable
|
7
|
+
|
8
|
+
validates :name, presence: true
|
9
|
+
end
|
10
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module MiniBlog
|
2
|
+
class ImageContentUploader < CarrierWave::Uploader::Base
|
3
|
+
# Include RMagick or MiniMagick support:
|
4
|
+
# include CarrierWave::RMagick
|
5
|
+
# include CarrierWave::MiniMagick
|
6
|
+
|
7
|
+
# Choose what kind of storage to use for this uploader:
|
8
|
+
storage :file
|
9
|
+
# storage :fog
|
10
|
+
|
11
|
+
# Override the directory where uploaded files will be stored.
|
12
|
+
# This is a sensible default for uploaders that are meant to be mounted:
|
13
|
+
def store_dir
|
14
|
+
"uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
|
15
|
+
end
|
16
|
+
|
17
|
+
# Provide a default URL as a default if there hasn't been a file uploaded:
|
18
|
+
# def default_url(*args)
|
19
|
+
# # For Rails 3.1+ asset pipeline compatibility:
|
20
|
+
# # ActionController::Base.helpers.asset_path("fallback/" + [version_name, "default.png"].compact.join('_'))
|
21
|
+
#
|
22
|
+
# "/images/fallback/" + [version_name, "default.png"].compact.join('_')
|
23
|
+
# end
|
24
|
+
|
25
|
+
# Process files as they are uploaded:
|
26
|
+
# process scale: [200, 300]
|
27
|
+
#
|
28
|
+
# def scale(width, height)
|
29
|
+
# # do something
|
30
|
+
# end
|
31
|
+
|
32
|
+
# Create different versions of your uploaded files:
|
33
|
+
# version :thumb do
|
34
|
+
# process resize_to_fit: [50, 50]
|
35
|
+
# end
|
36
|
+
|
37
|
+
# Add a white list of extensions which are allowed to be uploaded.
|
38
|
+
# For images you might use something like this:
|
39
|
+
# def extension_whitelist
|
40
|
+
# %w(jpg jpeg gif png)
|
41
|
+
# end
|
42
|
+
|
43
|
+
# Override the filename of the uploaded files:
|
44
|
+
# Avoid using model.id or version_name here, see uploader/store.rb for details.
|
45
|
+
# def filename
|
46
|
+
# "something.jpg" if original_filename
|
47
|
+
# end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,6 @@
|
|
1
|
+
- if page.current?
|
2
|
+
li.page-item.active
|
3
|
+
= content_tag :a, page, remote: remote, rel: (page.next? ? 'next' : (page.prev? ? 'prev' : nil)), class: 'page-link'
|
4
|
+
- else
|
5
|
+
li.page-item
|
6
|
+
= link_to page, url, remote: remote, rel: (page.next? ? 'next' : (page.prev? ? 'prev' : nil)), class: 'page-link'
|
@@ -0,0 +1,12 @@
|
|
1
|
+
= paginator.render do
|
2
|
+
nav
|
3
|
+
ul.pagination
|
4
|
+
== first_page_tag unless current_page.first?
|
5
|
+
== prev_page_tag unless current_page.first?
|
6
|
+
- each_page do |page|
|
7
|
+
- if page.left_outer? || page.right_outer? || page.inside_window?
|
8
|
+
== page_tag page
|
9
|
+
- elsif !page.was_truncated?
|
10
|
+
== gap_tag
|
11
|
+
== next_page_tag unless current_page.last?
|
12
|
+
== last_page_tag unless current_page.last?
|
@@ -0,0 +1,28 @@
|
|
1
|
+
doctype html
|
2
|
+
html
|
3
|
+
head
|
4
|
+
title
|
5
|
+
| Mini blog
|
6
|
+
meta name="viewport" content="width=device-width,initial-scale=1"
|
7
|
+
= stylesheet_link_tag 'mini_blog/application', media: 'all'
|
8
|
+
= javascript_include_tag 'mini_blog/application'
|
9
|
+
= csrf_meta_tags
|
10
|
+
body
|
11
|
+
header
|
12
|
+
nav.navbar.navbar-expand-lg.navbar-light.bg-light
|
13
|
+
.container
|
14
|
+
button.navbar-toggler data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation"
|
15
|
+
span.navbar-toggler-icon
|
16
|
+
= link_to 'MiniBlog', root_path, class: 'navbar-brand'
|
17
|
+
#navbarSupportedContent.collapse.navbar-collapse
|
18
|
+
ul.navbar-nav.mr-auto
|
19
|
+
- if user_signed_in?
|
20
|
+
li.nav-item
|
21
|
+
= link_to 'Sign out', destroy_user_session_path, class: 'nav-link', method: :delete
|
22
|
+
li.nav-item
|
23
|
+
= link_to 'New Article', new_article_path, class: 'nav-link'
|
24
|
+
- else
|
25
|
+
li.nav-item
|
26
|
+
= link_to 'Sign in', new_user_session_path, class: 'nav-link'
|
27
|
+
.container.main-contents
|
28
|
+
= yield
|
@@ -0,0 +1,9 @@
|
|
1
|
+
= form_with model: article, local: true do |f|
|
2
|
+
.form-group
|
3
|
+
= f.text_field :title, class: 'form-control', placeholder: 'Title'
|
4
|
+
.form-group
|
5
|
+
= f.text_area :body, class: 'form-control form-control-lg', placeholder: 'Body'
|
6
|
+
.form-group
|
7
|
+
= text_field :article, :tags, value: article.tags.pluck(:name).join('; '), class: 'form-control', placeholder: 'Tag'
|
8
|
+
button.btn.btn-info type="submit"
|
9
|
+
| send
|
@@ -0,0 +1 @@
|
|
1
|
+
= render 'form', article: @article
|
@@ -0,0 +1,14 @@
|
|
1
|
+
ul
|
2
|
+
- @articles.each do |article|
|
3
|
+
li.card
|
4
|
+
.card-header
|
5
|
+
h2
|
6
|
+
= "#{l(article.created_at)} #{article.title}"
|
7
|
+
ul
|
8
|
+
- article.tags.each do |tag|
|
9
|
+
li.badge.badge-dark.tag
|
10
|
+
= tag.name
|
11
|
+
article.article.card-body.collapse*{id: "article-#{article.id}", 'data-id': article.id}
|
12
|
+
button.btn.btn-link.btn-sm.text-left data-toggle="collapse" href="#article-#{article.id}" role="button" aria-expanded="false" aria-controls="article-#{article.id}"
|
13
|
+
| open...
|
14
|
+
= paginate @articles, theme: :bootstrap4
|
@@ -0,0 +1 @@
|
|
1
|
+
= render 'form', article: @article
|
@@ -0,0 +1,16 @@
|
|
1
|
+
<h2>Resend confirmation instructions</h2>
|
2
|
+
|
3
|
+
<%= form_for(resource, as: resource_name, url: confirmation_path(resource_name), html: { method: :post }) do |f| %>
|
4
|
+
<%= devise_error_messages! %>
|
5
|
+
|
6
|
+
<div class="field">
|
7
|
+
<%= f.label :email %><br />
|
8
|
+
<%= f.email_field :email, autofocus: true, autocomplete: "email", value: (resource.pending_reconfirmation? ? resource.unconfirmed_email : resource.email) %>
|
9
|
+
</div>
|
10
|
+
|
11
|
+
<div class="actions">
|
12
|
+
<%= f.submit "Resend confirmation instructions" %>
|
13
|
+
</div>
|
14
|
+
<% end %>
|
15
|
+
|
16
|
+
<%= render "mini_blog/users/shared/links" %>
|
@@ -0,0 +1,7 @@
|
|
1
|
+
<p>Hello <%= @email %>!</p>
|
2
|
+
|
3
|
+
<% if @resource.try(:unconfirmed_email?) %>
|
4
|
+
<p>We're contacting you to notify you that your email is being changed to <%= @resource.unconfirmed_email %>.</p>
|
5
|
+
<% else %>
|
6
|
+
<p>We're contacting you to notify you that your email has been changed to <%= @resource.email %>.</p>
|
7
|
+
<% end %>
|
@@ -0,0 +1,8 @@
|
|
1
|
+
<p>Hello <%= @resource.email %>!</p>
|
2
|
+
|
3
|
+
<p>Someone has requested a link to change your password. You can do this through the link below.</p>
|
4
|
+
|
5
|
+
<p><%= link_to 'Change my password', edit_password_url(@resource, reset_password_token: @token) %></p>
|
6
|
+
|
7
|
+
<p>If you didn't request this, please ignore this email.</p>
|
8
|
+
<p>Your password won't change until you access the link above and create a new one.</p>
|
@@ -0,0 +1,7 @@
|
|
1
|
+
<p>Hello <%= @resource.email %>!</p>
|
2
|
+
|
3
|
+
<p>Your account has been locked due to an excessive number of unsuccessful sign in attempts.</p>
|
4
|
+
|
5
|
+
<p>Click the link below to unlock your account:</p>
|
6
|
+
|
7
|
+
<p><%= link_to 'Unlock my account', unlock_url(@resource, unlock_token: @token) %></p>
|
@@ -0,0 +1,22 @@
|
|
1
|
+
h2
|
2
|
+
| Change your password
|
3
|
+
= form_with model: resource, url: user_password_path, html: {method: :put}, local: true do |f|
|
4
|
+
= devise_error_messages!
|
5
|
+
= f.hidden_field :reset_password_token
|
6
|
+
.form-group
|
7
|
+
= f.label :password, 'New password'
|
8
|
+
br
|
9
|
+
- if @minimum_password_length
|
10
|
+
em
|
11
|
+
| (
|
12
|
+
= @minimum_password_length
|
13
|
+
| characters minimum)
|
14
|
+
br
|
15
|
+
= f.password_field :password, autofocus: true, autocomplete: 'off', class: 'form-controller'
|
16
|
+
.field
|
17
|
+
= f.label :password_confirmation, 'Confirm new password'
|
18
|
+
br
|
19
|
+
= f.password_field :password_confirmation, autocomplete: 'off'
|
20
|
+
button.btn.btn-outline-success
|
21
|
+
| Send me reset password instructions
|
22
|
+
= render 'mini_blog/users/shared/links'
|
@@ -0,0 +1,10 @@
|
|
1
|
+
h2
|
2
|
+
| Forgot your password?
|
3
|
+
= form_with model: resource, url: user_password_path, local: true do |f|
|
4
|
+
= devise_error_messages!
|
5
|
+
.form-group
|
6
|
+
= f.label :email
|
7
|
+
= f.email_field :email, autofocus: true, autocomplete: 'email', class: 'form-control'
|
8
|
+
button.btn.btn-outline-success
|
9
|
+
| Send me reset password instructions
|
10
|
+
= render 'mini_blog/users/shared/links'
|
@@ -0,0 +1,43 @@
|
|
1
|
+
<h2>Edit <%= resource_name.to_s.humanize %></h2>
|
2
|
+
|
3
|
+
<%= form_for(resource, as: resource_name, url: registration_path(resource_name), html: { method: :put }) do |f| %>
|
4
|
+
<%= devise_error_messages! %>
|
5
|
+
|
6
|
+
<div class="field">
|
7
|
+
<%= f.label :email %><br />
|
8
|
+
<%= f.email_field :email, autofocus: true, autocomplete: "email" %>
|
9
|
+
</div>
|
10
|
+
|
11
|
+
<% if devise_mapping.confirmable? && resource.pending_reconfirmation? %>
|
12
|
+
<div>Currently waiting confirmation for: <%= resource.unconfirmed_email %></div>
|
13
|
+
<% end %>
|
14
|
+
|
15
|
+
<div class="field">
|
16
|
+
<%= f.label :password %> <i>(leave blank if you don't want to change it)</i><br />
|
17
|
+
<%= f.password_field :password, autocomplete: "off" %>
|
18
|
+
<% if @minimum_password_length %>
|
19
|
+
<br />
|
20
|
+
<em><%= @minimum_password_length %> characters minimum</em>
|
21
|
+
<% end %>
|
22
|
+
</div>
|
23
|
+
|
24
|
+
<div class="field">
|
25
|
+
<%= f.label :password_confirmation %><br />
|
26
|
+
<%= f.password_field :password_confirmation, autocomplete: "off" %>
|
27
|
+
</div>
|
28
|
+
|
29
|
+
<div class="field">
|
30
|
+
<%= f.label :current_password %> <i>(we need your current password to confirm your changes)</i><br />
|
31
|
+
<%= f.password_field :current_password, autocomplete: "off" %>
|
32
|
+
</div>
|
33
|
+
|
34
|
+
<div class="actions">
|
35
|
+
<%= f.submit "Update" %>
|
36
|
+
</div>
|
37
|
+
<% end %>
|
38
|
+
|
39
|
+
<h3>Cancel my account</h3>
|
40
|
+
|
41
|
+
<p>Unhappy? <%= button_to "Cancel my account", registration_path(resource_name), data: { confirm: "Are you sure?" }, method: :delete %></p>
|
42
|
+
|
43
|
+
<%= link_to "Back", :back %>
|
@@ -0,0 +1,29 @@
|
|
1
|
+
<h2>Sign up</h2>
|
2
|
+
|
3
|
+
<%= form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %>
|
4
|
+
<%= devise_error_messages! %>
|
5
|
+
|
6
|
+
<div class="field">
|
7
|
+
<%= f.label :email %><br />
|
8
|
+
<%= f.email_field :email, autofocus: true, autocomplete: "email" %>
|
9
|
+
</div>
|
10
|
+
|
11
|
+
<div class="field">
|
12
|
+
<%= f.label :password %>
|
13
|
+
<% if @minimum_password_length %>
|
14
|
+
<em>(<%= @minimum_password_length %> characters minimum)</em>
|
15
|
+
<% end %><br />
|
16
|
+
<%= f.password_field :password, autocomplete: "off" %>
|
17
|
+
</div>
|
18
|
+
|
19
|
+
<div class="field">
|
20
|
+
<%= f.label :password_confirmation %><br />
|
21
|
+
<%= f.password_field :password_confirmation, autocomplete: "off" %>
|
22
|
+
</div>
|
23
|
+
|
24
|
+
<div class="actions">
|
25
|
+
<%= f.submit "Sign up" %>
|
26
|
+
</div>
|
27
|
+
<% end %>
|
28
|
+
|
29
|
+
<%= render "mini_blog/users/shared/links" %>
|