easycomments 1.0.3 → 1.0.4

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 7167047b3d7e6712e100ad6e3692c94645fb4f5d
4
- data.tar.gz: 3cef902dde8bd0c7e029964d1a4563c8fda27024
3
+ metadata.gz: 3769d7478cdda520b182646690a420544f484241
4
+ data.tar.gz: 741d5355bf84ff27c09c3ef9f672a25e9472d24a
5
5
  SHA512:
6
- metadata.gz: e07ab076abda884464ebb29eb2b6b44e4d64040b731a5f3bc551bb8b1bd84ee9b39a941727b211760be6be98148f71ecbe68e26b34138a1fd86ab581037d56fb
7
- data.tar.gz: 2babd846e16e62569b7ed42c5436d88f3cc0f63bee63a06a37eff2f5541ab4c5fd48e681af4a4f6d1e297577c2a06af81d71ff691465945185597e87a9af9008
6
+ metadata.gz: 608099e88c4eac8f4b7b035480fe64d6cb88e94d2aebd59a20fdc80100019ab3656b9ea47dcac7630095f2fb792e6fcc312f9340fee5bcd099d203bc5ebbebba
7
+ data.tar.gz: 3e91047ba20119846abc20fa345c79f70e558926216519198c4b402d36376d15811299cc6baa55644fc5ce21ced3ed4456b9dccdda13cb61df018f3a22d32f06
data/README.md CHANGED
@@ -18,8 +18,11 @@ ec install
18
18
  ```
19
19
  (pass the --dev flag if you also want the spec suite)
20
20
  Then
21
- ```ruby
22
- bundle install
21
+ ```
22
+ bundle install --without test development
23
+ or just
24
+ bundle install
25
+ if --dev is on
23
26
  ```
24
27
  and you are ready.
25
28
  ##Configuring
@@ -38,7 +41,7 @@ to add your user.
38
41
  ##Endpoints
39
42
  EC has one endpoint for posting a new comment and one for retrieving a comment list.
40
43
  ```
41
- GET /comments, with a 'post' parameter
44
+ GET /comments, with a 'post' parameter and an optional 'page' parameter if you have pagination enabled.
42
45
  ```
43
46
  The 'post' parameter simply serves as a namespace to group comments for retrieval,
44
47
  it can be a blog post title, an url or something more sophisticated, it's up to you.
@@ -77,8 +80,14 @@ allow_cors: false
77
80
  #see available formats here https://github.com/cyu/rack-cors
78
81
  cors_origin: "*"
79
82
 
80
- #set to false to not automatically escape html in comment bodys
83
+ #set to false to not automatically escape html in comment bodies
81
84
  auto_escape_html: true
