carte-server 0.0.7 → 0.0.8
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rspec +1 -0
- data/Rakefile +1 -47
- data/config.json +3 -3
- data/lib/carte/client/helpers.coffee +4 -0
- data/lib/carte/client/models/card.coffee +6 -2
- data/lib/carte/client/models/cards.coffee +5 -1
- data/lib/carte/client/views/card.cjsx +3 -3
- data/lib/carte/client/views/content.cjsx +2 -1
- data/lib/carte/client/views/header.cjsx +1 -1
- data/lib/carte/client/views/list.cjsx +11 -47
- data/lib/carte/client/views/pagination.cjsx +55 -0
- data/lib/carte/server.rb +1 -0
- data/lib/carte/server/models/card.rb +3 -0
- data/lib/carte/server/tasks.rb +47 -0
- data/lib/carte/server/validators.rb +1 -0
- data/lib/carte/server/validators/array_validator.rb +24 -0
- data/lib/carte/server/version.rb +1 -1
- data/package.json +2 -1
- data/spec/server_spec.rb +35 -9
- metadata +8 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 62e6b5113d7bafffdb2e35701cabd5a01ae26532
|
4
|
+
data.tar.gz: 8f4dd2dee37acd726a75e5c4477e5d7ec325e4ab
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: af45cdb68b5f9de14cfc855e1199453ba0762f41bd6a781dd0e9f5db467f86713da9bd29f138d419e77b8d3bfbff7de045a30a972baf2f28b1631fdc9029853c
|
7
|
+
data.tar.gz: 015f9690877ab8a0f6ac5ca9f982b1774163ed38a9fef3fe237f02a516b1278403af5897a1d6f9e4f9113b6eb141030a84f94639b80dee25de4b13f3059fc299
|
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--format documentation --color
|
data/Rakefile
CHANGED
@@ -1,49 +1,3 @@
|
|
1
1
|
require "bundler/gem_tasks"
|
2
|
-
require "carte/server"
|
2
|
+
require "carte/server/tasks"
|
3
3
|
Carte::Server.configure { Mongoid.load!('mongoid.yml') }
|
4
|
-
include Carte::Server::Models
|
5
|
-
|
6
|
-
namespace :carte do
|
7
|
-
desc 'analyze'
|
8
|
-
task :analyze do
|
9
|
-
title, content = {max: 0, min: 0}, {max: 0, min: 0}
|
10
|
-
count = Hash.new(0)
|
11
|
-
Card.all.each do |card|
|
12
|
-
title[:max] = [card.title.length, title[:max]].max
|
13
|
-
title[:min] = [card.title.length, title[:min]].min
|
14
|
-
content[:max] = [card.content.length, content[:max]].max
|
15
|
-
content[:min] = [card.content.length, content[:min]].min
|
16
|
-
if card.content == ''
|
17
|
-
puts "#{card.title} : content is empty"
|
18
|
-
end
|
19
|
-
count[card.title] += 1
|
20
|
-
end
|
21
|
-
puts "title: #{title}, content: #{content}"
|
22
|
-
count.each do |card, count|
|
23
|
-
puts "#{card}: #{count} items" if count != 1
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
desc 'import fr.txt'
|
28
|
-
task :import do
|
29
|
-
entries = []
|
30
|
-
file = File.open(ENV['FILE'])
|
31
|
-
lines = file.read.split("\n")
|
32
|
-
lines.each_slice(2) do |title, content|
|
33
|
-
Card.create!(title: title, content: content)
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
desc 'export'
|
38
|
-
task :export do
|
39
|
-
Card.all.each do |card|
|
40
|
-
puts card.title
|
41
|
-
puts card.content
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
desc 'reset'
|
46
|
-
task :reset do
|
47
|
-
Card.delete_all
|
48
|
-
end
|
49
|
-
end
|
data/config.json
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
Backbone = require('backbone')
|
2
|
+
config = require('../../shared/config.json')
|
2
3
|
|
3
4
|
module.exports = class Card extends Backbone.Model
|
4
5
|
idAttribute: 'title'
|
@@ -10,10 +11,13 @@ module.exports = class Card extends Backbone.Model
|
|
10
11
|
if @isNew()
|
11
12
|
console.log @
|
12
13
|
console.log 'url is new'
|
13
|
-
'/api/cards.json'
|
14
|
+
url = '/api/cards.json'
|
14
15
|
else
|
15
16
|
console.log 'url is not new'
|
16
|
-
'/api/cards/' + @get('title') + '.json'
|
17
|
+
url = '/api/cards/' + @get('title') + '.json'
|
18
|
+
if config.api_path
|
19
|
+
url = config.api_path + url
|
20
|
+
url
|
17
21
|
|
18
22
|
parse: (response)->
|
19
23
|
if response.card then response.card else response
|
@@ -1,12 +1,16 @@
|
|
1
1
|
Backbone = require('backbone')
|
2
2
|
CardModel = require('./card')
|
3
3
|
$ = require('jquery')
|
4
|
+
config = require('../../shared/config.json')
|
4
5
|
|
5
6
|
module.exports = class Cards extends Backbone.Collection
|
6
7
|
model: CardModel
|
7
8
|
query: {}
|
8
9
|
url: ()->
|
9
|
-
|
10
|
+
url = '/api/cards.json?' + $.param(@query)
|
11
|
+
if config.api_path
|
12
|
+
url = config.api_path + url
|
13
|
+
url
|
10
14
|
parse: (response)->
|
11
15
|
console.log response
|
12
16
|
@page = response.page
|
@@ -3,10 +3,10 @@ React = require('react')
|
|
3
3
|
Edit = require('./edit')
|
4
4
|
ModalTrigger = require('react-bootstrap/lib/ModalTrigger')
|
5
5
|
markdownIt = require('markdown-it')(linkify: true)
|
6
|
+
helpers = require('../helpers')
|
6
7
|
|
7
8
|
module.exports = React.createClass
|
8
9
|
displayName: 'Card'
|
9
|
-
isSafariOrUiWebView: /(iPhone|iPod|iPad).*AppleWebKit/i.test(navigator.userAgent)
|
10
10
|
|
11
11
|
componentDidMount: ->
|
12
12
|
@props.card.on 'change', @forceUpdate.bind(@, null)
|
@@ -38,7 +38,7 @@ module.exports = React.createClass
|
|
38
38
|
<strong>
|
39
39
|
{@props.card.get('title')}
|
40
40
|
</strong>
|
41
|
-
<span className='pull-right tools' style={{visibility: if
|
41
|
+
<span className='pull-right tools' style={{visibility: if helpers.isMobile() || @state.showTools then 'visible' else 'hidden'}}>
|
42
42
|
<ModalTrigger modal={<Edit card={@props.card} />}>
|
43
43
|
<a href="javascript:void(0)">
|
44
44
|
<i className='glyphicon glyphicon-edit' />
|
@@ -54,7 +54,7 @@ module.exports = React.createClass
|
|
54
54
|
<div style={overflow:'hidden',width:'100%',height:'75%',wordWrap:'break-word'}>
|
55
55
|
<div dangerouslySetInnerHTML={__html: markdownIt.render @props.card.get('content')} />
|
56
56
|
</div>
|
57
|
-
<div style={{visibility: if
|
57
|
+
<div style={{visibility: if helpers.isMobile() || @state.showTools then 'visible' else 'hidden'}}>
|
58
58
|
{
|
59
59
|
if @props.card.get("tags")
|
60
60
|
@props.card.get("tags").map (tag)->
|
@@ -3,6 +3,7 @@ React = require('react')
|
|
3
3
|
List = require('./list')
|
4
4
|
CardCollection = require('../models/cards')
|
5
5
|
CardModel = require('../models/card')
|
6
|
+
String = require('string')
|
6
7
|
config = require('../../shared/config.json')
|
7
8
|
|
8
9
|
module.exports = React.createClass
|
@@ -31,7 +32,7 @@ module.exports = React.createClass
|
|
31
32
|
title = []
|
32
33
|
for k, v of cards.query
|
33
34
|
if k != 'title'
|
34
|
-
title.push(k + ': ' + v)
|
35
|
+
title.push(String(k).capitalize() + ': ' + v)
|
35
36
|
title = title.join(', ')
|
36
37
|
title = 'search: ' + cards.query.title + ' (' + title + ')' if cards.query.title
|
37
38
|
title += ' - ' + config.title
|
@@ -36,7 +36,7 @@ module.exports = React.createClass
|
|
36
36
|
<nav className="navbar navbar-default" style={{padding:"0px",backgroundColor:"white",marginBottom:"5px"}}>
|
37
37
|
<div className="container-fluid">
|
38
38
|
<div className="navbar-header">
|
39
|
-
<a className="navbar-brand" href="#/" style={{paddingTop:"10px"}}>
|
39
|
+
<a className="navbar-brand" href={if config.icon_link then config.icon_link else "#/"} style={{paddingTop:"10px"}}>
|
40
40
|
<img alt="Brand" src="/images/icon.png" width="30" height="30" />
|
41
41
|
</a>
|
42
42
|
<a className="navbar-brand" href="#/">
|
@@ -3,6 +3,8 @@ $ = require('jquery')
|
|
3
3
|
React = require('react')
|
4
4
|
Cards = require('./cards')
|
5
5
|
CardCollection = require('../models/cards')
|
6
|
+
Pagination = require('./pagination')
|
7
|
+
helpers = require('../helpers')
|
6
8
|
|
7
9
|
module.exports = React.createClass
|
8
10
|
displayName: 'List'
|
@@ -33,11 +35,6 @@ module.exports = React.createClass
|
|
33
35
|
delete query.page
|
34
36
|
$.param(query)
|
35
37
|
|
36
|
-
pageParam: (page)->
|
37
|
-
query = $.extend {}, @props.cards.query
|
38
|
-
query = $.extend query, {page: page}
|
39
|
-
$.param(query)
|
40
|
-
|
41
38
|
tagParam: (tag)->
|
42
39
|
query = $.extend {}, @props.cards.query
|
43
40
|
query = $.extend query, {tags: tag}
|
@@ -78,48 +75,7 @@ module.exports = React.createClass
|
|
78
75
|
</li>
|
79
76
|
</ul>
|
80
77
|
else
|
81
|
-
<
|
82
|
-
<li>
|
83
|
-
{
|
84
|
-
if @props.cards.page
|
85
|
-
if @props.cards.page.current > 1
|
86
|
-
href = "/#/?" + @pageParam(@props.cards.page.current - 1)
|
87
|
-
else
|
88
|
-
href = "/#/?" + @pageParam(@props.cards.page.total)
|
89
|
-
else
|
90
|
-
href = "javascript:void(0)"
|
91
|
-
<a href={href} aria-label="Previous" style={{padding:'6px 12px'}}>
|
92
|
-
<span aria-hidden="true">«</span>
|
93
|
-
</a>
|
94
|
-
}
|
95
|
-
</li>
|
96
|
-
<li style={width:'4.0em',textAlign:'center'}>
|
97
|
-
{
|
98
|
-
if @props.cards.page
|
99
|
-
<a href={"/#/?" + @pageParam(@props.cards.page.current)} style={{padding:'6px 12px'}}>
|
100
|
-
{@props.cards.page.current} / {@props.cards.page.total}
|
101
|
-
</a>
|
102
|
-
else
|
103
|
-
<a href="javascript:void(0)" style={{padding:'6px 12px'}}>
|
104
|
-
<i className="glyphicon glyphicon-refresh glyphicon-refresh-animate" />
|
105
|
-
</a>
|
106
|
-
}
|
107
|
-
</li>
|
108
|
-
<li>
|
109
|
-
{
|
110
|
-
if @props.cards.page
|
111
|
-
if @props.cards.page.current < @props.cards.page.total
|
112
|
-
href = "/#/?" + @pageParam(@props.cards.page.current + 1)
|
113
|
-
else
|
114
|
-
href = "/#/?" + @pageParam(1)
|
115
|
-
else
|
116
|
-
href = "javascript:void(0)"
|
117
|
-
<a href={href} aria-label="Next" style={{padding:'6px 12px'}}>
|
118
|
-
<span aria-hidden="true">»</span>
|
119
|
-
</a>
|
120
|
-
}
|
121
|
-
</li>
|
122
|
-
</ul>
|
78
|
+
<Pagination cards={@props.cards} />
|
123
79
|
}
|
124
80
|
</div>
|
125
81
|
</div>
|
@@ -133,4 +89,12 @@ module.exports = React.createClass
|
|
133
89
|
</div>
|
134
90
|
}
|
135
91
|
<Cards cards={@props.cards} />
|
92
|
+
{
|
93
|
+
if !@props.card && helpers.isMobile()
|
94
|
+
<div className="row">
|
95
|
+
<div className="col-sm-12" style={{padding:"0px"}}>
|
96
|
+
<Pagination cards={@props.cards} />
|
97
|
+
</div>
|
98
|
+
</div>
|
99
|
+
}
|
136
100
|
</div>
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# @cjsx React.DOM
|
2
|
+
$ = require('jquery')
|
3
|
+
React = require('react')
|
4
|
+
|
5
|
+
module.exports = React.createClass
|
6
|
+
displayName: 'Pagination'
|
7
|
+
|
8
|
+
pageParam: (page)->
|
9
|
+
query = $.extend {}, @props.cards.query
|
10
|
+
query = $.extend query, {page: page}
|
11
|
+
$.param(query)
|
12
|
+
|
13
|
+
render: ->
|
14
|
+
<ul className="nav nav-pills pull-right">
|
15
|
+
<li>
|
16
|
+
{
|
17
|
+
if @props.cards.page
|
18
|
+
if @props.cards.page.current > 1
|
19
|
+
href = "/#/?" + @pageParam(@props.cards.page.current - 1)
|
20
|
+
else
|
21
|
+
href = "/#/?" + @pageParam(@props.cards.page.total)
|
22
|
+
else
|
23
|
+
href = "javascript:void(0)"
|
24
|
+
<a href={href} aria-label="Previous" style={{padding:'6px 12px'}}>
|
25
|
+
<span aria-hidden="true">«</span>
|
26
|
+
</a>
|
27
|
+
}
|
28
|
+
</li>
|
29
|
+
<li style={width:'4.0em',textAlign:'center'}>
|
30
|
+
{
|
31
|
+
if @props.cards.page
|
32
|
+
<a href={"/#/?" + @pageParam(@props.cards.page.current)} style={{padding:'6px 12px'}}>
|
33
|
+
{@props.cards.page.current} / {@props.cards.page.total}
|
34
|
+
</a>
|
35
|
+
else
|
36
|
+
<a href="javascript:void(0)" style={{padding:'6px 12px'}}>
|
37
|
+
<i className="glyphicon glyphicon-refresh glyphicon-refresh-animate" />
|
38
|
+
</a>
|
39
|
+
}
|
40
|
+
</li>
|
41
|
+
<li>
|
42
|
+
{
|
43
|
+
if @props.cards.page
|
44
|
+
if @props.cards.page.current < @props.cards.page.total
|
45
|
+
href = "/#/?" + @pageParam(@props.cards.page.current + 1)
|
46
|
+
else
|
47
|
+
href = "/#/?" + @pageParam(1)
|
48
|
+
else
|
49
|
+
href = "javascript:void(0)"
|
50
|
+
<a href={href} aria-label="Next" style={{padding:'6px 12px'}}>
|
51
|
+
<span aria-hidden="true">»</span>
|
52
|
+
</a>
|
53
|
+
}
|
54
|
+
</li>
|
55
|
+
</ul>
|
data/lib/carte/server.rb
CHANGED
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'carte/server'
|
2
|
+
include Carte::Server::Models
|
3
|
+
|
4
|
+
namespace :carte do
|
5
|
+
desc 'analyze data'
|
6
|
+
task :analyze do
|
7
|
+
title, content = {max: 0, min: 0}, {max: 0, min: 0}
|
8
|
+
count = Hash.new(0)
|
9
|
+
Card.all.each do |card|
|
10
|
+
title[:max] = [card.title.length, title[:max]].max
|
11
|
+
title[:min] = [card.title.length, title[:min]].min
|
12
|
+
content[:max] = [card.content.length, content[:max]].max
|
13
|
+
content[:min] = [card.content.length, content[:min]].min
|
14
|
+
if card.content == ''
|
15
|
+
puts "#{card.title} : content is empty"
|
16
|
+
end
|
17
|
+
count[card.title] += 1
|
18
|
+
end
|
19
|
+
puts "title: #{title}, content: #{content}"
|
20
|
+
count.each do |title, count|
|
21
|
+
puts "duplicate: #{title}: #{count} items" if count != 1
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
desc 'import pdic one line format data'
|
26
|
+
task :import do
|
27
|
+
entries = []
|
28
|
+
file = File.open(ENV['FILE'])
|
29
|
+
lines = file.read.split("\n")
|
30
|
+
lines.each_slice(2) do |title, content|
|
31
|
+
Card.create!(title: title, content: content)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
desc 'export data as pdic one line format'
|
36
|
+
task :export do
|
37
|
+
Card.all.each do |card|
|
38
|
+
puts card.title
|
39
|
+
puts card.content
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
desc 'reset database'
|
44
|
+
task :reset do
|
45
|
+
Card.delete_all
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'carte/server/validators/array_validator'
|
@@ -0,0 +1,24 @@
|
|
1
|
+
|
2
|
+
class ArrayValidator < ActiveModel::EachValidator
|
3
|
+
def validate_each(record, attribute, values)
|
4
|
+
[values].flatten.each do |value|
|
5
|
+
options.each do |key, args|
|
6
|
+
validator_options = { attributes: attribute }
|
7
|
+
validator_options.merge!(args) if args.is_a?(Hash)
|
8
|
+
|
9
|
+
next if value.nil? && validator_options[:allow_nil]
|
10
|
+
next if value.blank? && validator_options[:allow_blank]
|
11
|
+
|
12
|
+
validator_class_name = "#{key.to_s.camelize}Validator"
|
13
|
+
validator_class = begin
|
14
|
+
validator_class_name.constantize
|
15
|
+
rescue NameError
|
16
|
+
"ActiveModel::Validations::#{validator_class_name}".constantize
|
17
|
+
end
|
18
|
+
|
19
|
+
validator = validator_class.new(validator_options)
|
20
|
+
validator.validate_each(record, attribute, value)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
data/lib/carte/server/version.rb
CHANGED
data/package.json
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
{
|
2
2
|
"name": "carte-client",
|
3
3
|
"description": "something like dictionary, wiki, or information card",
|
4
|
-
"version": "0.0.
|
4
|
+
"version": "0.0.8",
|
5
5
|
"main": "lib/carte.coffee",
|
6
6
|
"scripts": {
|
7
7
|
"test": "echo \"Error: no test specified\" && exit 1"
|
@@ -35,6 +35,7 @@
|
|
35
35
|
"react": "^0.13.2",
|
36
36
|
"react-bootstrap": "^0.21.0",
|
37
37
|
"react-tagsinput": "^1.3.2",
|
38
|
+
"string": "^3.1.1",
|
38
39
|
"vinyl-source-stream": "^1.1.0",
|
39
40
|
"watchify": "^3.1.2"
|
40
41
|
}
|
data/spec/server_spec.rb
CHANGED
@@ -10,7 +10,7 @@ end
|
|
10
10
|
|
11
11
|
class DictionaryClient
|
12
12
|
include HTTParty
|
13
|
-
base_uri 'http://localhost/api/'
|
13
|
+
base_uri 'http://localhost:9393/api/'
|
14
14
|
format :json
|
15
15
|
end
|
16
16
|
|
@@ -40,32 +40,44 @@ describe 'API' do
|
|
40
40
|
it 'returns error when the title is not specified' do
|
41
41
|
response = client.post('/cards.json', body: {content: 'content1'}.to_json)
|
42
42
|
expect(response.code).to eq(400)
|
43
|
-
expect(response['card']['errors']).to eq({'title' => ['
|
43
|
+
expect(response['card']['errors']).to eq({'title' => ["can't be blank"]})
|
44
44
|
end
|
45
45
|
|
46
46
|
it 'returns error when the content is not specified' do
|
47
47
|
response = client.post('/cards.json', body: {title: 'card1'}.to_json)
|
48
48
|
expect(response.code).to eq(400)
|
49
|
-
expect(response['card']['errors']).to eq({'content' => ['
|
49
|
+
expect(response['card']['errors']).to eq({'content' => ["can't be blank"]})
|
50
50
|
end
|
51
51
|
|
52
52
|
it 'returns error when the title is not unique' do
|
53
53
|
response = client.post('/cards.json', body: {title: 'card1', content: 'content1'}.to_json)
|
54
54
|
response = client.post('/cards.json', body: {title: 'card1', content: 'content1'}.to_json)
|
55
55
|
expect(response.code).to eq(400)
|
56
|
-
expect(response['card']['errors']).to eq({'title' => ['
|
56
|
+
expect(response['card']['errors']).to eq({'title' => ['is already taken']})
|
57
57
|
end
|
58
58
|
|
59
59
|
it 'returns error when the title is too long' do
|
60
60
|
response = client.post('/cards.json', body: {title: 'w' * 71, content: 'content1'}.to_json)
|
61
61
|
expect(response.code).to eq(400)
|
62
|
-
expect(response['card']['errors']).to eq({'title' => ['
|
62
|
+
expect(response['card']['errors']).to eq({'title' => ['is too long (maximum is 70 characters)']})
|
63
63
|
end
|
64
64
|
|
65
65
|
it 'returns error when the content is too long' do
|
66
66
|
response = client.post('/cards.json', body: {title: 'card1', content: 'd' * 561}.to_json)
|
67
67
|
expect(response.code).to eq(400)
|
68
|
-
expect(response['card']['errors']).to eq({'content' => ['
|
68
|
+
expect(response['card']['errors']).to eq({'content' => ['is too long (maximum is 560 characters)']})
|
69
|
+
end
|
70
|
+
|
71
|
+
it 'returns error when the tags is too many' do
|
72
|
+
response = client.post('/cards.json', body: {title: 'card1', content: 'content1', tags: %w(tag1 tag2 tag3 tag4)}.to_json)
|
73
|
+
expect(response.code).to eq(400)
|
74
|
+
expect(response['card']['errors']).to eq({'tags' => ['are too many (maximum is 3 tags)']})
|
75
|
+
end
|
76
|
+
|
77
|
+
it 'returns error when one of the tags is too long' do
|
78
|
+
response = client.post('/cards.json', body: {title: 'card1', content: 'content1', tags: ['a' * 11]}.to_json)
|
79
|
+
expect(response.code).to eq(400)
|
80
|
+
expect(response['card']['errors']).to eq({'tags' => ['is too long (maximum is 10 characters)']})
|
69
81
|
end
|
70
82
|
end
|
71
83
|
end
|
@@ -126,21 +138,35 @@ describe 'API' do
|
|
126
138
|
response = client.post('/cards.json', body: {title: 'card2', content: 'content2'}.to_json)
|
127
139
|
response = client.put("/cards/card2.json", body: {new_title: 'card1', content: 'content1'}.to_json)
|
128
140
|
expect(response.code).to eq(400)
|
129
|
-
expect(response['card']['errors']).to eq({'title' => ['
|
141
|
+
expect(response['card']['errors']).to eq({'title' => ['is already taken']})
|
130
142
|
end
|
131
143
|
|
132
144
|
it 'returns error when the title is too long' do
|
133
145
|
response = client.post('/cards.json', body: {title: 'card1', content: 'content1'}.to_json)
|
134
146
|
response = client.put("/cards/card1.json", body: {new_title: 'w' * 71}.to_json)
|
135
147
|
expect(response.code).to eq(400)
|
136
|
-
expect(response['card']['errors']).to eq({'title' => ['
|
148
|
+
expect(response['card']['errors']).to eq({'title' => ['is too long (maximum is 70 characters)']})
|
137
149
|
end
|
138
150
|
|
139
151
|
it 'returns error when the content is too long' do
|
140
152
|
response = client.post('/cards.json', body: {title: 'card1', content: 'content1'}.to_json)
|
141
153
|
response = client.put("/cards/card1.json", body: {content: 'd' * 561}.to_json)
|
142
154
|
expect(response.code).to eq(400)
|
143
|
-
expect(response['card']['errors']).to eq({'content' => ['
|
155
|
+
expect(response['card']['errors']).to eq({'content' => ['is too long (maximum is 560 characters)']})
|
156
|
+
end
|
157
|
+
|
158
|
+
it 'returns error when the tags is too many' do
|
159
|
+
response = client.post('/cards.json', body: {title: 'card1', content: 'content1'}.to_json)
|
160
|
+
response = client.put("/cards/card1.json", body: {tags: %w(tag1 tag2 tag3 tag4)}.to_json)
|
161
|
+
expect(response.code).to eq(400)
|
162
|
+
expect(response['card']['errors']).to eq({'tags' => ['are too many (maximum is 3 tags)']})
|
163
|
+
end
|
164
|
+
|
165
|
+
it 'returns error when one of the tags is too long' do
|
166
|
+
response = client.post('/cards.json', body: {title: 'card1', content: 'content1'}.to_json)
|
167
|
+
response = client.put("/cards/card1.json", body: {tags: ['a' * 11]}.to_json)
|
168
|
+
expect(response.code).to eq(400)
|
169
|
+
expect(response['card']['errors']).to eq({'tags' => ['is too long (maximum is 10 characters)']})
|
144
170
|
end
|
145
171
|
end
|
146
172
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: carte-server
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.8
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- tily
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-05-
|
11
|
+
date: 2015-05-03 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -200,6 +200,7 @@ extensions: []
|
|
200
200
|
extra_rdoc_files: []
|
201
201
|
files:
|
202
202
|
- .gitignore
|
203
|
+
- .rspec
|
203
204
|
- Gemfile
|
204
205
|
- LICENSE.txt
|
205
206
|
- README.md
|
@@ -211,6 +212,7 @@ files:
|
|
211
212
|
- lib/carte.coffee
|
212
213
|
- lib/carte.rb
|
213
214
|
- lib/carte/client.coffee
|
215
|
+
- lib/carte/client/helpers.coffee
|
214
216
|
- lib/carte/client/models/card.coffee
|
215
217
|
- lib/carte/client/models/cards.coffee
|
216
218
|
- lib/carte/client/router.coffee
|
@@ -222,10 +224,14 @@ files:
|
|
222
224
|
- lib/carte/client/views/footer.cjsx
|
223
225
|
- lib/carte/client/views/header.cjsx
|
224
226
|
- lib/carte/client/views/list.cjsx
|
227
|
+
- lib/carte/client/views/pagination.cjsx
|
225
228
|
- lib/carte/server.rb
|
226
229
|
- lib/carte/server/models.rb
|
227
230
|
- lib/carte/server/models/card.rb
|
228
231
|
- lib/carte/server/models/history.rb
|
232
|
+
- lib/carte/server/tasks.rb
|
233
|
+
- lib/carte/server/validators.rb
|
234
|
+
- lib/carte/server/validators/array_validator.rb
|
229
235
|
- lib/carte/server/version.rb
|
230
236
|
- lib/carte/server/views/cards.builder
|
231
237
|
- lib/carte/server/views/index.haml
|