easycomments 1.0.3 → 1.0.4

Sign up to get free protection for your applications and to get access to all the features.
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
  -->