85
+
86
+ #set to true to have pagination support in comment retrieval
87
+ paginate: false
88
+
89
+ #how many comments to return per page if paginate is true
90
+ comments_per_page: 10
82
91
  ```
83
92
 
84
93
  ## Updating
@@ -93,7 +102,6 @@ It will recopy all the files but keeps your _config.yml and Gemfile.
93
102
  by hand since it also bcrypts your passwords!
94
103
 
95
104
  ##TODO:
96
- * pagination in GET /comments
97
105
  * markdown support
98
106
  * dynamic fields in POST /comment
99
107
 
data/_config.yml CHANGED
@@ -1,12 +1,13 @@
1
1
  ---
2
- connection: "sqlite://blog.db"
2
+ connection: sqlite://blog.db
3
3
  approve_by_default: false
4
4
  allow_anonymous_post: false
5
5
  timestamp_format: "%d/%m/%Y - %H:%M"
6
6
  allow_cors: false
7
7
  cors_origin: "*"
8
8
  auto_escape_html: true
9
- :users:
9
+ paginate: false
10
+ comments_per_page: 10
10
11
  #
11
12
  ##connection : database connection url to be passed to sequel's connect method.
12
13
  ##check http://sequel.jeremyevans.net/rdoc/files/doc/opening_databases_rdoc.html
@@ -25,6 +26,10 @@ auto_escape_html: true
25
26
  #
26
27
  ##auto_escape_html : automatically escape html in comment bodys
27
28
  #
29
+ ##paginate : set to true to have pagination support in comment retrieval
30
+ #
31
+ ##comments_per_page : how many comments to return per page if paginate is true
32
+ #
28
33
  ##users : do not edit this by hand use 'rake adduser' instead.
29
34
  #
30
35
  ##if you edit this file after 'rake init' use 'rake update' for the changes to take effect.
data/dashboard.rb CHANGED
@@ -19,7 +19,7 @@ class ECDashboard < Sinatra::Application
19
19
  end
20
20
 
21
21
  get "/comments" do
22
- get_comments(params[:post])
22
+ get_comments(params[:post], params[:page])
23
23
  end
24
24
 
25
25
  get '/get_all_posts' do
@@ -47,7 +47,7 @@ class ECDashboard < Sinatra::Application
47
47
  end
48
48
 
49
49
  get '/get_pending_comments' do
50
- get_pending_comments(params[:post])
50
+ get_pending_comments(params[:post], params[:page])
51
51
  end
52
52
 
53
53
  post '/ignore_comment' do
data/easycomments.gemspec CHANGED
@@ -1,7 +1,7 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'easycomments'
3
- s.version = '1.0.3'
4
- s.date = '2015-03-31'
3
+ s.version = '1.0.4'
4
+ s.date = '2015-04-03'
5
5
  s.summary = "Simple and easy to use comment system"
6
6
  s.description = <<EOF
7
7
  EasyComments(EC) is an easy to use comment system with a simple api
data/ec.rb CHANGED
@@ -29,7 +29,7 @@ class EC < Sinatra::Application
29
29
 
30
30
 
31
31
  get "/comments" do
32
- get_comments(params[:post])
32
+ get_comments(params[:post], params[:page])
33
33
  end
34
34
 
35
35
  post "/comment" do
@@ -14,6 +14,8 @@ module Configuration
14
14
  ALLOW_CORS = CONFIG["allow_cors"]
15
15
  CORS_ORIGIN = CONFIG["cors_origin"]
16
16
  AUTO_ESCAPE_HTML = CONFIG["auto_escape_html"]
17
+ PAGINATE = CONFIG["paginate"]
18
+ COMMENTS_PER_PAGE = CONFIG["comments_per_page"].to_i
17
19
 
18
20
  #wall of help text to be added in _config.yml
19
21
  def comment_wall
@@ -34,7 +36,11 @@ comments = <<COMMENTS
34
36
  #
35
37
  ##cors_origin : see available formats here https://github.com/cyu/rack-cors
36
38
  #
37
- ##auto_escape_html : automatically escape html in comment bodys
39
+ ##auto_escape_html : automatically escape html in comment bodies
40
+ #
41
+ ##paginate : set to true to have pagination support in comment retrieval
42
+ #
43
+ ##comments_per_page : how many comments to return per page if paginate is true
38
44
  #
39
45
  ##users : do not edit this by hand use 'rake adduser' instead.
40
46
  #
@@ -2,11 +2,13 @@ require_relative "../easycomments.rb"
2
2
 
3
3
  module ECDashboardModel
4
4
  extend self
5
-
6
- def get_comments(post)
7
- comments = DB[:comments].where(:post => post).all.sort_by{|comment| comment[:id].to_i}.reverse #show latest comment first
5
+ include Pagination
6
+
7
+ def get_comments(post, page_num)
8
+ comments = DB[:comments].where(:post => post).reverse(Sequel.asc(:timestamp)).page(page_num).all
9
+ count = DB[:comments].where(:post => post).page(page_num).page_count
8
10
  comments = comments.each{|comment| comment[:timestamp] = comment[:timestamp].strftime(TIMESTAMP_FORMAT)}
9
- MultiJson.dump({:comments => comments})
11
+ MultiJson.dump(:comments => comments, :page_count => count)
10
12
  end
11
13
 
12
14
  def get_all_posts
@@ -43,10 +45,11 @@ module ECDashboardModel
43
45
  MultiJson.dump({:pending => pending})
44
46
  end
45
47
 
46
- def get_pending_comments(post)
47
- comments = DB[:comments].where(:post => post, :action_taken => false).all.sort_by{|comment| comment[:id].to_i}.reverse #show latest comment first
48
+ def get_pending_comments(post, page_num)
49
+ comments = DB[:comments].where(:post => post, :action_taken => false).reverse(Sequel.asc(:timestamp)).page(page_num).all
50
+ count = DB[:comments].where(:post => post, :action_taken => false).page(page_num).page_count
48
51
  comments = comments.each{|comment| comment[:timestamp] = comment[:timestamp].strftime(TIMESTAMP_FORMAT)}
49
- MultiJson.dump({:comments => comments})
52
+ MultiJson.dump({:comments => comments, :page_count => count})
50
53
  end
51
54
 
52
55
  def ignore_comment(id)
@@ -3,6 +3,7 @@ require_relative "../easycomments.rb"
3
3
  module ECModel
4
4
 
5
5
  extend self
6
+ include Pagination if PAGINATE
6
7
 
7
8
  def post_comment(comment)
8
9
  if comment[:body] != "undefined" && comment[:body] != ""
@@ -20,10 +21,20 @@ module ECModel
20
21
  end
21
22
  end
22
23
 
23
- def get_comments(post)
24
- comments = DB[:comments].where(:post => post, :approved => true).all.sort_by{|comment| comment[:id].to_i}.reverse #show latest comment first
25
- comments = comments.each{|comment| comment[:timestamp] = comment[:timestamp].strftime(TIMESTAMP_FORMAT)}
26
- MultiJson.dump({:comments => comments})
24
+ def get_comments(post, page_num)
25
+ if PAGINATE
26
+ comments = DB[:comments].where(:post => post, :approved => true).reverse(Sequel.asc(:timestamp)).page(page_num).all
27
+ count = DB[:comments].where(:post => post).page(page_num).page_count
28
+ comments = comments.each{|comment| comment[:timestamp] = comment[:timestamp].strftime(TIMESTAMP_FORMAT)}
29
+ page_num = page_num.to_i
30
+ page_num = 1 if page_num < 1
31
+ response = {:comments => comments, :page => page_num.to_i, :total_pages => count}
32
+ else
33
+ comments = DB[:comments].where(:post => post, :approved => true).reverse(Sequel.asc(:timestamp)).all
34
+ comments = comments.each{|comment| comment[:timestamp] = comment[:timestamp].strftime(TIMESTAMP_FORMAT)}
35
+ response = {:comments => comments}
36
+ end
37
+ MultiJson.dump(response)
27
38
  end
28
39
 
29
40
  private
@@ -44,4 +55,5 @@ module ECModel
44
55
  )
45
56
  MultiJson.dump({:status => "New comment posted."})
46
57
  end
58
+
47
59
  end
@@ -0,0 +1,20 @@
1
+ module Pagination
2
+ extend self
3
+
4
+ class Sequel::Model
5
+ def self.page(page, per_page=COMMENTS_PER_PAGE || 10, *args)
6
+ page = page.to_i
7
+ page = 1 if page < 1
8
+ dataset.paginate(page, per_page, *args)
9
+ end
10
+ end
11
+
12
+ class Sequel::Dataset
13
+ def page(page, per_page=COMMENTS_PER_PAGE || 10, *args)
14
+ page = page.to_i
15
+ page = 1 if page < 1
16
+ paginate(page, per_page, *args)
17
+ end
18
+ end
19
+
20
+ end
data/lib/easycomments.rb CHANGED
@@ -6,9 +6,11 @@ require 'rack/utils'
6
6
  require 'rack/protection'
7
7
  require 'bcrypt'
8
8
  require_relative "easycomments/ec_configuration.rb"
9
+ require_relative "easycomments/ec_pagination.rb"
9
10
 
10
- VERSION = "1.0.3"
11
+ VERSION = "1.0.4"
11
12
 
12
13
  include Configuration
13
14
 
14
15
  DB = Sequel.connect(CONNECTION)
16
+ DB.extension(:pagination)
@@ -81,6 +81,20 @@
81
81
  text-decoration: none !important;
82
82
  color: #616161;
83
83
  }
84
+ .pagination{
85
+ padding-top: 20px;
86
+ padding-bottom: 20px;
87
+ }
88
+ .pg_input {
89
+ width: 83px;
90
+ }
91
+ .pg_btn::shadow #ripple {
92
+ color: #FFA726;
93
+ }
94
+ paper-input-decorator /deep/ .focused-underline {
95
+ /* line color when the input is focused */
96
+ background-color: #FF9800;
97
+ }
84
98
  </style>
85
99
  <core-ajax
86
100
  auto
@@ -106,16 +120,18 @@
106
120
  <core-ajax
107
121
  id="get_all_comments"
108
122
  url="/dashboard/comments"
109
- params='{"post":"{{post_global}}"}'
123
+ params='{"post":"{{post_global}}", "page":"{{current_page}}"}'
110
124
  handleAs="json"
111
- response="{{comments}}">
125
+ response="{{comments}}"
126
+ on-core-complete="{{pageRange}}">
112
127
  </core-ajax>
113
128
  <core-ajax
114
129
  id="get_pending_comments"
115
130
  url="/dashboard/get_pending_comments"
116
- params='{"post":"{{post_global}}"}'
131
+ params='{"post":"{{post_global}}", "page":"{{current_page}}"}'
117
132
  handleAs="json"
118
- response="{{comments}}">
133
+ response="{{comments}}"
134
+ on-core-complete="{{pageRange}}">
119
135
  </core-ajax>
120
136
  <core-ajax
121
137
  id="edit_comment"
@@ -157,8 +173,8 @@
157
173
  <core-menu>
158
174
  <section is="auto-binding">
159
175
  <paper-tabs selected="{{selected}}">
160
- <paper-tab>Pending&nbsp;&nbsp;<span class="pending_number">{{total_pending.pending}}</span></paper-tab>
161
- <paper-tab>All</paper-tab>
176
+ <paper-tab on-click="{{refreshPosts}}">Pending&nbsp;&nbsp;<span class="pending_number">{{total_pending.pending}}</span></paper-tab>
177
+ <paper-tab on-click="{{refreshPosts}}">All</paper-tab>
162
178
  </paper-tabs>
163
179
  <core-pages selected="{{selected}}">
164
180
  <div>
@@ -180,7 +196,7 @@
180
196
  <div tool id="title">{{post_title}}</div>
181
197
  <div id ="content" fit>
182
198
  <template repeat="{{comment in comments.comments}}">
183
- <paper-shadow>
199
+ <paper-shadow id="comment_{{comment.id}}">
184
200
  <p id="comment-title">{{comment.name}} - {{comment.email}} - {{comment.timestamp}}</p>
185
201
  <paper-autogrow-textarea id="a1">
186
202
  <textarea value="{{comment.body}}" rows="5"></textarea>
@@ -198,6 +214,16 @@
198
214
  </div>
199
215
  </paper-shadow>
200
216
  </template>
217
+ <template if="{{comments.page_count > 1}}">
218
+ <paper-shadow class="pagination" horizontal center-justified layout>
219
+ <paper-button class="pg_btn" on-click="{{firstPage}}">First</paper-button>
220
+ <paper-button disabled='{{current_page <= 1}}' class="pg_btn" on-click="{{prevPage}}">Previous</paper-button>
221
+ <paper-input-decorator class="pg_input"><input is="core-input" value="{{page_input}}"></paper-input-decorator>
222
+ <label class="pg_btn"><br>of {{comments.page_count}}</label>
223
+ <paper-button disabled='{{current_page >= comments.total_pages}}' on-click="{{nextPage}}" class="pg_btn">Next</paper-button>
224
+ <paper-button class="pg_btn" on-click="{{lastPage}}">Last</paper-button>
225
+ </paper-shadow>
226
+ </template>
201
227
  </div>
202
228
  </core-scaffold>
203
229
  </template>
@@ -208,12 +234,16 @@
208
234
  var p = e.target.templateInstance.model.post;
209
235
  this.post_title = p;
210
236
  this.post_global = p;
237
+ this.current_page = 1;
238
+ this.page_input = this.current_page;
211
239
  this.shadowRoot.querySelector("#get_all_comments").go();
212
240
  },
213
241
  getPendingComments: function(e, detail, sender){
214
242
  var p = e.target.templateInstance.model.post.post;
215
243
  this.post_title = p;
216
244
  this.post_global = p;
245
+ this.current_page = 1;
246
+ this.page_input = this.current_page;
217
247
  this.shadowRoot.querySelector("#get_pending_comments").go();
218
248
  },
219
249
  editComment: function(e, detail, sender){
@@ -230,10 +260,13 @@
230
260
  this.comment_id = d;
231
261
  this.shadowRoot.querySelector("#remove_comment").go();
232
262
  //refresh comment list
233
- this.shadowRoot.querySelector("#get_all_comments").go();
263
+ if (this.selected == "0") {
264
+ this.shadowRoot.querySelector("#get_pending_comments").go();
265
+ }else {
266
+ this.shadowRoot.querySelector("#get_all_comments").go();
267
+ }
234
268
  //refresh post list
235
269
  this.refreshPosts();
236
- //na vgainei kai to title panw panw
237
270
  },
238
271
  approveComment: function(e, detail, sender){
239
272
  var d = e.target.templateInstance.model.comment.id;
@@ -249,7 +282,11 @@
249
282
  //refresh post list
250
283
  this.refreshPosts();
251
284
  //refresh comment list
252
- this.shadowRoot.querySelector("#get_pending_comments").go();
285
+ if (this.selected == "0") {
286
+ this.shadowRoot.querySelector("#get_pending_comments").go();
287
+ }else {
288
+ this.shadowRoot.querySelector("#get_all_comments").go();
289
+ }
253
290
  },
254
291
  showToast: function(event, response) {
255
292
  this.shadowRoot.querySelector('#toast1').text = response.response.status;
@@ -260,6 +297,56 @@
260
297
  this.shadowRoot.querySelector("#get_posts_with_pending").go();
261
298
  this.shadowRoot.querySelector("#get_total_pending").go();
262
299
  },
300
+ firstPage: function () {
301
+ this.current_page = 1;
302
+ this.page_input = this.current_page;
303
+ if (this.selected == "0") {
304
+ this.shadowRoot.querySelector("#get_pending_comments").go();
305
+ }else {
306
+ this.shadowRoot.querySelector("#get_all_comments").go();
307
+ }
308
+ },
309
+ lastPage: function () {
310
+ this.current_page = this.comments.page_count;
311
+ this.page_input = this.current_page;
312
+ if (this.selected == "0") {
313
+ this.shadowRoot.querySelector("#get_pending_comments").go();
314
+ }else {
315
+ this.shadowRoot.querySelector("#get_all_comments").go();
316
+ }
317
+ },
318
+ prevPage: function () {
319
+ this.current_page = this.current_page - 1;
320
+ this.page_input = this.current_page;
321
+ if (this.selected == "0") {
322
+ this.shadowRoot.querySelector("#get_pending_comments").go();
323
+ }else {
324
+ this.shadowRoot.querySelector("#get_all_comments").go();
325
+ }
326
+ },
327
+ nextPage: function () {
328
+ this.current_page = this.current_page + 1;
329
+ this.page_input = this.current_page;
330
+ if (this.selected == "0") {
331
+ this.shadowRoot.querySelector("#get_pending_comments").go();
332
+ }else {
333
+ this.shadowRoot.querySelector("#get_all_comments").go();
334
+ }
335
+ },
336
+ setPage: function (oldValue, newValue) {
337
+ if (oldValue != newValue && newValue > 0){
338
+ var value = Path.get('page_input').getValueFrom(this);
339
+ this.current_page = value;
340
+ if (this.selected == "0") {
341
+ this.shadowRoot.querySelector("#get_pending_comments").go();
342
+ }else {
343
+ this.shadowRoot.querySelector("#get_all_comments").go();
344
+ }
345
+ }
346
+ },
347
+ observe: {
348
+ 'page_input': 'setPage'
349
+ },
263
350
  attached: function() {
264
351
  //open pending tab by default
265
352
  this.selected = "0";
@@ -0,0 +1,78 @@
1
+ <link rel="import" href="../../bower_components/polymer/polymer.html">
2
+ <polymer-element name="ec-login">
3
+ <template>
4
+ <style>
5
+ #container {
6
+ background-color: #E5E5E5;
7
+ font-family: 'RobotoDraft', sans-serif;
8
+ width: 100%;
9
+ height: 100%;
10
+ }
11
+ #login_form {
12
+ width: 280px;
13
+ height: 260px;
14
+ margin-top: 10%;
15
+ }
16
+ a {
17
+ text-decoration: none !important;
18
+ color: #616161;
19
+ }
20
+ #title {
21
+ padding-left:50px;
22
+ }
23
+ #login_button::shadow #ripple {
24
+ color: #FFA726;
25
+ }
26
+ paper-input-decorator /deep/ .focused-underline {
27
+ /* line color when the input is focused */
28
+ background-color: #FFB74D;
29
+ }
30
+ paper-input-decorator /deep/ #floatedLabelText {
31
+ color: #616161;
32
+ }
33
+ </style>
34
+ <core-ajax
35
+ id="login"
36
+ url="/dashboard/login"
37
+ method="post"
38
+ params='{"username":"{{username}}", "password":"{{password}}"}'
39
+ handleAs="json"
40
+ on-core-response="{{postLogin}}">
41
+ </core-ajax>
42
+ <div horizontal center-justified layout id="container">
43
+ <paper-shadow id="login_form" vertical layout>
44
+ <paper-shadow><div id="title"><a href="/"><h2>EasyComments<h2></a></div></paper-shadow>
45
+ <paper-input-decorator label="Username" floatingLabel>
46
+ <input id="username" is="core-input" type="text" value="{{username}}"/>
47
+ </paper-input-decorator>
48
+ <paper-input-decorator label="Password" floatingLabel>
49
+ <input id="password" is="core-input" type="password" value="{{password}}"/>
50
+ </paper-input-decorator>
51
+ <paper-button id="login_button" on-click="{{login}}">Login</paper-button>
52
+ </paper-shadow>
53
+ </div>
54
+ <template if="{{has_access}}">
55
+ <ec-dashboard></ec-dashboard>
56
+ </template>
57
+ <paper-toast id="toast1" text="Wrong username or password."></paper-toast>
58
+ </template>
59
+ <script>
60
+ Polymer('ec-login', {
61
+ login: function() {
62
+ this.shadowRoot.querySelector("#login").go();
63
+ },
64
+ postLogin: function(event, response) {
65
+ this.has_access = response.response.has_access;
66
+ if(this.has_access === false){
67
+ this.shadowRoot.querySelector('#toast1').show();
68
+ }else{
69
+ //hide the form
70
+ this.shadowRoot.querySelector("#container").hidden = true;
71
+ }
72
+ },
73
+ ready: function(){
74
+ this.has_access = false;
75
+ },
76
+ });
77
+ </script>
78
+ </polymer-element>
@@ -19,6 +19,7 @@
19
19
  <link rel="import" href="/bower_components/core-pages/core-pages.html">
20
20
 
21
21
  <link rel="import" href="/elements/ec-dashboard/ec-dashboard.html">
22
+ <link rel="import" href="/elements/ec-login/ec-login.html">
22
23
  <!--
23
24
  vulcanize ./polymer-loader.html --abspath ./ --inline --strip -o ./polymer-loader.vulcanized.html
24
25
  -->