Commit 043bbbd13b70409a9cb6d837a54144ed661bd28e
Exists in
staging
and in
7 other branches
Merge branch 'noosfero_grape_api' into rails3_api
Conflicts: app/models/article.rb app/models/user.rb config.ru
Showing
13 changed files
with
503 additions
and
0 deletions
Show diff stats
app/models/article.rb
@@ -102,6 +102,16 @@ class Article < ActiveRecord::Base | @@ -102,6 +102,16 @@ class Article < ActiveRecord::Base | ||
102 | {:include => 'categories_including_virtual', :conditions => { 'categories.id' => category.id }} | 102 | {:include => 'categories_including_virtual', :conditions => { 'categories.id' => category.id }} |
103 | } | 103 | } |
104 | 104 | ||
105 | + #FIXME make this test | ||
106 | + scope :newer_than, lambda { |reference_id| | ||
107 | + {:conditions => ["articles.id > #{reference_id}"]} | ||
108 | + } | ||
109 | + | ||
110 | + #FIXME make this test | ||
111 | + scope :older_than, lambda { |reference_id| | ||
112 | + {:conditions => ["articles.id < #{reference_id}"]} | ||
113 | + } | ||
114 | + | ||
105 | scope :by_range, lambda { |range| { | 115 | scope :by_range, lambda { |range| { |
106 | :conditions => [ | 116 | :conditions => [ |
107 | 'published_at BETWEEN :start_date AND :end_date', { :start_date => range.first, :end_date => range.last } | 117 | 'published_at BETWEEN :start_date AND :end_date', { :start_date => range.first, :end_date => range.last } |
@@ -658,6 +668,11 @@ class Article < ActiveRecord::Base | @@ -658,6 +668,11 @@ class Article < ActiveRecord::Base | ||
658 | person ? person.id : nil | 668 | person ? person.id : nil |
659 | end | 669 | end |
660 | 670 | ||
671 | + #FIXME make this test | ||
672 | + def author_custom_image(size = :icon) | ||
673 | + author ? author.profile_custom_image(size) : nil | ||
674 | + end | ||
675 | + | ||
661 | def version_license(version_number = nil) | 676 | def version_license(version_number = nil) |
662 | return license if version_number.nil? | 677 | return license if version_number.nil? |
663 | profile.environment.licenses.find_by_id(versions.find_by_version(version_number).license_id) | 678 | profile.environment.licenses.find_by_id(versions.find_by_version(version_number).license_id) |
app/models/comment.rb
@@ -20,6 +20,17 @@ class Comment < ActiveRecord::Base | @@ -20,6 +20,17 @@ class Comment < ActiveRecord::Base | ||
20 | 20 | ||
21 | scope :without_reply, :conditions => ['reply_of_id IS NULL'] | 21 | scope :without_reply, :conditions => ['reply_of_id IS NULL'] |
22 | 22 | ||
23 | + #FIXME make this test | ||
24 | + named_scope :newer_than, lambda { |reference_id| | ||
25 | + {:conditions => ["comments.id > #{reference_id}"]} | ||
26 | + } | ||
27 | + | ||
28 | + #FIXME make this test | ||
29 | + named_scope :older_than, lambda { |reference_id| | ||
30 | + {:conditions => ["comments.id < #{reference_id}"]} | ||
31 | + } | ||
32 | + | ||
33 | + | ||
23 | # unauthenticated authors: | 34 | # unauthenticated authors: |
24 | validates_presence_of :name, :if => (lambda { |record| !record.email.blank? }) | 35 | validates_presence_of :name, :if => (lambda { |record| !record.email.blank? }) |
25 | validates_presence_of :email, :if => (lambda { |record| !record.name.blank? }) | 36 | validates_presence_of :email, :if => (lambda { |record| !record.name.blank? }) |
@@ -63,6 +74,11 @@ class Comment < ActiveRecord::Base | @@ -63,6 +74,11 @@ class Comment < ActiveRecord::Base | ||
63 | author ? author.url : nil | 74 | author ? author.url : nil |
64 | end | 75 | end |
65 | 76 | ||
77 | + #FIXME make this test | ||
78 | + def author_custom_image(size = :icon) | ||
79 | + author ? author.profile_custom_image(size) : nil | ||
80 | + end | ||
81 | + | ||
66 | def url | 82 | def url |
67 | article.view_url.merge(:anchor => anchor) | 83 | article.view_url.merge(:anchor => anchor) |
68 | end | 84 | end |
app/models/profile.rb
@@ -877,6 +877,13 @@ private :generate_url, :url_options | @@ -877,6 +877,13 @@ private :generate_url, :url_options | ||
877 | image.public_filename(:icon) if image.present? | 877 | image.public_filename(:icon) if image.present? |
878 | end | 878 | end |
879 | 879 | ||
880 | + #FIXME make this test | ||
881 | + def profile_custom_image(size = :icon) | ||
882 | + image_path = profile_custom_icon if size == :icon | ||
883 | + image_path ||= image.public_filename(size) if image.present? | ||
884 | + image_path | ||
885 | + end | ||
886 | + | ||
880 | def jid(options = {}) | 887 | def jid(options = {}) |
881 | domain = options[:domain] || environment.default_hostname | 888 | domain = options[:domain] || environment.default_hostname |
882 | "#{identifier}@#{domain}" | 889 | "#{identifier}@#{domain}" |
app/models/user.rb
1 | require 'digest/sha1' | 1 | require 'digest/sha1' |
2 | require 'user_activation_job' | 2 | require 'user_activation_job' |
3 | +require 'securerandom' | ||
3 | 4 | ||
4 | # User models the system users, and is generated by the acts_as_authenticated | 5 | # User models the system users, and is generated by the acts_as_authenticated |
5 | # Rails generator. | 6 | # Rails generator. |
@@ -138,6 +139,18 @@ class User < ActiveRecord::Base | @@ -138,6 +139,18 @@ class User < ActiveRecord::Base | ||
138 | u && u.authenticated?(password) ? u : nil | 139 | u && u.authenticated?(password) ? u : nil |
139 | end | 140 | end |
140 | 141 | ||
142 | + #FIXME make this test | ||
143 | + def generate_private_token! | ||
144 | + self.private_token = SecureRandom.hex | ||
145 | + self.private_token_generated_at = DateTime.now | ||
146 | + save(false) | ||
147 | + end | ||
148 | + | ||
149 | + #FIXME make this test | ||
150 | + def private_token_expired? | ||
151 | + self.generate_private_token! if self.private_token.nil? || (self.private_token_generated_at + 2.weeks < DateTime.now) | ||
152 | + end | ||
153 | + | ||
141 | # Activates the user in the database. | 154 | # Activates the user in the database. |
142 | def activate | 155 | def activate |
143 | return false unless self.person | 156 | return false unless self.person |
config.ru
@@ -2,3 +2,14 @@ | @@ -2,3 +2,14 @@ | ||
2 | 2 | ||
3 | require ::File.expand_path('../config/environment', __FILE__) | 3 | require ::File.expand_path('../config/environment', __FILE__) |
4 | run Noosfero::Application | 4 | run Noosfero::Application |
5 | + | ||
6 | +rails_app = Rack::Builder.new do | ||
7 | + use Rails::Rack::LogTailer | ||
8 | + use Rails::Rack::Static | ||
9 | + run ActionController::Dispatcher.new | ||
10 | +end | ||
11 | + | ||
12 | +run Rack::Cascade.new([ | ||
13 | + API::API, | ||
14 | + rails_app | ||
15 | +]) | ||
5 | \ No newline at end of file | 16 | \ No newline at end of file |
db/migrate/20140407013817_add_private_token_info_to_users.rb
0 → 100644
@@ -0,0 +1,11 @@ | @@ -0,0 +1,11 @@ | ||
1 | +class AddPrivateTokenInfoToUsers < ActiveRecord::Migration | ||
2 | + def self.up | ||
3 | + add_column :users, :private_token, :string | ||
4 | + add_column :users, :private_token_generated_at, :datetime | ||
5 | + end | ||
6 | + | ||
7 | + def self.down | ||
8 | + remove_column :users, :private_token | ||
9 | + remove_column :users, :private_token_generated_at | ||
10 | + end | ||
11 | +end |
@@ -0,0 +1,19 @@ | @@ -0,0 +1,19 @@ | ||
1 | +require 'grape' | ||
2 | +Dir["#{Rails.root}/lib/api/*.rb"].each {|file| require file} | ||
3 | + | ||
4 | +module API | ||
5 | + class API < Grape::API | ||
6 | + version 'v1' | ||
7 | + prefix "api" | ||
8 | + format :json | ||
9 | + content_type :txt, "text/plain" | ||
10 | + | ||
11 | + helpers APIHelpers | ||
12 | + | ||
13 | + mount V1::Articles | ||
14 | + mount V1::Comments | ||
15 | + mount V1::Users | ||
16 | + mount Session | ||
17 | + | ||
18 | + end | ||
19 | +end |
@@ -0,0 +1,59 @@ | @@ -0,0 +1,59 @@ | ||
1 | +module API | ||
2 | + module Entities | ||
3 | + class Article < Grape::Entity | ||
4 | + root 'articles', 'article' | ||
5 | + expose :id, :body, :created_at | ||
6 | + expose :title, :documentation => {:type => "String", :desc => "Title of the article"} | ||
7 | + | ||
8 | + expose :author do |article, options| | ||
9 | + { | ||
10 | + :id => article.author_id, | ||
11 | + :name => article.author_name, | ||
12 | + :icon_url => article.author_custom_image(:icon), | ||
13 | + :minor_url => article.author_custom_image(:minor), | ||
14 | + :portrait_url => article.author_custom_image(:portrait), | ||
15 | + :thumb_url => article.author_custom_image(:thumb), | ||
16 | + } | ||
17 | + end | ||
18 | + | ||
19 | + expose :profile do |article, options| | ||
20 | + { | ||
21 | + :id => article.profile.id, | ||
22 | + :name => article.profile.name, | ||
23 | + :icon_url => article.profile.profile_custom_image(:icon), | ||
24 | + :minor_url => article.profile.profile_custom_image(:minor), | ||
25 | + :portrait_url => article.profile.profile_custom_image(:portrait), | ||
26 | + :thumb_url => article.profile.profile_custom_image(:thumb), | ||
27 | + } | ||
28 | + end | ||
29 | + | ||
30 | + end | ||
31 | + | ||
32 | + class Comment < Grape::Entity | ||
33 | + root 'comments', 'comment' | ||
34 | + expose :body, :title, :created_at, :id | ||
35 | + | ||
36 | + expose :author do |comment, options| | ||
37 | + { | ||
38 | + :id => comment.author_id, | ||
39 | + :name => comment.author_name, | ||
40 | + :icon_url => comment.author_custom_image(:icon), | ||
41 | + :minor_url => comment.author_custom_image(:minor), | ||
42 | + :portrait_url => comment.author_custom_image(:portrait), | ||
43 | + :thumb_url => comment.author_custom_image(:thumb), | ||
44 | + } | ||
45 | + end | ||
46 | + | ||
47 | + end | ||
48 | + | ||
49 | + class User < Grape::Entity | ||
50 | + root 'users', 'user' | ||
51 | + expose :login | ||
52 | + end | ||
53 | + | ||
54 | + class UserLogin < User | ||
55 | + expose :private_token | ||
56 | + end | ||
57 | + | ||
58 | + end | ||
59 | +end |
@@ -0,0 +1,181 @@ | @@ -0,0 +1,181 @@ | ||
1 | +module API | ||
2 | + module APIHelpers | ||
3 | + PRIVATE_TOKEN_PARAM = :private_token | ||
4 | + | ||
5 | + def logger | ||
6 | + API.logger | ||
7 | + end | ||
8 | + | ||
9 | + def current_user | ||
10 | + private_token = params[PRIVATE_TOKEN_PARAM].to_s | ||
11 | + @current_user ||= User.find_by_private_token(private_token) | ||
12 | + @current_user = nil if !@current_user.nil? && @current_user.private_token_expired? | ||
13 | + @current_user | ||
14 | + end | ||
15 | + | ||
16 | + def current_person | ||
17 | + current_user.person unless current_user.nil? | ||
18 | + end | ||
19 | + | ||
20 | + def logout | ||
21 | + @current_user = nil | ||
22 | + end | ||
23 | + | ||
24 | + def environment | ||
25 | + @environment | ||
26 | + end | ||
27 | + | ||
28 | + def limit | ||
29 | + limit = params[:limit].to_i | ||
30 | + limit = default_limit if limit <= 0 | ||
31 | + limit | ||
32 | + end | ||
33 | + | ||
34 | + def period(from_date, until_date) | ||
35 | + if from_date.nil? | ||
36 | + begin_period = Time.at(0).to_datetime | ||
37 | + end_period = until_date.nil? ? DateTime.now : until_date | ||
38 | + else | ||
39 | + begin_period = from_date | ||
40 | + end_period = DateTime.now | ||
41 | + end | ||
42 | + | ||
43 | + begin_period...end_period | ||
44 | + end | ||
45 | + | ||
46 | + def parse_content_type(content_type) | ||
47 | + return nil if content_type.blank? | ||
48 | + content_type.split(',').map do |content_type| | ||
49 | + content_type.camelcase | ||
50 | + end | ||
51 | + end | ||
52 | + | ||
53 | + | ||
54 | + def make_conditions_with_parameter(params = {}) | ||
55 | + conditions = {} | ||
56 | + from_date = DateTime.parse(params[:from]) if params[:from] | ||
57 | + until_date = DateTime.parse(params[:until]) if params[:until] | ||
58 | + | ||
59 | + conditions[:type] = parse_content_type(params[:content_type]) unless params[:content_type].nil? | ||
60 | + | ||
61 | + conditions[:created_at] = period(from_date, until_date) | ||
62 | + | ||
63 | + conditions | ||
64 | + end | ||
65 | + | ||
66 | +#FIXME see if its needed | ||
67 | +# def paginate(relation) | ||
68 | +# per_page = params[:per_page].to_i | ||
69 | +# paginated = relation.page(params[:page]).per(per_page) | ||
70 | +# add_pagination_headers(paginated, per_page) | ||
71 | +# | ||
72 | +# paginated | ||
73 | +# end | ||
74 | + | ||
75 | + def authenticate! | ||
76 | + unauthorized! unless current_user | ||
77 | + end | ||
78 | + | ||
79 | +#FIXME see if its needed | ||
80 | +# def authenticated_as_admin! | ||
81 | +# forbidden! unless current_user.is_admin? | ||
82 | +# end | ||
83 | +# | ||
84 | +#FIXME see if its needed | ||
85 | +# def authorize! action, subject | ||
86 | +# unless abilities.allowed?(current_user, action, subject) | ||
87 | +# forbidden! | ||
88 | +# end | ||
89 | +# end | ||
90 | +# | ||
91 | +#FIXME see if its needed | ||
92 | +# def can?(object, action, subject) | ||
93 | +# abilities.allowed?(object, action, subject) | ||
94 | +# end | ||
95 | + | ||
96 | + # Checks the occurrences of required attributes, each attribute must be present in the params hash | ||
97 | + # or a Bad Request error is invoked. | ||
98 | + # | ||
99 | + # Parameters: | ||
100 | + # keys (required) - A hash consisting of keys that must be present | ||
101 | + def required_attributes!(keys) | ||
102 | + keys.each do |key| | ||
103 | + bad_request!(key) unless params[key].present? | ||
104 | + end | ||
105 | + end | ||
106 | + | ||
107 | + # Checks the occurrences of uniqueness of attributes, each attribute must be present in the params hash | ||
108 | + # or a Bad Request error is invoked. | ||
109 | + # | ||
110 | + # Parameters: | ||
111 | + # keys (unique) - A hash consisting of keys that must be unique | ||
112 | + def unique_attributes!(obj, keys) | ||
113 | + keys.each do |key| | ||
114 | + cant_be_saved_request!(key) if obj.send("find_by_#{key.to_s}", params[key]) | ||
115 | + end | ||
116 | + end | ||
117 | + | ||
118 | + def attributes_for_keys(keys) | ||
119 | + attrs = {} | ||
120 | + keys.each do |key| | ||
121 | + attrs[key] = params[key] if params[key].present? or (params.has_key?(key) and params[key] == false) | ||
122 | + end | ||
123 | + attrs | ||
124 | + end | ||
125 | + | ||
126 | + # error helpers | ||
127 | + def forbidden! | ||
128 | + render_api_error!('403 Forbidden', 403) | ||
129 | + end | ||
130 | + | ||
131 | + def cant_be_saved_request!(attribute) | ||
132 | + message = _("(Invalid request) #{attribute} can't be saved") | ||
133 | + render_api_error!(message, 400) | ||
134 | + end | ||
135 | + | ||
136 | + def bad_request!(attribute) | ||
137 | + message = _("(Bad request) #{attribute} not given") | ||
138 | + render_api_error!(message, 400) | ||
139 | + end | ||
140 | + | ||
141 | + def something_wrong! | ||
142 | + message = _("Something wrong happened") | ||
143 | + render_api_error!(message, 400) | ||
144 | + end | ||
145 | + | ||
146 | + def unauthorized! | ||
147 | + render_api_error!(_('Unauthorized'), 401) | ||
148 | + end | ||
149 | + | ||
150 | + def not_allowed! | ||
151 | + render_api_error!(_('Method Not Allowed'), 405) | ||
152 | + end | ||
153 | + | ||
154 | + def render_api_error!(message, status) | ||
155 | + error!({'message' => message, :code => status}, status) | ||
156 | + end | ||
157 | + | ||
158 | + protected | ||
159 | + | ||
160 | + def detect_stuff_by_domain | ||
161 | + @domain = Domain.find_by_name(request.host) | ||
162 | + if @domain.nil? | ||
163 | + @environment = Environment.default | ||
164 | + if @environment.nil? && Rails.env.development? | ||
165 | + # This should only happen in development ... | ||
166 | + @environment = Environment.create!(:name => "Noosfero", :is_default => true) | ||
167 | + end | ||
168 | + else | ||
169 | + @environment = @domain.environment | ||
170 | + end | ||
171 | + end | ||
172 | + | ||
173 | + private | ||
174 | + | ||
175 | + def default_limit | ||
176 | + 20 | ||
177 | + end | ||
178 | + | ||
179 | + | ||
180 | + end | ||
181 | +end |
@@ -0,0 +1,44 @@ | @@ -0,0 +1,44 @@ | ||
1 | +module API | ||
2 | + | ||
3 | + class Session < Grape::API | ||
4 | + | ||
5 | + # Login to get token | ||
6 | + # | ||
7 | + # Parameters: | ||
8 | + # login (*required) - user login or email | ||
9 | + # password (required) - user password | ||
10 | + # | ||
11 | + # Example Request: | ||
12 | + # POST /login?login=some&password=pass | ||
13 | + post "/login" do | ||
14 | + user ||= User.authenticate(params[:login], params[:password], environment) | ||
15 | + | ||
16 | + return unauthorized! unless user | ||
17 | + user.generate_private_token! | ||
18 | + present user, :with => Entities::UserLogin | ||
19 | + end | ||
20 | + | ||
21 | + # Create user. | ||
22 | + # | ||
23 | + # Parameters: | ||
24 | + # email (required) - Email | ||
25 | + # password (required) - Password | ||
26 | + # login - login | ||
27 | + # Example Request: | ||
28 | + # POST /register?email=some@mail.com&password=pas&login=some | ||
29 | + post "/register" do | ||
30 | + required_attributes! [:email, :login, :password] | ||
31 | + unique_attributes! User, [:email, :login] | ||
32 | + attrs = attributes_for_keys [:email, :login, :password] | ||
33 | + attrs[:password_confirmation] = attrs[:password] | ||
34 | + user = User.new(attrs) | ||
35 | + if user.save | ||
36 | + user.activate | ||
37 | + present user, :with => Entities::User | ||
38 | + else | ||
39 | + something_wrong! | ||
40 | + end | ||
41 | + end | ||
42 | + | ||
43 | + end | ||
44 | +end |
@@ -0,0 +1,60 @@ | @@ -0,0 +1,60 @@ | ||
1 | +module API | ||
2 | + module V1 | ||
3 | + class Articles < Grape::API | ||
4 | + before { detect_stuff_by_domain } | ||
5 | + before { authenticate! } | ||
6 | + | ||
7 | + resource :articles do | ||
8 | + | ||
9 | + # Collect comments from articles | ||
10 | + # | ||
11 | + # Parameters: | ||
12 | + # from - date where the search will begin. If nothing is passed the default date will be the date of the first article created | ||
13 | + # oldest - Collect the oldest comments from reference_id comment. If nothing is passed the newest comments are collected | ||
14 | + # limit - amount of comments returned. The default value is 20 | ||
15 | + # | ||
16 | + # Example Request: | ||
17 | + # GET /articles?from=2013-04-04-14:41:43&until=2014-04-04-14:41:43&limit=10&content_type=Hub | ||
18 | +# desc 'Articles.', { | ||
19 | +# :params => API::Entities::Article.documentation | ||
20 | +# } | ||
21 | + get do | ||
22 | + | ||
23 | + conditions = make_conditions_with_parameter(params) | ||
24 | + | ||
25 | + if params[:reference_id] | ||
26 | + articles = environment.articles.send("#{params.key?(:oldest) ? 'older_than' : 'newer_than'}", params[:reference_id]).find(:all, :conditions => conditions, :limit => limit, :order => "created_at DESC") | ||
27 | + else | ||
28 | + articles = environment.articles.find(:all, :conditions => conditions, :limit => limit, :order => "created_at DESC") | ||
29 | + end | ||
30 | + present articles, :with => Entities::Article | ||
31 | + end | ||
32 | + | ||
33 | + desc "Return the article id" | ||
34 | + get ':id' do | ||
35 | + present environment.articles.find(params[:id]), :with => Entities::Article | ||
36 | + end | ||
37 | + | ||
38 | + get ':id/children' do | ||
39 | + from_date = DateTime.parse(params[:from]) if params[:from] | ||
40 | + until_date = DateTime.parse(params[:until]) if params[:until] | ||
41 | + | ||
42 | + conditions = make_conditions_with_parameter(params) | ||
43 | + if params[:reference_id] | ||
44 | + articles = environment.articles.find(params[:id]).children.send("#{params.key?(:oldest) ? 'older_than' : 'newer_than'}", params[:reference_id]).find(:all, :conditions => conditions, :limit => limit, :order => "created_at DESC") | ||
45 | + else | ||
46 | + articles = environment.articles.find(params[:id]).children.find(:all, :conditions => conditions, :limit => limit, :order => "created_at DESC") | ||
47 | + end | ||
48 | + present articles, :with => Entities::Article | ||
49 | + end | ||
50 | + | ||
51 | + get ':id/children/:child_id' do | ||
52 | + present environment.articles.find(params[:id]).children.find(params[:child_id]), :with => Entities::Article | ||
53 | + end | ||
54 | + | ||
55 | + | ||
56 | + end | ||
57 | + | ||
58 | + end | ||
59 | + end | ||
60 | +end |
@@ -0,0 +1,44 @@ | @@ -0,0 +1,44 @@ | ||
1 | +module API | ||
2 | + module V1 | ||
3 | + class Comments < Grape::API | ||
4 | + | ||
5 | + before { detect_stuff_by_domain } | ||
6 | + before { authenticate! } | ||
7 | + | ||
8 | + resource :articles do | ||
9 | + # Collect comments from articles | ||
10 | + # | ||
11 | + # Parameters: | ||
12 | + # reference_id - comment id used as reference to collect comment | ||
13 | + # oldest - Collect the oldest comments from reference_id comment. If nothing is passed the newest comments are collected | ||
14 | + # limit - amount of comments returned. The default value is 20 | ||
15 | + # | ||
16 | + # Example Request: | ||
17 | + # GET /articles/12/comments?oldest&limit=10&reference_id=23 | ||
18 | + get ":id/comments" do | ||
19 | + | ||
20 | + conditions = make_conditions_with_parameter(params) | ||
21 | + | ||
22 | + if params[:reference_id] | ||
23 | + comments = environment.articles.find(params[:id]).comments.send("#{params.key?(:oldest) ? 'older_than' : 'newer_than'}", params[:reference_id]).find(:all, :conditions => conditions, :limit => limit, :order => "created_at DESC") | ||
24 | + else | ||
25 | + comments = environment.articles.find(params[:id]).comments.find(:all, :conditions => conditions, :limit => limit, :order => "created_at DESC") | ||
26 | + end | ||
27 | + present comments, :with => Entities::Comment | ||
28 | + | ||
29 | + end | ||
30 | + | ||
31 | + get ":id/comments/:comment_id" do | ||
32 | + present environment.articles.find(params[:id]).comments.find(params[:comment_id]), :with => Entities::Comment | ||
33 | + end | ||
34 | + | ||
35 | + # Example Request: | ||
36 | + # POST api/v1/articles/12/comments?private_toke=234298743290432&body=new comment | ||
37 | + post ":id/comments" do | ||
38 | + present environment.articles.find(params[:id]).comments.create(:author => current_person, :body => params[:body]), :with => Entities::Comment | ||
39 | + end | ||
40 | + end | ||
41 | + | ||
42 | + end | ||
43 | + end | ||
44 | +end |
@@ -0,0 +1,23 @@ | @@ -0,0 +1,23 @@ | ||
1 | +module API | ||
2 | + module V1 | ||
3 | + class Users < Grape::API | ||
4 | + | ||
5 | + before { authenticate! } | ||
6 | + | ||
7 | + resource :users do | ||
8 | + | ||
9 | + #FIXME make the pagination | ||
10 | + #FIXME put it on environment context | ||
11 | + get do | ||
12 | + present User.all, :with => Entities::User | ||
13 | + end | ||
14 | + | ||
15 | + get ":id" do | ||
16 | + present User.find(params[:id]), :with => Entities::User | ||
17 | + end | ||
18 | + | ||
19 | + end | ||
20 | + | ||
21 | + end | ||
22 | + end | ||
23 | +end |