jekyll-mail-comments 0.0.2
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/.env.dist +5 -0
- data/.gitignore +13 -0
- data/Gemfile +5 -0
- data/README.md +70 -0
- data/bin/jekyll-mail-comments-fetch +4 -0
- data/jekyll-mail-comments.gemspec +21 -0
- data/lib/jekyll-mail-comments.rb +103 -0
- data/lib/jekyll_mail_comments.rb +100 -0
- data/templates/comments-count.html +7 -0
- data/templates/comments.html +30 -0
- metadata +73 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 4ebed81f1e8338d62ed7b4260a85053cebba168a7ad734785ba90ba4e2358a4f
|
4
|
+
data.tar.gz: 8a06546dd5307ca7c0142fd9dcca55542510c419edd62d93fb8898a12fb9b65e
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: b1261991ca3b7f61b1b9f2f81a7ad5517f7ba50d2cb4801cc57c4b9a40412e569e15e80c3d803df7952750ed498652b4ba3c3051b78eb335dbf24356f6b08c12
|
7
|
+
data.tar.gz: 5291b56543dc5b8fb8fe97275a942c40500327380d3d877bb6d2fff112845097b9694c19687d8ceed8631c07e8795b685475bcd7a50ee48c5be6144dc39d86ec
|
data/.env.dist
ADDED
data/.gitignore
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
# Jekyll Mail comments
|
2
|
+
|
3
|
+
This gem fetches email from your mailbox by filtering with specific suffix, it makes data files which you can use to generate Jekyll comments.
|
4
|
+
|
5
|
+
## How it works ?
|
6
|
+
|
7
|
+
* You've to setup mailbox, on Jekyll pages you will have mailto link which opens native system mail client with pre filled subject.
|
8
|
+
* Person who wants to comment message write message to your specific email address.
|
9
|
+
* Fetch program watch for special subject suffix to distinct comments from other emails
|
10
|
+
* Fetch program generate json based data files which perfectly fits to Jekyll data system https://jekyllrb.com/docs/datafiles/
|
11
|
+
|
12
|
+
|
13
|
+
## What is the purpose ?
|
14
|
+
|
15
|
+
* Jekyll static site generator has no comments system
|
16
|
+
* Don't want to inject 3rdparty javascript code to work with SaSS comments system
|
17
|
+
* Any RDBS for static site generator is overhead
|
18
|
+
|
19
|
+
|
20
|
+
## How-to Setup
|
21
|
+
|
22
|
+
* Go to your jekyll site `cd ~/jekull_site`
|
23
|
+
* Install gem `gem install mail_comments`
|
24
|
+
* Setup credentials
|
25
|
+
|
26
|
+
There few credentials your have to setup before run:
|
27
|
+
|
28
|
+
** MC_LOGIN - Login to imap server
|
29
|
+
** MC_PASSWORD - Password for imap server
|
30
|
+
** MC_HOST - IMAP server hostname
|
31
|
+
** MC_PORT - IMAP server port
|
32
|
+
** MC_SUBJECT_SUFFIX - Suffix to filter comments
|
33
|
+
|
34
|
+
* You have put this as environment variables `see .env.dist`
|
35
|
+
* `jekyll-mail-comments-fetch`
|
36
|
+
* After that you will get comments data files inside Jekyll data directory - **_data**
|
37
|
+
|
38
|
+
After that if new comments are present it will generate data files with comments which you can process with Jekyll with data tag.
|
39
|
+
See here. https://jekyllrb.com/docs/datafiles/ or below.
|
40
|
+
|
41
|
+
Here is how to you can include comments block into your Jekyll post template
|
42
|
+
|
43
|
+
```
|
44
|
+
|
45
|
+
<section>
|
46
|
+
{% include comments-count.html replies_to=page.path %}
|
47
|
+
|
48
|
+
{% if comment_count %}
|
49
|
+
<h2>Comments ({{- comment_count -}}) <small class="text-muted">Read carefuly </small> </h2>
|
50
|
+
{% include comments.html replies_to=page.path indent_class="ml-auto" title=page.title %}
|
51
|
+
{% else %}
|
52
|
+
<h2>No comments here yet <small class="text-muted">Write here gently</small></h2>
|
53
|
+
{% endif %}
|
54
|
+
<div class="mt-3"><a class="btn btn-outline-secondary btn-block" href="mailto:{{site.comments.email}}?subject=RE:{{page.path}}:{{site.comments.subject_suffix}}:{{post.title}}">Write a comment</a> </div>
|
55
|
+
</section>
|
56
|
+
```
|
57
|
+
Templates can be found inside **templates** directory of this gem.
|
58
|
+
|
59
|
+
|
60
|
+
## Credits
|
61
|
+
|
62
|
+
Inspiration while searching for already existing gem for email comments
|
63
|
+
|
64
|
+
* https://stevescott.ca/2017-04-03-static-site-comments-via-email.html
|
65
|
+
* https://github.com/aioobe/dead-simple-jekyll-comments/
|
66
|
+
|
67
|
+
|
68
|
+
## Example
|
69
|
+
|
70
|
+
* https://blog.falsetrue.io
|
@@ -0,0 +1,21 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = 'jekyll-mail-comments'
|
3
|
+
s.version = '0.0.2'
|
4
|
+
s.date = '2022-01-01'
|
5
|
+
s.summary = "Email based comment system for Jekyll static site generator"
|
6
|
+
s.description = <<DESC
|
7
|
+
Provides html generator of threaded comments pages fetched from an IMAP for Jekyll
|
8
|
+
DESC
|
9
|
+
s.authors = "Dmitry Rodichev"
|
10
|
+
s.email = 'noroot@falsetrue.io'
|
11
|
+
s.files = `git ls-files`.split($/)
|
12
|
+
s.executables = s.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
13
|
+
s.test_files = s.files.grep(%r{^(test|spec|features)/})
|
14
|
+
|
15
|
+
s.add_dependency 'jekyll'
|
16
|
+
s.homepage = 'https://github.com/noroot/jekyll-mail-comments'
|
17
|
+
s.license = 'GPL-3.0'
|
18
|
+
s.post_install_message = <<MSG
|
19
|
+
Don't forget to put credentials inside .env file, see .env.dist inside gem source.
|
20
|
+
MSG
|
21
|
+
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
require 'net/imap'
|
2
|
+
require 'mail'
|
3
|
+
require 'fileutils'
|
4
|
+
require "base64"
|
5
|
+
require 'yaml'
|
6
|
+
require 'digest'
|
7
|
+
require 'jekyll'
|
8
|
+
|
9
|
+
module Jekyll
|
10
|
+
|
11
|
+
module MailComments
|
12
|
+
|
13
|
+
class Configuration
|
14
|
+
attr_accessor :login
|
15
|
+
attr_accessor :password
|
16
|
+
attr_accessor :host
|
17
|
+
attr_accessor :port
|
18
|
+
attr_accessor :subject_suffix
|
19
|
+
|
20
|
+
def initialize
|
21
|
+
@login = ENV.fetch('MC_LOGIN', '')
|
22
|
+
@password = ENV.fetch('MC_PASSWORD', '')
|
23
|
+
@host = ENV.fetch('MC_HOST', '')
|
24
|
+
@port = ENV.fetch('MC_PORT', '')
|
25
|
+
@subject_suffix = ENV.fetch('MC_SUBJECT_SUFFIX', '')
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
|
30
|
+
class << self
|
31
|
+
attr_writer :configuration
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.configuration
|
35
|
+
@configuration ||= Configuration.new
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.configure
|
39
|
+
yield(configuration)
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.fetch
|
43
|
+
|
44
|
+
login = MailComments.configuration.login
|
45
|
+
password = MailComments.configuration.password
|
46
|
+
host = MailComments.configuration.host
|
47
|
+
port = MailComments.configuration.port
|
48
|
+
subject_suffix = MailComments.configuration.subject_suffix
|
49
|
+
|
50
|
+
imap = Net::IMAP.new(host, 993, true)
|
51
|
+
imap.login(login, password)
|
52
|
+
imap.select("INBOX")
|
53
|
+
cx = imap.search(["SUBJECT", subject_suffix, "UNSEEN"])
|
54
|
+
if !cx.nil? && cx.length > 0
|
55
|
+
puts "Comments found CX=#{cx.length}"
|
56
|
+
comments = {}
|
57
|
+
cx.each do |message_id|
|
58
|
+
msg = imap.fetch(message_id,'RFC822')[0].attr['RFC822']
|
59
|
+
mail = Mail.read_from_string(msg)
|
60
|
+
if mail.multipart?
|
61
|
+
body = mail.multipart?? mail.text_part.body.decoded : mail.html_part.body.decoded
|
62
|
+
else
|
63
|
+
body = mail.body.decoded
|
64
|
+
end
|
65
|
+
|
66
|
+
author = mail.header['From'].field.addrs.first.display_name
|
67
|
+
|
68
|
+
begin
|
69
|
+
tmp = mail.subject.split(":")
|
70
|
+
if tmp.length == 4
|
71
|
+
reply_id = mail.subject.split(":")[1].strip()
|
72
|
+
post_title = mail.subject.split(":")[3].strip()
|
73
|
+
|
74
|
+
message_id = Digest::SHA1.hexdigest(mail['Message-ID'].value)
|
75
|
+
comment = {
|
76
|
+
title: post_title,
|
77
|
+
reply_to: reply_id,
|
78
|
+
id: message_id,
|
79
|
+
author: author,
|
80
|
+
from: mail.from.first,
|
81
|
+
date: mail.date,
|
82
|
+
text: body
|
83
|
+
}
|
84
|
+
file_name = "#{mail.date.strftime("%s").to_s}-#{message_id}.yaml"
|
85
|
+
File.open("_data/comments/#{file_name}", "w") do |f|
|
86
|
+
f.write(comment.transform_keys(&:to_s).to_yaml)
|
87
|
+
end
|
88
|
+
puts "Comment from #{comment[:author]} - <#{comment[:from]}> on \"#{comment[:title]}\" at #{comment[:date]}"
|
89
|
+
else
|
90
|
+
puts "Wrong subject for #{msg}"
|
91
|
+
end
|
92
|
+
|
93
|
+
rescue => e
|
94
|
+
puts e
|
95
|
+
end
|
96
|
+
end
|
97
|
+
else
|
98
|
+
puts "No messages found."
|
99
|
+
end
|
100
|
+
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
require 'net/imap'
|
2
|
+
require 'mail'
|
3
|
+
require 'fileutils'
|
4
|
+
require "base64"
|
5
|
+
require 'yaml'
|
6
|
+
require 'digest'
|
7
|
+
|
8
|
+
|
9
|
+
module MailComments
|
10
|
+
|
11
|
+
class Configuration
|
12
|
+
attr_accessor :login
|
13
|
+
attr_accessor :password
|
14
|
+
attr_accessor :host
|
15
|
+
attr_accessor :port
|
16
|
+
attr_accessor :subject_suffix
|
17
|
+
|
18
|
+
def initialize
|
19
|
+
@login = ENV.fetch('MC_LOGIN', '')
|
20
|
+
@password = ENV.fetch('MC_PASSWORD', '')
|
21
|
+
@host = ENV.fetch('MC_HOST', '')
|
22
|
+
@port = ENV.fetch('MC_PORT', '')
|
23
|
+
@subject_suffix = ENV.fetch('MC_SUBJECT_SUFFIX', '')
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
|
28
|
+
class << self
|
29
|
+
attr_writer :configuration
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.configuration
|
33
|
+
@configuration ||= Configuration.new
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.configure
|
37
|
+
yield(configuration)
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.fetch
|
41
|
+
|
42
|
+
login = MailComments.configuration.login
|
43
|
+
password = MailComments.configuration.password
|
44
|
+
host = MailComments.configuration.host
|
45
|
+
port = MailComments.configuration.port
|
46
|
+
subject_suffix = MailComments.configuration.subject_suffix
|
47
|
+
|
48
|
+
imap = Net::IMAP.new(host, 993, true)
|
49
|
+
imap.login(login, password)
|
50
|
+
imap.select("INBOX")
|
51
|
+
cx = imap.search(["SUBJECT", subject_suffix, "UNSEEN"])
|
52
|
+
if !cx.nil? && cx.length > 0
|
53
|
+
puts "Comments found CX=#{cx.length}"
|
54
|
+
comments = {}
|
55
|
+
cx.each do |message_id|
|
56
|
+
msg = imap.fetch(message_id,'RFC822')[0].attr['RFC822']
|
57
|
+
mail = Mail.read_from_string(msg)
|
58
|
+
if mail.multipart?
|
59
|
+
body = mail.multipart?? mail.text_part.body.decoded : mail.html_part.body.decoded
|
60
|
+
else
|
61
|
+
body = mail.body.decoded
|
62
|
+
end
|
63
|
+
|
64
|
+
author = mail.header['From'].field.addrs.first.display_name
|
65
|
+
|
66
|
+
begin
|
67
|
+
tmp = mail.subject.split(":")
|
68
|
+
if tmp.length == 4
|
69
|
+
reply_id = mail.subject.split(":")[1].strip()
|
70
|
+
post_title = mail.subject.split(":")[3].strip()
|
71
|
+
|
72
|
+
message_id = Digest::SHA1.hexdigest(mail['Message-ID'].value)
|
73
|
+
comment = {
|
74
|
+
title: post_title,
|
75
|
+
reply_to: reply_id,
|
76
|
+
id: message_id,
|
77
|
+
author: author,
|
78
|
+
from: mail.from.first,
|
79
|
+
date: mail.date,
|
80
|
+
text: body
|
81
|
+
}
|
82
|
+
file_name = "#{mail.date.strftime("%s").to_s}-#{message_id}.yaml"
|
83
|
+
File.open("_data/comments/#{file_name}", "w") do |f|
|
84
|
+
f.write(comment.transform_keys(&:to_s).to_yaml)
|
85
|
+
end
|
86
|
+
puts "Comment from #{comment[:author]} - <#{comment[:from]}> on \"#{comment[:title]}\" at #{comment[:date]}"
|
87
|
+
else
|
88
|
+
puts "Wrong subject for #{msg}"
|
89
|
+
end
|
90
|
+
|
91
|
+
rescue => e
|
92
|
+
puts e
|
93
|
+
end
|
94
|
+
end
|
95
|
+
else
|
96
|
+
puts "No messages found."
|
97
|
+
end
|
98
|
+
|
99
|
+
end
|
100
|
+
end
|
@@ -0,0 +1,7 @@
|
|
1
|
+
{%- for entry in site.data.comments -%}
|
2
|
+
{%- if entry[1].reply_to == include.replies_to -%}
|
3
|
+
{%- assign comment_count = comment_count | plus: 1 -%}
|
4
|
+
{%- assign com_id = entry[0] -%}
|
5
|
+
{%- include comments-count.html replies_to=com_id -%}
|
6
|
+
{%- endif -%}
|
7
|
+
{%- endfor -%}
|
@@ -0,0 +1,30 @@
|
|
1
|
+
{% assign sorted = site.data.comments | sort %}
|
2
|
+
{%- for entry in sorted -%}
|
3
|
+
|
4
|
+
{%- assign cid = entry[0] -%}
|
5
|
+
{%- assign com = entry[1] -%}
|
6
|
+
{%- assign indent_class = include.indent_class %}
|
7
|
+
{%- assign title = include.title %}
|
8
|
+
{%- if com.reply_to != include.replies_to -%}
|
9
|
+
{%- continue -%}
|
10
|
+
{%- endif -%}
|
11
|
+
|
12
|
+
<div class="{{ indent_class }} comment" id="{{ cid }}">
|
13
|
+
<div class="d-flex">
|
14
|
+
<div><a href="" class="comment-author">{{ com.author | escape | strip_newlines }}</a> - <span class="comment-date"> {{ com.date | date_to_rfc822 }}</span></div>
|
15
|
+
<!-- <div class="ml-auto">at {{ com.date | date_to_rfc822 }}</div> -->
|
16
|
+
</div>
|
17
|
+
<div>
|
18
|
+
{{ com.text | escape | newline_to_br | strip_newlines | markdownify | replace: "&#39;", "'" | replace: "&quot;", '"' }}
|
19
|
+
|
20
|
+
<!-- <div class="comment-controls">
|
21
|
+
<a href="#{{cid}}">Permalink</a> | <a href="mailto:{{site.comments.email}}?subject=RE:{{cid}}:{{site.comments.subject_suffix}}:{{ page.path}}">Reply</a>
|
22
|
+
</div> -->
|
23
|
+
</div>
|
24
|
+
<div class="d-flex">
|
25
|
+
<div class="ml-auto"><a href="#{{cid}}">Permalink</a> | <a href="mailto:{{site.comments.email}}?subject=RE:{{cid}}:{{site.comments.subject_suffix}}:{{title}}">Reply</a> </div>
|
26
|
+
</div>
|
27
|
+
{%- include comments.html replies_to=cid indent_class="ml-3 comment-indent" title=title -%}
|
28
|
+
</div>
|
29
|
+
|
30
|
+
{%- endfor -%}
|
metadata
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: jekyll-mail-comments
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.2
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Dmitry Rodichev
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2022-01-01 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: jekyll
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
description: 'Provides html generator of threaded comments pages fetched from an IMAP
|
28
|
+
for Jekyll
|
29
|
+
|
30
|
+
'
|
31
|
+
email: noroot@falsetrue.io
|
32
|
+
executables:
|
33
|
+
- jekyll-mail-comments-fetch
|
34
|
+
extensions: []
|
35
|
+
extra_rdoc_files: []
|
36
|
+
files:
|
37
|
+
- ".env.dist"
|
38
|
+
- ".gitignore"
|
39
|
+
- Gemfile
|
40
|
+
- README.md
|
41
|
+
- bin/jekyll-mail-comments-fetch
|
42
|
+
- jekyll-mail-comments.gemspec
|
43
|
+
- lib/jekyll-mail-comments.rb
|
44
|
+
- lib/jekyll_mail_comments.rb
|
45
|
+
- templates/comments-count.html
|
46
|
+
- templates/comments.html
|
47
|
+
homepage: https://github.com/noroot/jekyll-mail-comments
|
48
|
+
licenses:
|
49
|
+
- GPL-3.0
|
50
|
+
metadata: {}
|
51
|
+
post_install_message: 'Don''t forget to put credentials inside .env file, see .env.dist
|
52
|
+
inside gem source.
|
53
|
+
|
54
|
+
'
|
55
|
+
rdoc_options: []
|
56
|
+
require_paths:
|
57
|
+
- lib
|
58
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
59
|
+
requirements:
|
60
|
+
- - ">="
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: '0'
|
63
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
64
|
+
requirements:
|
65
|
+
- - ">="
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: '0'
|
68
|
+
requirements: []
|
69
|
+
rubygems_version: 3.0.6
|
70
|
+
signing_key:
|
71
|
+
specification_version: 4
|
72
|
+
summary: Email based comment system for Jekyll static site generator
|
73
|
+
test_files: []
|