carte-server 0.0.7 → 0.0.8
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 +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
|