Commit b4960cda06578e5516b9cfd560f51c872cbfa69e
Exists in
theme-brasil-digital-from-staging
and in
9 other branches
Merge branch 'rails3_api' into rails3_stable
Showing
18 changed files
with
748 additions
and
1 deletions
Show diff stats
Gemfile
... | ... | @@ -15,6 +15,7 @@ gem 'thin' |
15 | 15 | gem 'hpricot' |
16 | 16 | gem 'nokogiri' |
17 | 17 | gem 'rake', :require => false |
18 | +gem 'grape', '0.2.1' | |
18 | 19 | |
19 | 20 | # FIXME list here all actual dependencies (i.e. the ones in debian/control), |
20 | 21 | # with their GEM names (not the Debian package names) | ... | ... |
app/models/article.rb
... | ... | @@ -102,6 +102,16 @@ class Article < ActiveRecord::Base |
102 | 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 | 115 | scope :by_range, lambda { |range| { |
106 | 116 | :conditions => [ |
107 | 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 | 668 | person ? person.id : nil |
659 | 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 | 676 | def version_license(version_number = nil) |
662 | 677 | return license if version_number.nil? |
663 | 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 | 20 | |
21 | 21 | scope :without_reply, :conditions => ['reply_of_id IS NULL'] |
22 | 22 | |
23 | + #FIXME make this test | |
24 | + scope :newer_than, lambda { |reference_id| | |
25 | + {:conditions => ["comments.id > #{reference_id}"]} | |
26 | + } | |
27 | + | |
28 | + #FIXME make this test | |
29 | + scope :older_than, lambda { |reference_id| | |
30 | + {:conditions => ["comments.id < #{reference_id}"]} | |
31 | + } | |
32 | + | |
33 | + | |
23 | 34 | # unauthenticated authors: |
24 | 35 | validates_presence_of :name, :if => (lambda { |record| !record.email.blank? }) |
25 | 36 | validates_presence_of :email, :if => (lambda { |record| !record.name.blank? }) |
... | ... | @@ -63,6 +74,11 @@ class Comment < ActiveRecord::Base |
63 | 74 | author ? author.url : nil |
64 | 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 | 82 | def url |
67 | 83 | article.view_url.merge(:anchor => anchor) |
68 | 84 | end | ... | ... |
app/models/profile.rb
... | ... | @@ -89,6 +89,16 @@ class Profile < ActiveRecord::Base |
89 | 89 | scope :templates, {:conditions => {:is_template => true}} |
90 | 90 | scope :no_templates, {:conditions => {:is_template => false}} |
91 | 91 | |
92 | + #FIXME make this test | |
93 | + scope :newer_than, lambda { |reference_id| | |
94 | + {:conditions => ["profiles.id > #{reference_id}"]} | |
95 | + } | |
96 | + | |
97 | + #FIXME make this test | |
98 | + scope :older_than, lambda { |reference_id| | |
99 | + {:conditions => ["profiles.id < #{reference_id}"]} | |
100 | + } | |
101 | + | |
92 | 102 | def members |
93 | 103 | scopes = plugins.dispatch_scopes(:organization_members, self) |
94 | 104 | scopes << Person.members_of(self) |
... | ... | @@ -877,6 +887,13 @@ private :generate_url, :url_options |
877 | 887 | image.public_filename(:icon) if image.present? |
878 | 888 | end |
879 | 889 | |
890 | + #FIXME make this test | |
891 | + def profile_custom_image(size = :icon) | |
892 | + image_path = profile_custom_icon if size == :icon | |
893 | + image_path ||= image.public_filename(size) if image.present? | |
894 | + image_path | |
895 | + end | |
896 | + | |
880 | 897 | def jid(options = {}) |
881 | 898 | domain = options[:domain] || environment.default_hostname |
882 | 899 | "#{identifier}@#{domain}" | ... | ... |
app/models/user.rb
1 | 1 | require 'digest/sha1' |
2 | 2 | require 'user_activation_job' |
3 | +require 'securerandom' | |
3 | 4 | |
4 | 5 | # User models the system users, and is generated by the acts_as_authenticated |
5 | 6 | # Rails generator. |
... | ... | @@ -138,6 +139,18 @@ class User < ActiveRecord::Base |
138 | 139 | u && u.authenticated?(password) ? u : nil |
139 | 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(:validate => 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 | 154 | # Activates the user in the database. |
142 | 155 | def activate |
143 | 156 | return false unless self.person | ... | ... |
config.ru
1 | 1 | # This file is used by Rack-based servers to start the application. |
2 | 2 | |
3 | 3 | require ::File.expand_path('../config/environment', __FILE__) |
4 | -run Noosfero::Application | |
4 | + | |
5 | +rails_app = Rack::Builder.new do | |
6 | + run Noosfero::Application | |
7 | +end | |
8 | + | |
9 | +run Rack::Cascade.new([ | |
10 | + API::API, | |
11 | + rails_app | |
12 | +]) | ... | ... |
db/migrate/20140407013817_add_private_token_info_to_users.rb
0 → 100644
... | ... | @@ -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,22 @@ |
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 V1::Communities | |
17 | + mount V1::People | |
18 | + mount V1::Enterprises | |
19 | + mount Session | |
20 | + | |
21 | + end | |
22 | +end | ... | ... |
... | ... | @@ -0,0 +1,71 @@ |
1 | +module API | |
2 | + module Entities | |
3 | + | |
4 | + class Image < Grape::Entity | |
5 | + root 'images', 'image' | |
6 | + | |
7 | + expose :icon_url do |image, options| | |
8 | + image.public_filename(:icon) | |
9 | + end | |
10 | + | |
11 | + expose :minor_url do |image, options| | |
12 | + image.public_filename(:minor) | |
13 | + end | |
14 | + | |
15 | + expose :portrait_url do |image, options| | |
16 | + image.public_filename(:portrait) | |
17 | + end | |
18 | + | |
19 | + expose :thumb_url do |image, options| | |
20 | + image.public_filename(:thumb) | |
21 | + end | |
22 | + end | |
23 | + | |
24 | + class Profile < Grape::Entity | |
25 | + expose :identifier, :name, :created_at, :id | |
26 | + expose :image, :using => Image | |
27 | + end | |
28 | + | |
29 | + class Person < Profile;end; | |
30 | + class Enterprise < Profile;end; | |
31 | + class Community < Profile | |
32 | + root 'communities', 'community' | |
33 | + expose :description | |
34 | + end | |
35 | + | |
36 | + class Category < Grape::Entity | |
37 | + root 'categories', 'category' | |
38 | + expose :name, :id, :slug | |
39 | + expose :image, :using => Image | |
40 | + end | |
41 | + | |
42 | + | |
43 | + class Article < Grape::Entity | |
44 | + root 'articles', 'article' | |
45 | + expose :id, :body, :created_at | |
46 | + expose :title, :documentation => {:type => "String", :desc => "Title of the article"} | |
47 | + expose :author, :using => Profile | |
48 | + expose :profile, :using => Profile | |
49 | + expose :categories, :using => Category | |
50 | + end | |
51 | + | |
52 | + class Comment < Grape::Entity | |
53 | + root 'comments', 'comment' | |
54 | + expose :body, :title, :created_at, :id | |
55 | + | |
56 | + expose :author, :using => Profile | |
57 | + end | |
58 | + | |
59 | + | |
60 | + class User < Grape::Entity | |
61 | + root 'users', 'user' | |
62 | + expose :login | |
63 | + expose :person, :using => Profile | |
64 | + end | |
65 | + | |
66 | + class UserLogin < User | |
67 | + expose :private_token | |
68 | + end | |
69 | + | |
70 | + end | |
71 | +end | ... | ... |
... | ... | @@ -0,0 +1,190 @@ |
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 | + begin_period = from_date.nil? ? Time.at(0).to_datetime : from_date | |
36 | + end_period = until_date.nil? ? DateTime.now : until_date | |
37 | + | |
38 | + begin_period...end_period | |
39 | + end | |
40 | + | |
41 | + def parse_content_type(content_type) | |
42 | + return nil if content_type.blank? | |
43 | + content_type.split(',').map do |content_type| | |
44 | + content_type.camelcase | |
45 | + end | |
46 | + end | |
47 | + | |
48 | + def make_conditions_with_parameter(params = {}) | |
49 | + conditions = {} | |
50 | + from_date = DateTime.parse(params[:from]) if params[:from] | |
51 | + until_date = DateTime.parse(params[:until]) if params[:until] | |
52 | + | |
53 | + conditions[:type] = parse_content_type(params[:content_type]) unless params[:content_type].nil? | |
54 | + | |
55 | + conditions[:created_at] = period(from_date, until_date) if from_date || until_date | |
56 | + | |
57 | + conditions | |
58 | + end | |
59 | + | |
60 | + | |
61 | + def select_filtered_collection_of(object, method, params) | |
62 | + conditions = make_conditions_with_parameter(params) | |
63 | + | |
64 | + if params[:reference_id] | |
65 | + objects = object.send(method).send("#{params.key?(:oldest) ? 'older_than' : 'newer_than'}", params[:reference_id]).find(:all, :conditions => conditions, :limit => limit, :order => "created_at DESC") | |
66 | + else | |
67 | + objects = object.send(method).find(:all, :conditions => conditions, :limit => limit, :order => "created_at DESC") | |
68 | + end | |
69 | + objects | |
70 | + end | |
71 | + | |
72 | +#FIXME see if its needed | |
73 | +# def paginate(relation) | |
74 | +# per_page = params[:per_page].to_i | |
75 | +# paginated = relation.page(params[:page]).per(per_page) | |
76 | +# add_pagination_headers(paginated, per_page) | |
77 | +# | |
78 | +# paginated | |
79 | +# end | |
80 | + | |
81 | + def authenticate! | |
82 | + unauthorized! unless current_user | |
83 | + end | |
84 | + | |
85 | +#FIXME see if its needed | |
86 | +# def authenticated_as_admin! | |
87 | +# forbidden! unless current_user.is_admin? | |
88 | +# end | |
89 | +# | |
90 | +#FIXME see if its needed | |
91 | +# def authorize! action, subject | |
92 | +# unless abilities.allowed?(current_user, action, subject) | |
93 | +# forbidden! | |
94 | +# end | |
95 | +# end | |
96 | +# | |
97 | +#FIXME see if its needed | |
98 | +# def can?(object, action, subject) | |
99 | +# abilities.allowed?(object, action, subject) | |
100 | +# end | |
101 | + | |
102 | + # Checks the occurrences of required attributes, each attribute must be present in the params hash | |
103 | + # or a Bad Request error is invoked. | |
104 | + # | |
105 | + # Parameters: | |
106 | + # keys (required) - A hash consisting of keys that must be present | |
107 | + def required_attributes!(keys) | |
108 | + keys.each do |key| | |
109 | + bad_request!(key) unless params[key].present? | |
110 | + end | |
111 | + end | |
112 | + | |
113 | + # Checks the occurrences of uniqueness of attributes, each attribute must be present in the params hash | |
114 | + # or a Bad Request error is invoked. | |
115 | + # | |
116 | + # Parameters: | |
117 | + # keys (unique) - A hash consisting of keys that must be unique | |
118 | + def unique_attributes!(obj, keys) | |
119 | + keys.each do |key| | |
120 | + cant_be_saved_request!(key) if obj.send("find_by_#{key.to_s}", params[key]) | |
121 | + end | |
122 | + end | |
123 | + | |
124 | + def attributes_for_keys(keys) | |
125 | + attrs = {} | |
126 | + keys.each do |key| | |
127 | + attrs[key] = params[key] if params[key].present? or (params.has_key?(key) and params[key] == false) | |
128 | + end | |
129 | + attrs | |
130 | + end | |
131 | + | |
132 | + # error helpers | |
133 | + def forbidden! | |
134 | + render_api_error!('403 Forbidden', 403) | |
135 | + end | |
136 | + | |
137 | + def cant_be_saved_request!(attribute) | |
138 | + message = _("(Invalid request) #{attribute} can't be saved") | |
139 | + render_api_error!(message, 400) | |
140 | + end | |
141 | + | |
142 | + def bad_request!(attribute) | |
143 | + message = _("(Bad request) #{attribute} not given") | |
144 | + render_api_error!(message, 400) | |
145 | + end | |
146 | + | |
147 | + def something_wrong! | |
148 | + message = _("Something wrong happened") | |
149 | + render_api_error!(message, 400) | |
150 | + end | |
151 | + | |
152 | + def unauthorized! | |
153 | + render_api_error!(_('Unauthorized'), 401) | |
154 | + end | |
155 | + | |
156 | + def not_allowed! | |
157 | + render_api_error!(_('Method Not Allowed'), 405) | |
158 | + end | |
159 | + | |
160 | + def render_api_error!(message, status) | |
161 | + error!({'message' => message, :code => status}, status) | |
162 | + end | |
163 | + | |
164 | + def render_api_errors!(messages) | |
165 | + render_api_error!(messages.join(','), 400) | |
166 | + end | |
167 | + protected | |
168 | + | |
169 | + def detect_stuff_by_domain | |
170 | + @domain = Domain.find_by_name(request.host) | |
171 | + if @domain.nil? | |
172 | + @environment = Environment.default | |
173 | + if @environment.nil? && Rails.env.development? | |
174 | + # This should only happen in development ... | |
175 | + @environment = Environment.create!(:name => "Noosfero", :is_default => true) | |
176 | + end | |
177 | + else | |
178 | + @environment = @domain.environment | |
179 | + end | |
180 | + end | |
181 | + | |
182 | + private | |
183 | + | |
184 | + def default_limit | |
185 | + 20 | |
186 | + end | |
187 | + | |
188 | + | |
189 | + end | |
190 | +end | ... | ... |
... | ... | @@ -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,83 @@ |
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 | + articles = select_filtered_collection_of(environment, 'articles', params) | |
24 | + present articles, :with => Entities::Article | |
25 | + end | |
26 | + | |
27 | + desc "Return the article id" | |
28 | + get ':id' do | |
29 | + present environment.articles.find(params[:id]), :with => Entities::Article | |
30 | + end | |
31 | + | |
32 | + get ':id/children' do | |
33 | + | |
34 | + conditions = make_conditions_with_parameter(params) | |
35 | + if params[:reference_id] | |
36 | + 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") | |
37 | + else | |
38 | + articles = environment.articles.find(params[:id]).children.find(:all, :conditions => conditions, :limit => limit, :order => "created_at DESC") | |
39 | + end | |
40 | + present articles, :with => Entities::Article | |
41 | + end | |
42 | + | |
43 | + get ':id/children/:child_id' do | |
44 | + present environment.articles.find(params[:id]).children.find(params[:child_id]), :with => Entities::Article | |
45 | + end | |
46 | + | |
47 | + | |
48 | + end | |
49 | + | |
50 | + resource :communities do | |
51 | + segment '/:community_id' do | |
52 | + resource :articles do | |
53 | + get do | |
54 | + community = environment.communities.find(params[:community_id]) | |
55 | + articles = select_filtered_collection_of(community, 'articles', params) | |
56 | + present articles, :with => Entities::Article | |
57 | + end | |
58 | + | |
59 | + get '/:id' do | |
60 | + community = environment.communities.find(params[:community_id]) | |
61 | + present community.articles.find(params[:id]), :with => Entities::Article | |
62 | + end | |
63 | + | |
64 | + # Example Request: | |
65 | + # POST api/v1/communites/:community_id/articles?private_toke=234298743290432&article[name]=title&article[body]=body | |
66 | + post do | |
67 | + community = environment.communities.find(params[:community_id]) | |
68 | + article = community.articles.build(params[:article].merge(:last_changed_by => current_person)) | |
69 | + article.type= params[:type].nil? ? 'TinyMceArticle' : params[:type] | |
70 | + if !article.save | |
71 | + render_api_errors!(article.errors.full_messages) | |
72 | + end | |
73 | + present article, :with => Entities::Article | |
74 | + end | |
75 | + | |
76 | + end | |
77 | + end | |
78 | + | |
79 | + end | |
80 | + | |
81 | + end | |
82 | + end | |
83 | +end | ... | ... |
... | ... | @@ -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,39 @@ |
1 | +module API | |
2 | + module V1 | |
3 | + class Communities < Grape::API | |
4 | + before { detect_stuff_by_domain } | |
5 | + before { authenticate! } | |
6 | + | |
7 | + resource :communities 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 /communities?from=2013-04-04-14:41:43&until=2014-04-04-14:41:43&limit=10 | |
18 | + # GET /communities?reference_id=10&limit=10&oldest | |
19 | + get do | |
20 | + communities = select_filtered_collection_of(current_person, 'communities', params) | |
21 | + present communities, :with => Entities::Community | |
22 | + end | |
23 | + | |
24 | + #FIXME See only public communities | |
25 | + get '/all' do | |
26 | + communities = select_filtered_collection_of(environment, 'communities', params) | |
27 | + present communities, :with => Entities::Community | |
28 | + end | |
29 | + | |
30 | + get ':id' do | |
31 | + community = environment.communities.find(params[:id]) | |
32 | + present community, :with => Entities::Community | |
33 | + end | |
34 | + | |
35 | + end | |
36 | + | |
37 | + end | |
38 | + end | |
39 | +end | ... | ... |
... | ... | @@ -0,0 +1,33 @@ |
1 | +module API | |
2 | + module V1 | |
3 | + class Enterprises < Grape::API | |
4 | + before { detect_stuff_by_domain } | |
5 | + before { authenticate! } | |
6 | + | |
7 | + resource :enterprises 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 /enterprises?from=2013-04-04-14:41:43&until=2014-04-04-14:41:43&limit=10 | |
18 | + # GET /enterprises?reference_id=10&limit=10&oldest | |
19 | + get do | |
20 | + enterprises = select_filtered_collection_of(environment, 'enterprises', params) | |
21 | + present enterprises, :with => Entities::Enterprise | |
22 | + end | |
23 | + | |
24 | + desc "Return the article id" | |
25 | + get ':id' do | |
26 | + present environment.enterprises.find(params[:id]), :with => Entities::Enterprise | |
27 | + end | |
28 | + | |
29 | + end | |
30 | + | |
31 | + end | |
32 | + end | |
33 | +end | ... | ... |
... | ... | @@ -0,0 +1,33 @@ |
1 | +module API | |
2 | + module V1 | |
3 | + class People < Grape::API | |
4 | + before { detect_stuff_by_domain } | |
5 | + before { authenticate! } | |
6 | + | |
7 | + resource :people 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 /people?from=2013-04-04-14:41:43&until=2014-04-04-14:41:43&limit=10 | |
18 | + # GET /people?reference_id=10&limit=10&oldest | |
19 | + get do | |
20 | + people = select_filtered_collection_of(environment, 'people', params) | |
21 | + present people, :with => Entities::Person | |
22 | + end | |
23 | + | |
24 | + desc "Return the person information" | |
25 | + get '/:id' do | |
26 | + present environment.people.find(params[:id]), :with => Entities::Person | |
27 | + end | |
28 | + | |
29 | + end | |
30 | + | |
31 | + end | |
32 | + end | |
33 | +end | ... | ... |
... | ... | @@ -0,0 +1,22 @@ |
1 | +module API | |
2 | + module V1 | |
3 | + class Users < Grape::API | |
4 | + | |
5 | + before { detect_stuff_by_domain } | |
6 | + before { authenticate! } | |
7 | + | |
8 | + resource :users do | |
9 | + | |
10 | + get do | |
11 | + present environment.users, :with => Entities::User | |
12 | + end | |
13 | + | |
14 | + get ":id" do | |
15 | + present environment.users.find(params[:id]), :with => Entities::User | |
16 | + end | |
17 | + | |
18 | + end | |
19 | + | |
20 | + end | |
21 | + end | |
22 | +end | ... | ... |
... | ... | @@ -0,0 +1,85 @@ |
1 | +require File.dirname(__FILE__) + '/../test_helper' | |
2 | + | |
3 | +class APITest < ActiveSupport::TestCase | |
4 | + | |
5 | + include Rack::Test::Methods | |
6 | + | |
7 | + def app | |
8 | + API::API | |
9 | + end | |
10 | + | |
11 | + def setup | |
12 | + @user = User.create!(:login => 'testapi', :password => 'testapi', :password_confirmation => 'testapi', :email => 'test@test.org', :environment => Environment.default) | |
13 | + @user.activate | |
14 | + | |
15 | + post "/api/v1/login?login=testapi&password=testapi" | |
16 | + json = JSON.parse(last_response.body) | |
17 | + @private_token = json["private_token"] | |
18 | + @params = {:private_token => @private_token} | |
19 | + end | |
20 | + attr_accessor :private_token, :user, :params | |
21 | + | |
22 | + should 'generate private token when login' do | |
23 | + params = {:login => "testapi", :password => "testapi"} | |
24 | + post "/api/v1/login?#{params.to_query}" | |
25 | + json = JSON.parse(last_response.body) | |
26 | + assert !json["private_token"].blank? | |
27 | + end | |
28 | + | |
29 | + should 'return 401 when login fails' do | |
30 | + user.destroy | |
31 | + params = {:login => "testapi", :password => "testapi"} | |
32 | + post "/api/v1/login?#{params.to_query}" | |
33 | + assert_equal 401, last_response.status | |
34 | + end | |
35 | + | |
36 | + should 'register a user' do | |
37 | + params = {:login => "newuserapi", :password => "newuserapi", :email => "newuserapi@email.com" } | |
38 | + post "/api/v1/register?#{params.to_query}" | |
39 | + assert_equal 201, last_response.status | |
40 | + end | |
41 | + | |
42 | + should 'do not register a user without email' do | |
43 | + params = {:login => "newuserapi", :password => "newuserapi", :email => nil } | |
44 | + post "/api/v1/register?#{params.to_query}" | |
45 | + assert_equal 400, last_response.status | |
46 | + end | |
47 | + | |
48 | + should 'do not register a duplicated user' do | |
49 | + params = {:login => "newuserapi", :password => "newuserapi", :email => "newuserapi@email.com" } | |
50 | + post "/api/v1/register?#{params.to_query}" | |
51 | + post "/api/v1/register?#{params.to_query}" | |
52 | + assert_equal 400, last_response.status | |
53 | + end | |
54 | + | |
55 | + should 'list articles' do | |
56 | + article = fast_create(Article, :profile_id => user.person.id, :name => "Some thing") | |
57 | + get "/api/v1/articles/?#{params.to_query}" | |
58 | + json = JSON.parse(last_response.body) | |
59 | + assert_includes json["articles"].map { |a| a["id"] }, article.id | |
60 | + end | |
61 | + | |
62 | + should 'return article by id' do | |
63 | + article = fast_create(Article, :profile_id => user.person.id, :name => "Some thing") | |
64 | + get "/api/v1/articles/#{article.id}?#{params.to_query}" | |
65 | + json = JSON.parse(last_response.body) | |
66 | + assert_equal article.id, json["article"]["id"] | |
67 | + end | |
68 | + | |
69 | + should 'return comments of an article' do | |
70 | + article = fast_create(Article, :profile_id => user.person.id, :name => "Some thing") | |
71 | + article.comments.create!(:body => "some comment", :author => user.person) | |
72 | + article.comments.create!(:body => "another comment", :author => user.person) | |
73 | + | |
74 | + get "/api/v1/articles/#{article.id}/comments?#{params.to_query}" | |
75 | + json = JSON.parse(last_response.body) | |
76 | + assert_equal 2, json["comments"].length | |
77 | + end | |
78 | + | |
79 | + should 'list users' do | |
80 | + get "/api/v1/users/?#{params.to_query}" | |
81 | + json = JSON.parse(last_response.body) | |
82 | + assert_includes json["users"].map { |a| a["login"] }, user.login | |
83 | + end | |
84 | + | |
85 | +end | ... | ... |