Commit d8b7fec7e322b98c0dd92356e3f643e7c0363197

Authored by Victor Costa
2 parents da1968e4 a3659ade

Merge branch 'move-api' into 'master'

Move api to app/api

`lib` can't depend on `app`, just the opposite.

See merge request !917
Showing 59 changed files with 2000 additions and 2039 deletions   Show diff stats
app/api/app.rb 0 → 100644
@@ -0,0 +1,89 @@ @@ -0,0 +1,89 @@
  1 +require_dependency 'api/helpers'
  2 +
  3 +module Api
  4 + class App < Grape::API
  5 + use Rack::JSONP
  6 +
  7 + logger = Logger.new(File.join(Rails.root, 'log', "#{ENV['RAILS_ENV'] || 'production'}_api.log"))
  8 + logger.formatter = GrapeLogging::Formatters::Default.new
  9 + #use GrapeLogging::Middleware::RequestLogger, { logger: logger }
  10 +
  11 + rescue_from :all do |e|
  12 + logger.error e
  13 + error! e.message, 500
  14 + end unless Rails.env.test?
  15 +
  16 + @@NOOSFERO_CONF = nil
  17 + def self.NOOSFERO_CONF
  18 + if @@NOOSFERO_CONF
  19 + @@NOOSFERO_CONF
  20 + else
  21 + file = Rails.root.join('config', 'noosfero.yml')
  22 + @@NOOSFERO_CONF = File.exists?(file) ? YAML.load_file(file)[Rails.env] || {} : {}
  23 + end
  24 + end
  25 +
  26 + before { set_locale }
  27 + before { setup_multitenancy }
  28 + before { detect_stuff_by_domain }
  29 + before { filter_disabled_plugins_endpoints }
  30 + before { init_noosfero_plugins }
  31 + after { set_session_cookie }
  32 +
  33 + version 'v1'
  34 + prefix [ENV['RAILS_RELATIVE_URL_ROOT'], "api"].compact.join('/')
  35 + format :json
  36 + content_type :txt, "text/plain"
  37 +
  38 + helpers Helpers
  39 +
  40 + mount V1::Session
  41 + mount V1::Articles
  42 + mount V1::Comments
  43 + mount V1::Users
  44 + mount V1::Communities
  45 + mount V1::People
  46 + mount V1::Enterprises
  47 + mount V1::Categories
  48 + mount V1::Tasks
  49 + mount V1::Tags
  50 + mount V1::Environments
  51 + mount V1::Search
  52 + mount V1::Contacts
  53 + mount V1::Boxes
  54 + mount V1::Blocks
  55 + mount V1::Profiles
  56 + mount V1::Activities
  57 +
  58 + # hook point which allow plugins to add Grape::API extensions to Api::App
  59 + #finds for plugins which has api mount points classes defined (the class should extends Grape::API)
  60 + @plugins = Noosfero::Plugin.all.map { |p| p.constantize }
  61 + @plugins.each do |klass|
  62 + if klass.public_methods.include? :api_mount_points
  63 + klass.api_mount_points.each do |mount_class|
  64 + mount mount_class if mount_class && ( mount_class < Grape::API )
  65 + end
  66 + end
  67 + end
  68 +
  69 + def self.endpoint_unavailable?(endpoint, environment)
  70 + api_class = endpoint.options[:app] || endpoint.options[:for]
  71 + if api_class.present?
  72 + klass = api_class.name.deconstantize.constantize
  73 + return klass < Noosfero::Plugin && !environment.plugin_enabled?(klass)
  74 + end
  75 + end
  76 +
  77 + class << self
  78 + def endpoints_with_plugins(environment = nil)
  79 + if environment.present?
  80 + cloned_endpoints = endpoints_without_plugins.dup
  81 + cloned_endpoints.delete_if { |endpoint| endpoint_unavailable?(endpoint, environment) }
  82 + else
  83 + endpoints_without_plugins
  84 + end
  85 + end
  86 + alias_method_chain :endpoints, :plugins
  87 + end
  88 + end
  89 +end
app/api/entities.rb 0 → 100644
@@ -0,0 +1,267 @@ @@ -0,0 +1,267 @@
  1 +module Api
  2 + module Entities
  3 +
  4 + Entity.format_with :timestamp do |date|
  5 + date.strftime('%Y/%m/%d %H:%M:%S') if date
  6 + end
  7 +
  8 + PERMISSIONS = {
  9 + :admin => 0,
  10 + :self => 10,
  11 + :private_content => 20,
  12 + :logged_user => 30,
  13 + :anonymous => 40
  14 + }
  15 +
  16 + def self.can_display_profile_field? profile, options, permission_options={}
  17 + permissions={:field => "", :permission => :private_content}
  18 + permissions.merge!(permission_options)
  19 + field = permissions[:field]
  20 + permission = permissions[:permission]
  21 + return true if profile.public? && profile.public_fields.map{|f| f.to_sym}.include?(field.to_sym)
  22 +
  23 + current_person = options[:current_person]
  24 +
  25 + current_permission = if current_person.present?
  26 + if current_person.is_admin?
  27 + :admin
  28 + elsif current_person == profile
  29 + :self
  30 + elsif profile.display_private_info_to?(current_person)
  31 + :private_content
  32 + else
  33 + :logged_user
  34 + end
  35 + else
  36 + :anonymous
  37 + end
  38 + PERMISSIONS[current_permission] <= PERMISSIONS[permission]
  39 + end
  40 +
  41 + class Image < Entity
  42 + root 'images', 'image'
  43 +
  44 + expose :url do |image, options|
  45 + image.public_filename
  46 + end
  47 +
  48 + expose :icon_url do |image, options|
  49 + image.public_filename(:icon)
  50 + end
  51 +
  52 + expose :minor_url do |image, options|
  53 + image.public_filename(:minor)
  54 + end
  55 +
  56 + expose :portrait_url do |image, options|
  57 + image.public_filename(:portrait)
  58 + end
  59 +
  60 + expose :thumb_url do |image, options|
  61 + image.public_filename(:thumb)
  62 + end
  63 + end
  64 +
  65 + class CategoryBase < Entity
  66 + root 'categories', 'category'
  67 + expose :name, :id, :slug
  68 + end
  69 +
  70 + class Category < CategoryBase
  71 + root 'categories', 'category'
  72 + expose :full_name do |category, options|
  73 + category.full_name
  74 + end
  75 + expose :parent, :using => CategoryBase, if: { parent: true }
  76 + expose :children, :using => CategoryBase, if: { children: true }
  77 + expose :image, :using => Image
  78 + expose :display_color
  79 + end
  80 +
  81 + class Region < Category
  82 + root 'regions', 'region'
  83 + expose :parent_id
  84 + end
  85 +
  86 + class Block < Entity
  87 + root 'blocks', 'block'
  88 + expose :id, :type, :settings, :position, :enabled
  89 + expose :mirror, :mirror_block_id, :title
  90 + expose :api_content, if: lambda { |object, options| options[:display_api_content] || object.display_api_content_by_default? }
  91 + end
  92 +
  93 + class Box < Entity
  94 + root 'boxes', 'box'
  95 + expose :id, :position
  96 + expose :blocks, :using => Block
  97 + end
  98 +
  99 + class Profile < Entity
  100 + expose :identifier, :name, :id
  101 + expose :created_at, :format_with => :timestamp
  102 + expose :updated_at, :format_with => :timestamp
  103 + expose :additional_data do |profile, options|
  104 + hash ={}
  105 + profile.public_values.each do |value|
  106 + hash[value.custom_field.name]=value.value
  107 + end
  108 +
  109 + private_values = profile.custom_field_values - profile.public_values
  110 + private_values.each do |value|
  111 + if Entities.can_display_profile_field?(profile,options)
  112 + hash[value.custom_field.name]=value.value
  113 + end
  114 + end
  115 + hash
  116 + end
  117 + expose :image, :using => Image
  118 + expose :region, :using => Region
  119 + expose :type
  120 + expose :custom_header
  121 + expose :custom_footer
  122 + end
  123 +
  124 + class UserBasic < Entity
  125 + expose :id
  126 + expose :login
  127 + end
  128 +
  129 + class Person < Profile
  130 + root 'people', 'person'
  131 + expose :user, :using => UserBasic, documentation: {type: 'User', desc: 'The user data of a person' }
  132 + expose :vote_count
  133 + expose :comments_count do |person, options|
  134 + person.comments.count
  135 + end
  136 + expose :following_articles_count do |person, options|
  137 + person.following_articles.count
  138 + end
  139 + expose :articles_count do |person, options|
  140 + person.articles.count
  141 + end
  142 + end
  143 +
  144 + class Enterprise < Profile
  145 + root 'enterprises', 'enterprise'
  146 + end
  147 +
  148 + class Community < Profile
  149 + root 'communities', 'community'
  150 + expose :description
  151 + expose :admins, :if => lambda { |community, options| community.display_info_to? options[:current_person]} do |community, options|
  152 + community.admins.map{|admin| {"name"=>admin.name, "id"=>admin.id, "username" => admin.identifier}}
  153 + end
  154 + expose :categories, :using => Category
  155 + expose :members, :using => Person , :if => lambda{ |community, options| community.display_info_to? options[:current_person] }
  156 + end
  157 +
  158 + class CommentBase < Entity
  159 + expose :body, :title, :id
  160 + expose :created_at, :format_with => :timestamp
  161 + expose :author, :using => Profile
  162 + expose :reply_of, :using => CommentBase
  163 + end
  164 +
  165 + class Comment < CommentBase
  166 + root 'comments', 'comment'
  167 + expose :children, as: :replies, :using => Comment
  168 + end
  169 +
  170 + class ArticleBase < Entity
  171 + root 'articles', 'article'
  172 + expose :id
  173 + expose :body
  174 + expose :abstract, documentation: {type: 'String', desc: 'Teaser of the body'}
  175 + expose :created_at, :format_with => :timestamp
  176 + expose :updated_at, :format_with => :timestamp
  177 + expose :title, :documentation => {:type => "String", :desc => "Title of the article"}
  178 + expose :created_by, :as => :author, :using => Profile, :documentation => {type: 'Profile', desc: 'The profile author that create the article'}
  179 + expose :profile, :using => Profile, :documentation => {type: 'Profile', desc: 'The profile associated with the article'}
  180 + expose :categories, :using => Category
  181 + expose :image, :using => Image
  182 + expose :votes_for
  183 + expose :votes_against
  184 + expose :setting
  185 + expose :position
  186 + expose :hits
  187 + expose :start_date
  188 + expose :end_date, :documentation => {type: 'DateTime', desc: 'The date of finish of the article'}
  189 + expose :tag_list
  190 + expose :children_count
  191 + expose :slug, :documentation => {:type => "String", :desc => "Trimmed and parsed name of a article"}
  192 + expose :path
  193 + expose :followers_count
  194 + expose :votes_count
  195 + expose :comments_count
  196 + expose :archived, :documentation => {:type => "Boolean", :desc => "Defines if a article is readonly"}
  197 + expose :type
  198 + expose :comments, using: CommentBase, :if => lambda{|obj,opt| opt[:params] && ['1','true',true].include?(opt[:params][:show_comments])}
  199 + expose :published
  200 + expose :accept_comments?, as: :accept_comments
  201 + end
  202 +
  203 + class Article < ArticleBase
  204 + root 'articles', 'article'
  205 + expose :parent, :using => ArticleBase
  206 + expose :children, :using => ArticleBase do |article, options|
  207 + article.children.published.limit(V1::Articles::MAX_PER_PAGE)
  208 + end
  209 + end
  210 +
  211 + class User < Entity
  212 + root 'users', 'user'
  213 +
  214 + attrs = [:id,:login,:email,:activated?]
  215 + aliases = {:activated? => :activated}
  216 +
  217 + attrs.each do |attribute|
  218 + name = aliases.has_key?(attribute) ? aliases[attribute] : attribute
  219 + expose attribute, :as => name, :if => lambda{|user,options| Entities.can_display_profile_field?(user.person, options, {:field => attribute})}
  220 + end
  221 +
  222 + expose :person, :using => Person, :if => lambda{|user,options| user.person.display_info_to? options[:current_person]}
  223 + expose :permissions, :if => lambda{|user,options| Entities.can_display_profile_field?(user.person, options, {:field => :permissions, :permission => :self})} do |user, options|
  224 + output = {}
  225 + user.person.role_assignments.map do |role_assigment|
  226 + if role_assigment.resource.respond_to?(:identifier) && !role_assigment.role.nil?
  227 + output[role_assigment.resource.identifier] = role_assigment.role.permissions
  228 + end
  229 + end
  230 + output
  231 + end
  232 + end
  233 +
  234 + class UserLogin < User
  235 + root 'users', 'user'
  236 + expose :private_token, documentation: {type: 'String', desc: 'A valid authentication code for post/delete api actions'}, if: lambda {|object, options| object.activated? }
  237 + end
  238 +
  239 + class Task < Entity
  240 + root 'tasks', 'task'
  241 + expose :id
  242 + expose :type
  243 + end
  244 +
  245 + class Environment < Entity
  246 + expose :name
  247 + expose :id
  248 + expose :description
  249 + expose :settings, if: lambda { |instance, options| options[:is_admin] }
  250 + end
  251 +
  252 + class Tag < Entity
  253 + root 'tags', 'tag'
  254 + expose :name
  255 + end
  256 +
  257 + class Activity < Entity
  258 + root 'activities', 'activity'
  259 + expose :id, :params, :verb, :created_at, :updated_at, :comments_count, :visible
  260 + expose :user, :using => Profile
  261 + expose :target do |activity, opts|
  262 + type_map = {Profile => ::Profile, ArticleBase => ::Article}.find {|h| activity.target.kind_of?(h.last)}
  263 + type_map.first.represent(activity.target) unless type_map.nil?
  264 + end
  265 + end
  266 + end
  267 +end
app/api/entity.rb 0 → 100644
@@ -0,0 +1,27 @@ @@ -0,0 +1,27 @@
  1 +module Api
  2 + class Entity < Grape::Entity
  3 +
  4 + def initialize(object, options = {})
  5 + object = nil if object.is_a? Exception
  6 + super object, options
  7 + end
  8 +
  9 + def self.represent(objects, options = {})
  10 + if options[:has_exception]
  11 + data = super objects, options.merge(is_inner_data: true)
  12 + if objects.is_a? Exception
  13 + data.merge ok: false, error: {
  14 + type: objects.class.name,
  15 + message: objects.message
  16 + }
  17 + else
  18 + data = data.serializable_hash if data.is_a? Entity
  19 + data.merge ok: true, error: { type: 'Success', message: '' }
  20 + end
  21 + else
  22 + super objects, options
  23 + end
  24 + end
  25 +
  26 + end
  27 +end
app/api/helpers.rb 0 → 100644
@@ -0,0 +1,421 @@ @@ -0,0 +1,421 @@
  1 +require 'base64'
  2 +require 'tempfile'
  3 +
  4 +module Api
  5 + module Helpers
  6 + PRIVATE_TOKEN_PARAM = :private_token
  7 + DEFAULT_ALLOWED_PARAMETERS = [:parent_id, :from, :until, :content_type, :author_id, :identifier, :archived]
  8 +
  9 + include SanitizeParams
  10 + include Noosfero::Plugin::HotSpot
  11 + include ForgotPasswordHelper
  12 + include SearchTermHelper
  13 +
  14 + def set_locale
  15 + I18n.locale = (params[:lang] || request.env['HTTP_ACCEPT_LANGUAGE'] || 'en')
  16 + end
  17 +
  18 + def init_noosfero_plugins
  19 + plugins
  20 + end
  21 +
  22 + def current_user
  23 + private_token = (params[PRIVATE_TOKEN_PARAM] || headers['Private-Token']).to_s
  24 + @current_user ||= User.find_by private_token: private_token
  25 + @current_user ||= plugins.dispatch("api_custom_login", request).first
  26 + @current_user
  27 + end
  28 +
  29 + def current_person
  30 + current_user.person unless current_user.nil?
  31 + end
  32 +
  33 + def is_admin?(environment)
  34 + return false unless current_user
  35 + return current_person.is_admin?(environment)
  36 + end
  37 +
  38 + def logout
  39 + @current_user = nil
  40 + end
  41 +
  42 + def environment
  43 + @environment
  44 + end
  45 +
  46 + def present_partial(model, options)
  47 + if(params[:fields].present?)
  48 + begin
  49 + fields = JSON.parse(params[:fields])
  50 + if fields.present?
  51 + options.merge!(fields.symbolize_keys.slice(:only, :except))
  52 + end
  53 + rescue
  54 + fields = params[:fields]
  55 + fields = fields.split(',') if fields.kind_of?(String)
  56 + options[:only] = Array.wrap(fields)
  57 + end
  58 + end
  59 + present model, options
  60 + end
  61 +
  62 + include FindByContents
  63 +
  64 + ####################################################################
  65 + #### SEARCH
  66 + ####################################################################
  67 + def multiple_search?(searches=nil)
  68 + ['index', 'category_index'].include?(params[:action]) || (searches && searches.size > 1)
  69 + end
  70 + ####################################################################
  71 +
  72 + def logger
  73 + logger = Logger.new(File.join(Rails.root, 'log', "#{ENV['RAILS_ENV'] || 'production'}_api.log"))
  74 + logger.formatter = GrapeLogging::Formatters::Default.new
  75 + logger
  76 + end
  77 +
  78 + def limit
  79 + limit = params[:limit].to_i
  80 + limit = default_limit if limit <= 0
  81 + limit
  82 + end
  83 +
  84 + def period(from_date, until_date)
  85 + return nil if from_date.nil? && until_date.nil?
  86 +
  87 + begin_period = from_date.nil? ? Time.at(0).to_datetime : from_date
  88 + end_period = until_date.nil? ? DateTime.now : until_date
  89 +
  90 + begin_period..end_period
  91 + end
  92 +
  93 + def parse_content_type(content_type)
  94 + return nil if content_type.blank?
  95 + content_type.split(',').map do |content_type|
  96 + content_type.camelcase
  97 + end
  98 + end
  99 +
  100 + def find_article(articles, id)
  101 + article = articles.find(id)
  102 + article.display_to?(current_person) ? article : forbidden!
  103 + end
  104 +
  105 + def post_article(asset, params)
  106 + return forbidden! unless current_person.can_post_content?(asset)
  107 +
  108 + klass_type = params[:content_type] || params[:article].delete(:type) || TinyMceArticle.name
  109 + return forbidden! unless klass_type.constantize <= Article
  110 +
  111 + article = klass_type.constantize.new(params[:article])
  112 + article.last_changed_by = current_person
  113 + article.created_by= current_person
  114 + article.profile = asset
  115 +
  116 + if !article.save
  117 + render_api_errors!(article.errors.full_messages)
  118 + end
  119 + present_partial article, :with => Entities::Article
  120 + end
  121 +
  122 + def present_article(asset)
  123 + article = find_article(asset.articles, params[:id])
  124 + present_partial article, :with => Entities::Article, :params => params
  125 + end
  126 +
  127 + def present_articles_for_asset(asset, method = 'articles')
  128 + articles = find_articles(asset, method)
  129 + present_articles(articles)
  130 + end
  131 +
  132 + def present_articles(articles)
  133 + present_partial paginate(articles), :with => Entities::Article, :params => params
  134 + end
  135 +
  136 + def find_articles(asset, method = 'articles')
  137 + articles = select_filtered_collection_of(asset, method, params)
  138 + if current_person.present?
  139 + articles = articles.display_filter(current_person, nil)
  140 + else
  141 + articles = articles.published
  142 + end
  143 + articles
  144 + end
  145 +
  146 + def find_task(asset, id)
  147 + task = asset.tasks.find(id)
  148 + current_person.has_permission?(task.permission, asset) ? task : forbidden!
  149 + end
  150 +
  151 + def post_task(asset, params)
  152 + klass_type= params[:content_type].nil? ? 'Task' : params[:content_type]
  153 + return forbidden! unless klass_type.constantize <= Task
  154 +
  155 + task = klass_type.constantize.new(params[:task])
  156 + task.requestor_id = current_person.id
  157 + task.target_id = asset.id
  158 + task.target_type = 'Profile'
  159 +
  160 + if !task.save
  161 + render_api_errors!(task.errors.full_messages)
  162 + end
  163 + present_partial task, :with => Entities::Task
  164 + end
  165 +
  166 + def present_task(asset)
  167 + task = find_task(asset, params[:id])
  168 + present_partial task, :with => Entities::Task
  169 + end
  170 +
  171 + def present_tasks(asset)
  172 + tasks = select_filtered_collection_of(asset, 'tasks', params)
  173 + tasks = tasks.select {|t| current_person.has_permission?(t.permission, asset)}
  174 + return forbidden! if tasks.empty? && !current_person.has_permission?(:perform_task, asset)
  175 + present_partial tasks, :with => Entities::Task
  176 + end
  177 +
  178 + def make_conditions_with_parameter(params = {})
  179 + parsed_params = parser_params(params)
  180 + conditions = {}
  181 + from_date = DateTime.parse(parsed_params.delete(:from)) if parsed_params[:from]
  182 + until_date = DateTime.parse(parsed_params.delete(:until)) if parsed_params[:until]
  183 +
  184 + conditions[:type] = parse_content_type(parsed_params.delete(:content_type)) unless parsed_params[:content_type].nil?
  185 +
  186 + conditions[:created_at] = period(from_date, until_date) if from_date || until_date
  187 + conditions.merge!(parsed_params)
  188 +
  189 + conditions
  190 + end
  191 +
  192 + # changing make_order_with_parameters to avoid sql injection
  193 + def make_order_with_parameters(object, method, params)
  194 + order = "created_at DESC"
  195 + unless params[:order].blank?
  196 + if params[:order].include? '\'' or params[:order].include? '"'
  197 + order = "created_at DESC"
  198 + elsif ['RANDOM()', 'RANDOM'].include? params[:order].upcase
  199 + order = 'RANDOM()'
  200 + else
  201 + field_name, direction = params[:order].split(' ')
  202 + assoc = object.class.reflect_on_association(method.to_sym)
  203 + if !field_name.blank? and assoc
  204 + if assoc.klass.attribute_names.include? field_name
  205 + if direction.present? and ['ASC','DESC'].include? direction.upcase
  206 + order = "#{field_name} #{direction.upcase}"
  207 + end
  208 + end
  209 + end
  210 + end
  211 + end
  212 + return order
  213 + end
  214 +
  215 + def make_timestamp_with_parameters_and_method(params, method)
  216 + timestamp = nil
  217 + if params[:timestamp]
  218 + datetime = DateTime.parse(params[:timestamp])
  219 + table_name = method.to_s.singularize.camelize.constantize.table_name
  220 + timestamp = "#{table_name}.updated_at >= '#{datetime}'"
  221 + end
  222 +
  223 + timestamp
  224 + end
  225 +
  226 + def by_reference(scope, params)
  227 + reference_id = params[:reference_id].to_i == 0 ? nil : params[:reference_id].to_i
  228 + if reference_id.nil?
  229 + scope
  230 + else
  231 + created_at = scope.find(reference_id).created_at
  232 + scope.send("#{params.key?(:oldest) ? 'older_than' : 'younger_than'}", created_at)
  233 + end
  234 + end
  235 +
  236 + def by_categories(scope, params)
  237 + category_ids = params[:category_ids]
  238 + if category_ids.nil?
  239 + scope
  240 + else
  241 + scope.joins(:categories).where(:categories => {:id => category_ids})
  242 + end
  243 + end
  244 +
  245 + def select_filtered_collection_of(object, method, params)
  246 + conditions = make_conditions_with_parameter(params)
  247 + order = make_order_with_parameters(object,method,params)
  248 + timestamp = make_timestamp_with_parameters_and_method(params, method)
  249 +
  250 + objects = object.send(method)
  251 + objects = by_reference(objects, params)
  252 + objects = by_categories(objects, params)
  253 +
  254 + objects = objects.where(conditions).where(timestamp).reorder(order)
  255 +
  256 + params[:page] ||= 1
  257 + params[:per_page] ||= limit
  258 + paginate(objects)
  259 + end
  260 +
  261 + def authenticate!
  262 + unauthorized! unless current_user
  263 + end
  264 +
  265 + def profiles_for_person(profiles, person)
  266 + if person
  267 + profiles.listed_for_person(person)
  268 + else
  269 + profiles.visible
  270 + end
  271 + end
  272 +
  273 + # Checks the occurrences of uniqueness of attributes, each attribute must be present in the params hash
  274 + # or a Bad Request error is invoked.
  275 + #
  276 + # Parameters:
  277 + # keys (unique) - A hash consisting of keys that must be unique
  278 + def unique_attributes!(obj, keys)
  279 + keys.each do |key|
  280 + cant_be_saved_request!(key) if obj.find_by(key.to_s => params[key])
  281 + end
  282 + end
  283 +
  284 + def attributes_for_keys(keys)
  285 + attrs = {}
  286 + keys.each do |key|
  287 + attrs[key] = params[key] if params[key].present? or (params.has_key?(key) and params[key] == false)
  288 + end
  289 + attrs
  290 + end
  291 +
  292 + ##########################################
  293 + # error helpers #
  294 + ##########################################
  295 +
  296 + def not_found!
  297 + render_api_error!('404 Not found', 404)
  298 + end
  299 +
  300 + def forbidden!
  301 + render_api_error!('403 Forbidden', 403)
  302 + end
  303 +
  304 + def cant_be_saved_request!(attribute)
  305 + message = _("(Invalid request) %s can't be saved") % attribute
  306 + render_api_error!(message, 400)
  307 + end
  308 +
  309 + def bad_request!(attribute)
  310 + message = _("(Invalid request) %s not given") % attribute
  311 + render_api_error!(message, 400)
  312 + end
  313 +
  314 + def something_wrong!
  315 + message = _("Something wrong happened")
  316 + render_api_error!(message, 400)
  317 + end
  318 +
  319 + def unauthorized!
  320 + render_api_error!(_('Unauthorized'), 401)
  321 + end
  322 +
  323 + def not_allowed!
  324 + render_api_error!(_('Method Not Allowed'), 405)
  325 + end
  326 +
  327 + # javascript_console_message is supposed to be executed as console.log()
  328 + def render_api_error!(user_message, status, log_message = nil, javascript_console_message = nil)
  329 + message_hash = {'message' => user_message, :code => status}
  330 + message_hash[:javascript_console_message] = javascript_console_message if javascript_console_message.present?
  331 + log_msg = "#{status}, User message: #{user_message}"
  332 + log_msg = "#{log_message}, #{log_msg}" if log_message.present?
  333 + log_msg = "#{log_msg}, Javascript Console Message: #{javascript_console_message}" if javascript_console_message.present?
  334 + logger.error log_msg unless Rails.env.test?
  335 + error!(message_hash, status)
  336 + end
  337 +
  338 + def render_api_errors!(messages)
  339 + messages = messages.to_a if messages.class == ActiveModel::Errors
  340 + render_api_error!(messages.join(','), 400)
  341 + end
  342 +
  343 + protected
  344 +
  345 + def set_session_cookie
  346 + cookies['_noosfero_api_session'] = { value: @current_user.private_token, httponly: true } if @current_user.present?
  347 + end
  348 +
  349 + def setup_multitenancy
  350 + Noosfero::MultiTenancy.setup!(request.host)
  351 + end
  352 +
  353 + def detect_stuff_by_domain
  354 + @domain = Domain.by_name(request.host)
  355 + if @domain.nil?
  356 + @environment = Environment.default
  357 + if @environment.nil? && Rails.env.development?
  358 + # This should only happen in development ...
  359 + @environment = Environment.create!(:name => "Noosfero", :is_default => true)
  360 + end
  361 + else
  362 + @environment = @domain.environment
  363 + end
  364 + end
  365 +
  366 + def filter_disabled_plugins_endpoints
  367 + not_found! if Api::App.endpoint_unavailable?(self, @environment)
  368 + end
  369 +
  370 + def asset_with_image params
  371 + if params.has_key? :image_builder
  372 + asset_api_params = params
  373 + asset_api_params[:image_builder] = base64_to_uploadedfile(asset_api_params[:image_builder])
  374 + return asset_api_params
  375 + end
  376 + params
  377 + end
  378 +
  379 + def base64_to_uploadedfile(base64_image)
  380 + tempfile = base64_to_tempfile base64_image
  381 + converted_image = base64_image
  382 + converted_image[:tempfile] = tempfile
  383 + return {uploaded_data: ActionDispatch::Http::UploadedFile.new(converted_image)}
  384 + end
  385 +
  386 + def base64_to_tempfile base64_image
  387 + base64_img_str = base64_image[:tempfile]
  388 + decoded_base64_str = Base64.decode64(base64_img_str)
  389 + tempfile = Tempfile.new(base64_image[:filename])
  390 + tempfile.write(decoded_base64_str.encode("ascii-8bit").force_encoding("utf-8"))
  391 + tempfile.rewind
  392 + tempfile
  393 + end
  394 + private
  395 +
  396 + def parser_params(params)
  397 + parsed_params = {}
  398 + params.map do |k,v|
  399 + parsed_params[k.to_sym] = v if DEFAULT_ALLOWED_PARAMETERS.include?(k.to_sym)
  400 + end
  401 + parsed_params
  402 + end
  403 +
  404 + def default_limit
  405 + 20
  406 + end
  407 +
  408 + def parse_content_type(content_type)
  409 + return nil if content_type.blank?
  410 + content_type.split(',').map do |content_type|
  411 + content_type.camelcase
  412 + end
  413 + end
  414 +
  415 + def period(from_date, until_date)
  416 + begin_period = from_date.nil? ? Time.at(0).to_datetime : from_date
  417 + end_period = until_date.nil? ? DateTime.now : until_date
  418 + begin_period..end_period
  419 + end
  420 + end
  421 +end
app/api/v1/activities.rb 0 → 100644
@@ -0,0 +1,20 @@ @@ -0,0 +1,20 @@
  1 +module Api
  2 + module V1
  3 + class Activities < Grape::API
  4 + before { authenticate! }
  5 +
  6 + resource :profiles do
  7 +
  8 + get ':id/activities' do
  9 + profile = Profile.find_by id: params[:id]
  10 +
  11 + not_found! if profile.blank? || profile.secret || !profile.visible
  12 + forbidden! if !profile.secret && profile.visible && !profile.display_private_info_to?(current_person)
  13 +
  14 + activities = profile.activities.map(&:activity)
  15 + present activities, :with => Entities::Activity, :current_person => current_person
  16 + end
  17 + end
  18 + end
  19 + end
  20 +end
app/api/v1/articles.rb 0 → 100644
@@ -0,0 +1,303 @@ @@ -0,0 +1,303 @@
  1 +module Api
  2 + module V1
  3 + class Articles < Grape::API
  4 +
  5 + ARTICLE_TYPES = Article.descendants.map{|a| a.to_s}
  6 +
  7 + MAX_PER_PAGE = 50
  8 +
  9 + resource :articles do
  10 +
  11 + paginate max_per_page: MAX_PER_PAGE
  12 + # Collect articles
  13 + #
  14 + # Parameters:
  15 + # from - date where the search will begin. If nothing is passed the default date will be the date of the first article created
  16 + # oldest - Collect the oldest articles. If nothing is passed the newest articles are collected
  17 + # limit - amount of articles returned. The default value is 20
  18 + #
  19 + # Example Request:
  20 + # GET host/api/v1/articles?from=2013-04-04-14:41:43&until=2015-04-04-14:41:43&limit=10&private_token=e96fff37c2238fdab074d1dcea8e6317
  21 +
  22 + desc 'Return all articles of all kinds' do
  23 + detail 'Get all articles filtered by fields in query params'
  24 + params Entities::Article.documentation
  25 + success Entities::Article
  26 + failure [[403, 'Forbidden']]
  27 + named 'ArticlesList'
  28 + headers [
  29 + 'Per-Page' => {
  30 + description: 'Total number of records',
  31 + required: false
  32 + }
  33 + ]
  34 + end
  35 + get do
  36 + present_articles_for_asset(environment)
  37 + end
  38 +
  39 + desc "Return one article by id" do
  40 + detail 'Get only one article by id. If not found the "forbidden" http error is showed'
  41 + params Entities::Article.documentation
  42 + success Entities::Article
  43 + failure [[403, 'Forbidden']]
  44 + named 'ArticleById'
  45 + end
  46 + get ':id', requirements: {id: /[0-9]+/} do
  47 + present_article(environment)
  48 + end
  49 +
  50 + post ':id' do
  51 + article = environment.articles.find(params[:id])
  52 + return forbidden! unless article.allow_edit?(current_person)
  53 + article.update_attributes!(asset_with_image(params[:article]))
  54 + present_partial article, :with => Entities::Article
  55 + end
  56 +
  57 + desc 'Report a abuse and/or violent content in a article by id' do
  58 + detail 'Submit a abuse (in general, a content violation) report about a specific article'
  59 + params Entities::Article.documentation
  60 + failure [[400, 'Bad Request']]
  61 + named 'ArticleReportAbuse'
  62 + end
  63 + post ':id/report_abuse' do
  64 + article = find_article(environment.articles, params[:id])
  65 + profile = article.profile
  66 + begin
  67 + abuse_report = AbuseReport.new(:reason => params[:report_abuse])
  68 + if !params[:content_type].blank?
  69 + article = params[:content_type].constantize.find(params[:content_id])
  70 + abuse_report.content = article_reported_version(article)
  71 + end
  72 +
  73 + current_person.register_report(abuse_report, profile)
  74 +
  75 + if !params[:content_type].blank?
  76 + abuse_report = AbuseReport.find_by reporter_id: current_person.id, abuse_complaint_id: profile.opened_abuse_complaint.id
  77 + Delayed::Job.enqueue DownloadReportedImagesJob.new(abuse_report, article)
  78 + end
  79 +
  80 + {
  81 + :success => true,
  82 + :message => _('Your abuse report was registered. The administrators are reviewing your report.'),
  83 + }
  84 + rescue Exception => exception
  85 + #logger.error(exception.to_s)
  86 + render_api_error!(_('Your report couldn\'t be saved due to some problem. Please contact the administrator.'), 400)
  87 + end
  88 +
  89 + end
  90 +
  91 + desc "Returns the articles I voted" do
  92 + detail 'Get the Articles I make a vote'
  93 + failure [[403, 'Forbidden']]
  94 + named 'ArticleFollowers'
  95 + end
  96 + #FIXME refactor this method
  97 + get 'voted_by_me' do
  98 + present_articles(current_person.votes.where(:voteable_type => 'Article').collect(&:voteable))
  99 + end
  100 +
  101 + desc 'Perform a vote on a article by id' do
  102 + detail 'Vote on a specific article with values: 1 (if you like) or -1 (if not)'
  103 + params Entities::UserLogin.documentation
  104 + failure [[401,'Unauthorized']]
  105 + named 'ArticleVote'
  106 + end
  107 + post ':id/vote' do
  108 + authenticate!
  109 + value = (params[:value] || 1).to_i
  110 + # FIXME verify allowed values
  111 + render_api_error!('Vote value not allowed', 400) unless [-1, 1].include?(value)
  112 + article = find_article(environment.articles, params[:id])
  113 + begin
  114 + vote = Vote.new(:voteable => article, :voter => current_person, :vote => value)
  115 + {:vote => vote.save!}
  116 + rescue ActiveRecord::RecordInvalid => e
  117 + render_api_error!(e.message, 400)
  118 + end
  119 + end
  120 +
  121 + desc "Returns the total followers for the article" do
  122 + detail 'Get the followers of a specific article by id'
  123 + failure [[403, 'Forbidden']]
  124 + named 'ArticleFollowers'
  125 + end
  126 + get ':id/followers' do
  127 + article = find_article(environment.articles, params[:id])
  128 + total = article.person_followers.count
  129 + {:total_followers => total}
  130 + end
  131 +
  132 + desc "Return the articles followed by me"
  133 + get 'followed_by_me' do
  134 + present_articles_for_asset(current_person, 'following_articles')
  135 + end
  136 +
  137 + desc "Add a follower for the article" do
  138 + detail 'Add the current user identified by private token, like a follower of a article'
  139 + params Entities::UserLogin.documentation
  140 + failure [[401, 'Unauthorized']]
  141 + named 'ArticleFollow'
  142 + end
  143 + post ':id/follow' do
  144 + authenticate!
  145 + article = find_article(environment.articles, params[:id])
  146 + if article.article_followers.exists?(:person_id => current_person.id)
  147 + {:success => false, :already_follow => true}
  148 + else
  149 + article_follower = ArticleFollower.new
  150 + article_follower.article = article
  151 + article_follower.person = current_person
  152 + article_follower.save!
  153 + {:success => true}
  154 + end
  155 + end
  156 +
  157 + desc 'Return the children of a article identified by id' do
  158 + detail 'Get all children articles of a specific article'
  159 + params Entities::Article.documentation
  160 + failure [[403, 'Forbidden']]
  161 + named 'ArticleChildren'
  162 + end
  163 +
  164 + paginate per_page: MAX_PER_PAGE, max_per_page: MAX_PER_PAGE
  165 + get ':id/children' do
  166 + article = find_article(environment.articles, params[:id])
  167 +
  168 + #TODO make tests for this situation
  169 + votes_order = params.delete(:order) if params[:order]=='votes_score'
  170 + articles = select_filtered_collection_of(article, 'children', params)
  171 + articles = articles.display_filter(current_person, article.profile)
  172 +
  173 + #TODO make tests for this situation
  174 + if votes_order
  175 + articles = articles.joins('left join votes on articles.id=votes.voteable_id').group('articles.id').reorder('sum(coalesce(votes.vote, 0)) DESC')
  176 + end
  177 + Article.hit(articles)
  178 + present_articles(articles)
  179 + end
  180 +
  181 + desc 'Return one child of a article identified by id' do
  182 + detail 'Get a child of a specific article'
  183 + params Entities::Article.documentation
  184 + success Entities::Article
  185 + failure [[403, 'Forbidden']]
  186 + named 'ArticleChild'
  187 + end
  188 + get ':id/children/:child_id' do
  189 + article = find_article(environment.articles, params[:id])
  190 + child = find_article(article.children, params[:child_id])
  191 + child.hit
  192 + present_partial child, :with => Entities::Article
  193 + end
  194 +
  195 + desc 'Suggest a article to another profile' do
  196 + detail 'Suggest a article to another profile (person, community...)'
  197 + params Entities::Article.documentation
  198 + success Entities::Task
  199 + failure [[401,'Unauthorized']]
  200 + named 'ArticleSuggest'
  201 + end
  202 + post ':id/children/suggest' do
  203 + authenticate!
  204 + parent_article = environment.articles.find(params[:id])
  205 +
  206 + suggest_article = SuggestArticle.new
  207 + suggest_article.article = params[:article]
  208 + suggest_article.article[:parent_id] = parent_article.id
  209 + suggest_article.target = parent_article.profile
  210 + suggest_article.requestor = current_person
  211 +
  212 + unless suggest_article.save
  213 + render_api_errors!(suggest_article.article_object.errors.full_messages)
  214 + end
  215 + present_partial suggest_article, :with => Entities::Task
  216 + end
  217 +
  218 + # Example Request:
  219 + # POST api/v1/articles/:id/children?private_token=234298743290432&article[name]=title&article[body]=body
  220 + desc 'Add a child article to a parent identified by id' do
  221 + detail 'Create a new article and associate to a parent'
  222 + params Entities::Article.documentation
  223 + success Entities::Article
  224 + failure [[401,'Unauthorized']]
  225 + named 'ArticleAddChild'
  226 + end
  227 + post ':id/children' do
  228 + parent_article = environment.articles.find(params[:id])
  229 + params[:article][:parent_id] = parent_article.id
  230 + post_article(parent_article.profile, params)
  231 + end
  232 + end
  233 +
  234 + resource :profiles do
  235 + get ':id/home_page' do
  236 + profiles = environment.profiles
  237 + profiles = profiles.visible_for_person(current_person)
  238 + profile = profiles.find_by id: params[:id]
  239 + present_partial profile.home_page, :with => Entities::Article
  240 + end
  241 + end
  242 +
  243 + kinds = %w[profile community person enterprise]
  244 + kinds.each do |kind|
  245 + resource kind.pluralize.to_sym do
  246 + segment "/:#{kind}_id" do
  247 + resource :articles do
  248 +
  249 + desc "Return all articles associate with a profile of type #{kind}" do
  250 + detail 'Get a list of articles of a profile'
  251 + params Entities::Article.documentation
  252 + success Entities::Article
  253 + failure [[403, 'Forbidden']]
  254 + named 'ArticlesOfProfile'
  255 + end
  256 + get do
  257 + profile = environment.send(kind.pluralize).find(params["#{kind}_id"])
  258 +
  259 + if params[:path].present?
  260 + article = profile.articles.find_by path: params[:path]
  261 + if !article || !article.display_to?(current_person)
  262 + article = forbidden!
  263 + end
  264 +
  265 + present_partial article, :with => Entities::Article
  266 + else
  267 +
  268 + present_articles_for_asset(profile)
  269 + end
  270 + end
  271 +
  272 + desc "Return a article associate with a profile of type #{kind}" do
  273 + detail 'Get only one article of a profile'
  274 + params Entities::Article.documentation
  275 + success Entities::Article
  276 + failure [[403, 'Forbidden']]
  277 + named 'ArticleOfProfile'
  278 + end
  279 + get ':id' do
  280 + profile = environment.send(kind.pluralize).find(params["#{kind}_id"])
  281 + present_article(profile)
  282 + end
  283 +
  284 + # Example Request:
  285 + # POST api/v1/{people,communities,enterprises}/:asset_id/articles?private_token=234298743290432&article[name]=title&article[body]=body
  286 + desc "Add a new article associated with a profile of type #{kind}" do
  287 + detail 'Create a new article and associate with a profile'
  288 + params Entities::Article.documentation
  289 + success Entities::Article
  290 + failure [[403, 'Forbidden']]
  291 + named 'ArticleCreateToProfile'
  292 + end
  293 + post do
  294 + profile = environment.send(kind.pluralize).find(params["#{kind}_id"])
  295 + post_article(profile, params)
  296 + end
  297 + end
  298 + end
  299 + end
  300 + end
  301 + end
  302 + end
  303 +end
app/api/v1/blocks.rb 0 → 100644
@@ -0,0 +1,15 @@ @@ -0,0 +1,15 @@
  1 +module Api
  2 + module V1
  3 +
  4 + class Blocks < Grape::API
  5 + resource :blocks do
  6 + get ':id' do
  7 + block = Block.find(params["id"])
  8 + return forbidden! unless block.visible_to_user?(current_person)
  9 + present block, :with => Entities::Block, display_api_content: true
  10 + end
  11 + end
  12 + end
  13 +
  14 + end
  15 +end
app/api/v1/boxes.rb 0 → 100644
@@ -0,0 +1,44 @@ @@ -0,0 +1,44 @@
  1 +module Api
  2 + module V1
  3 +
  4 + class Boxes < Grape::API
  5 +
  6 + kinds = %w[profile community person enterprise]
  7 + kinds.each do |kind|
  8 +
  9 + resource kind.pluralize.to_sym do
  10 +
  11 + segment "/:#{kind}_id" do
  12 + resource :boxes do
  13 + get do
  14 + profile = environment.send(kind.pluralize).find(params["#{kind}_id"])
  15 + present profile.boxes, :with => Entities::Box
  16 + end
  17 + end
  18 + end
  19 + end
  20 +
  21 + end
  22 +
  23 + resource :environments do
  24 + [ '/default', '/context', ':environment_id' ].each do |route|
  25 + segment route do
  26 + resource :boxes do
  27 + get do
  28 + if (route.match(/default/))
  29 + env = Environment.default
  30 + elsif (route.match(/context/))
  31 + env = environment
  32 + else
  33 + env = Environment.find(params[:environment_id])
  34 + end
  35 + present env.boxes, :with => Entities::Box
  36 + end
  37 + end
  38 + end
  39 + end
  40 + end
  41 + end
  42 +
  43 + end
  44 +end
app/api/v1/categories.rb 0 → 100644
@@ -0,0 +1,25 @@ @@ -0,0 +1,25 @@
  1 +module Api
  2 + module V1
  3 + class Categories < Grape::API
  4 +
  5 + resource :categories do
  6 +
  7 + get do
  8 + type = params[:category_type]
  9 + include_parent = params[:include_parent] == 'true'
  10 + include_children = params[:include_children] == 'true'
  11 +
  12 + categories = type.nil? ? environment.categories : environment.categories.where(:type => type)
  13 + present categories, :with => Entities::Category, parent: include_parent, children: include_children
  14 + end
  15 +
  16 + desc "Return the category by id"
  17 + get ':id' do
  18 + present environment.categories.find(params[:id]), :with => Entities::Category, parent: true, children: true
  19 + end
  20 +
  21 + end
  22 +
  23 + end
  24 + end
  25 +end
app/api/v1/comments.rb 0 → 100644
@@ -0,0 +1,49 @@ @@ -0,0 +1,49 @@
  1 +module Api
  2 + module V1
  3 + class Comments < Grape::API
  4 + MAX_PER_PAGE = 20
  5 +
  6 +
  7 + resource :articles do
  8 + paginate max_per_page: MAX_PER_PAGE
  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 + article = find_article(environment.articles, params[:id])
  20 + comments = select_filtered_collection_of(article, :comments, params)
  21 + comments = comments.without_spam
  22 + comments = comments.without_reply if(params[:without_reply].present?)
  23 + comments = plugins.filter(:unavailable_comments, comments)
  24 + present paginate(comments), :with => Entities::Comment, :current_person => current_person
  25 + end
  26 +
  27 + get ":id/comments/:comment_id" do
  28 + article = find_article(environment.articles, params[:id])
  29 + present article.comments.find(params[:comment_id]), :with => Entities::Comment, :current_person => current_person
  30 + end
  31 +
  32 + # Example Request:
  33 + # POST api/v1/articles/12/comments?private_token=2298743290432&body=new comment&title=New
  34 + post ":id/comments" do
  35 + authenticate!
  36 + article = find_article(environment.articles, params[:id])
  37 + options = params.select { |key,v| !['id','private_token'].include?(key) }.merge(:author => current_person, :source => article)
  38 + begin
  39 + comment = Comment.create!(options)
  40 + rescue ActiveRecord::RecordInvalid => e
  41 + render_api_error!(e.message, 400)
  42 + end
  43 + present comment, :with => Entities::Comment, :current_person => current_person
  44 + end
  45 + end
  46 +
  47 + end
  48 + end
  49 +end
app/api/v1/communities.rb 0 → 100644
@@ -0,0 +1,82 @@ @@ -0,0 +1,82 @@
  1 +module Api
  2 + module V1
  3 + class Communities < Grape::API
  4 +
  5 + resource :communities do
  6 +
  7 + # Collect comments from articles
  8 + #
  9 + # Parameters:
  10 + # from - date where the search will begin. If nothing is passed the default date will be the date of the first article created
  11 + # oldest - Collect the oldest comments from reference_id comment. If nothing is passed the newest comments are collected
  12 + # limit - amount of comments returned. The default value is 20
  13 + #
  14 + # Example Request:
  15 + # GET /communities?from=2013-04-04-14:41:43&until=2014-04-04-14:41:43&limit=10
  16 + # GET /communities?reference_id=10&limit=10&oldest
  17 + get do
  18 + communities = select_filtered_collection_of(environment, 'communities', params)
  19 + communities = profiles_for_person(communities, current_person)
  20 + communities = communities.by_location(params) # Must be the last. May return Exception obj
  21 + present communities, :with => Entities::Community, :current_person => current_person
  22 + end
  23 +
  24 +
  25 + # Example Request:
  26 + # POST api/v1/communties?private_token=234298743290432&community[name]=some_name
  27 + # for each custom field for community, add &community[field_name]=field_value to the request
  28 + post do
  29 + authenticate!
  30 + params[:community] ||= {}
  31 +
  32 + params[:community][:custom_values]={}
  33 + params[:community].keys.each do |key|
  34 + params[:community][:custom_values][key]=params[:community].delete(key) if Community.custom_fields(environment).any?{|cf| cf.name==key}
  35 + end
  36 +
  37 + begin
  38 + community = Community.create_after_moderation(current_person, params[:community].merge({:environment => environment}))
  39 + rescue
  40 + community = Community.new(params[:community])
  41 + end
  42 +
  43 + if !community.save
  44 + render_api_errors!(community.errors.full_messages)
  45 + end
  46 +
  47 + present community, :with => Entities::Community, :current_person => current_person
  48 + end
  49 +
  50 + get ':id' do
  51 + community = profiles_for_person(environment.communities, current_person).find_by_id(params[:id])
  52 + present community, :with => Entities::Community, :current_person => current_person
  53 + end
  54 +
  55 + end
  56 +
  57 + resource :people do
  58 +
  59 + segment '/:person_id' do
  60 +
  61 + resource :communities do
  62 +
  63 + get do
  64 + person = environment.people.find(params[:person_id])
  65 +
  66 + not_found! if person.blank?
  67 + forbidden! if !person.display_info_to?(current_person)
  68 +
  69 + communities = select_filtered_collection_of(person, 'communities', params)
  70 + communities = communities.visible
  71 + present communities, :with => Entities::Community, :current_person => current_person
  72 + end
  73 +
  74 + end
  75 +
  76 + end
  77 +
  78 + end
  79 +
  80 + end
  81 + end
  82 +end
app/api/v1/contacts.rb 0 → 100644
@@ -0,0 +1,26 @@ @@ -0,0 +1,26 @@
  1 +module Api
  2 + module V1
  3 + class Contacts < Grape::API
  4 +
  5 + resource :communities do
  6 +
  7 + resource ':id/contact' do
  8 + #contact => {:name => 'some name', :email => 'test@mail.com', :subject => 'some title', :message => 'some message'}
  9 + desc "Send a contact message"
  10 + post do
  11 + profile = environment.communities.find(params[:id])
  12 + forbidden! unless profile.present?
  13 + contact = Contact.new params[:contact].merge(dest: profile)
  14 + if contact.deliver
  15 + {:success => true}
  16 + else
  17 + {:success => false}
  18 + end
  19 + end
  20 +
  21 + end
  22 + end
  23 +
  24 + end
  25 + end
  26 +end
app/api/v1/enterprises.rb 0 → 100644
@@ -0,0 +1,55 @@ @@ -0,0 +1,55 @@
  1 +module Api
  2 + module V1
  3 + class Enterprises < Grape::API
  4 +
  5 + resource :enterprises do
  6 +
  7 + # Collect enterprises from environment
  8 + #
  9 + # Parameters:
  10 + # from - date where the search will begin. If nothing is passed the default date will be the date of the first article created
  11 + # oldest - Collect the oldest comments from reference_id comment. If nothing is passed the newest comments are collected
  12 + # limit - amount of comments returned. The default value is 20
  13 + # georef params - read `Profile.by_location` for more information.
  14 + #
  15 + # Example Request:
  16 + # GET /enterprises?from=2013-04-04-14:41:43&until=2014-04-04-14:41:43&limit=10
  17 + # GET /enterprises?reference_id=10&limit=10&oldest
  18 + get do
  19 + enterprises = select_filtered_collection_of(environment, 'enterprises', params)
  20 + enterprises = enterprises.visible
  21 + enterprises = enterprises.by_location(params) # Must be the last. May return Exception obj.
  22 + present enterprises, :with => Entities::Enterprise, :current_person => current_person
  23 + end
  24 +
  25 + desc "Return one enterprise by id"
  26 + get ':id' do
  27 + enterprise = environment.enterprises.visible.find_by(id: params[:id])
  28 + present enterprise, :with => Entities::Enterprise, :current_person => current_person
  29 + end
  30 +
  31 + end
  32 +
  33 + resource :people do
  34 +
  35 + segment '/:person_id' do
  36 +
  37 + resource :enterprises do
  38 +
  39 + get do
  40 + person = environment.people.find(params[:person_id])
  41 + enterprises = select_filtered_collection_of(person, 'enterprises', params)
  42 + enterprises = enterprises.visible.by_location(params)
  43 + present enterprises, :with => Entities::Enterprise, :current_person => current_person
  44 + end
  45 +
  46 + end
  47 +
  48 + end
  49 +
  50 + end
  51 +
  52 +
  53 + end
  54 + end
  55 +end
app/api/v1/environments.rb 0 → 100644
@@ -0,0 +1,28 @@ @@ -0,0 +1,28 @@
  1 +module Api
  2 + module V1
  3 + class Environments < Grape::API
  4 +
  5 + resource :environment do
  6 +
  7 + desc "Return the person information"
  8 + get '/signup_person_fields' do
  9 + present environment.signup_person_fields
  10 + end
  11 +
  12 + get ':id' do
  13 + local_environment = nil
  14 + if (params[:id] == "default")
  15 + local_environment = Environment.default
  16 + elsif (params[:id] == "context")
  17 + local_environment = environment
  18 + else
  19 + local_environment = Environment.find(params[:id])
  20 + end
  21 + present_partial local_environment, :with => Entities::Environment, :is_admin => is_admin?(local_environment)
  22 + end
  23 +
  24 + end
  25 +
  26 + end
  27 + end
  28 +end
app/api/v1/people.rb 0 → 100644
@@ -0,0 +1,127 @@ @@ -0,0 +1,127 @@
  1 +module Api
  2 + module V1
  3 + class People < Grape::API
  4 +
  5 + MAX_PER_PAGE = 50
  6 +
  7 + desc 'API Root'
  8 +
  9 + resource :people do
  10 + paginate max_per_page: MAX_PER_PAGE
  11 +
  12 + # -- A note about privacy --
  13 + # We wold find people by location, but we must test if the related
  14 + # fields are public. We can't do it now, with SQL, while the location
  15 + # data and the fields_privacy are a serialized settings.
  16 + # We must build a new table for profile data, where we can set meta-data
  17 + # like:
  18 + # | id | profile_id | key | value | privacy_level | source |
  19 + # | 1 | 99 | city | Salvador | friends | user |
  20 + # | 2 | 99 | lng | -38.521 | me only | automatic |
  21 +
  22 + # Collect people from environment
  23 + #
  24 + # Parameters:
  25 + # from - date where the search will begin. If nothing is passed the default date will be the date of the first article created
  26 + # oldest - Collect the oldest comments from reference_id comment. If nothing is passed the newest comments are collected
  27 + # limit - amount of comments returned. The default value is 20
  28 + #
  29 + # Example Request:
  30 + # GET /people?from=2013-04-04-14:41:43&until=2014-04-04-14:41:43&limit=10
  31 + # GET /people?reference_id=10&limit=10&oldest
  32 +
  33 + desc "Find environment's people"
  34 + get do
  35 + people = select_filtered_collection_of(environment, 'people', params)
  36 + people = people.visible
  37 + present_partial people, :with => Entities::Person, :current_person => current_person
  38 + end
  39 +
  40 + desc "Return the logged user information"
  41 + get "/me" do
  42 + authenticate!
  43 + present_partial current_person, :with => Entities::Person, :current_person => current_person
  44 + end
  45 +
  46 + desc "Return the person information"
  47 + get ':id' do
  48 + person = environment.people.visible.find_by(id: params[:id])
  49 + return not_found! if person.blank?
  50 + present person, :with => Entities::Person, :current_person => current_person
  51 + end
  52 +
  53 + desc "Update person information"
  54 + post ':id' do
  55 + authenticate!
  56 + return forbidden! if current_person.id.to_s != params[:id]
  57 + current_person.update_attributes!(asset_with_image(params[:person]))
  58 + present current_person, :with => Entities::Person, :current_person => current_person
  59 + end
  60 +
  61 + # POST api/v1/people?person[login]=some_login&person[password]=some_password&person[name]=Jack
  62 + # for each custom field for person, add &person[field_name]=field_value to the request
  63 + desc "Create person"
  64 + post do
  65 + authenticate!
  66 + user_data = {}
  67 + user_data[:login] = params[:person].delete(:login) || params[:person][:identifier]
  68 + user_data[:email] = params[:person].delete(:email)
  69 + user_data[:password] = params[:person].delete(:password)
  70 + user_data[:password_confirmation] = params[:person].delete(:password_confirmation)
  71 +
  72 + params[:person][:custom_values]={}
  73 + params[:person].keys.each do |key|
  74 + params[:person][:custom_values][key]=params[:person].delete(key) if Person.custom_fields(environment).any?{|cf| cf.name==key}
  75 + end
  76 +
  77 + user = User.build(user_data, asset_with_image(params[:person]), environment)
  78 +
  79 + begin
  80 + user.signup!
  81 + rescue ActiveRecord::RecordInvalid
  82 + render_api_errors!(user.errors.full_messages)
  83 + end
  84 +
  85 + present user.person, :with => Entities::Person, :current_person => user.person
  86 + end
  87 +
  88 + desc "Return the person friends"
  89 + get ':id/friends' do
  90 + person = environment.people.visible.find_by(id: params[:id])
  91 + return not_found! if person.blank?
  92 + friends = person.friends.visible
  93 + present friends, :with => Entities::Person, :current_person => current_person
  94 + end
  95 +
  96 + desc "Return the person permissions on other profiles"
  97 + get ":id/permissions" do
  98 + authenticate!
  99 + person = environment.people.find(params[:id])
  100 + return not_found! if person.blank?
  101 + return forbidden! unless current_person == person || environment.admins.include?(current_person)
  102 +
  103 + output = {}
  104 + person.role_assignments.map do |role_assigment|
  105 + if role_assigment.resource.respond_to?(:identifier)
  106 + output[role_assigment.resource.identifier] = role_assigment.role.permissions
  107 + end
  108 + end
  109 + present output
  110 + end
  111 + end
  112 +
  113 + resource :profiles do
  114 + segment '/:profile_id' do
  115 + resource :members do
  116 + paginate max_per_page: MAX_PER_PAGE
  117 + get do
  118 + profile = environment.profiles.find_by id: params[:profile_id]
  119 + members = select_filtered_collection_of(profile, 'members', params)
  120 + present members, :with => Entities::Person, :current_person => current_person
  121 + end
  122 + end
  123 + end
  124 + end
  125 + end
  126 + end
  127 +end
app/api/v1/profiles.rb 0 → 100644
@@ -0,0 +1,42 @@ @@ -0,0 +1,42 @@
  1 +module Api
  2 + module V1
  3 + class Profiles < Grape::API
  4 +
  5 + resource :profiles do
  6 +
  7 + get do
  8 + profiles = select_filtered_collection_of(environment, 'profiles', params)
  9 + profiles = profiles.visible
  10 + profiles = profiles.by_location(params) # Must be the last. May return Exception obj.
  11 + present profiles, :with => Entities::Profile, :current_person => current_person
  12 + end
  13 +
  14 + get ':id' do
  15 + profiles = environment.profiles
  16 + profiles = profiles.visible
  17 + profile = profiles.find_by id: params[:id]
  18 +
  19 + if profile
  20 + present profile, :with => Entities::Profile, :current_person => current_person
  21 + else
  22 + not_found!
  23 + end
  24 + end
  25 +
  26 + delete ':id' do
  27 + authenticate!
  28 + profiles = environment.profiles
  29 + profile = profiles.find_by id: params[:id]
  30 +
  31 + not_found! if profile.blank?
  32 +
  33 + if current_person.has_permission?(:destroy_profile, profile)
  34 + profile.destroy
  35 + else
  36 + forbidden!
  37 + end
  38 + end
  39 + end
  40 + end
  41 + end
  42 +end
app/api/v1/search.rb 0 → 100644
@@ -0,0 +1,37 @@ @@ -0,0 +1,37 @@
  1 +module Api
  2 + module V1
  3 + class Search < Grape::API
  4 +
  5 + resource :search do
  6 + resource :article do
  7 + paginate max_per_page: 200
  8 + get do
  9 + # Security checks
  10 + sanitize_params_hash(params)
  11 + # Api::Helpers
  12 + asset = :articles
  13 + context = environment
  14 +
  15 + profile = environment.profiles.find(params[:profile_id]) if params[:profile_id]
  16 + scope = profile.nil? ? environment.articles.is_public : profile.articles.is_public
  17 + scope = scope.where(:type => params[:type]) if params[:type] && !(params[:type] == 'Article')
  18 + scope = scope.where(make_conditions_with_parameter(params))
  19 + scope = scope.joins(:categories).where(:categories => {:id => params[:category_ids]}) if params[:category_ids].present?
  20 + scope = scope.where('articles.children_count > 0') if params[:has_children].present?
  21 + query = params[:query] || ""
  22 + order = "more_recent"
  23 +
  24 + options = {:filter => order, :template_id => params[:template_id]}
  25 +
  26 + search_result = find_by_contents(asset, context, scope, query, {:page => 1}, options)
  27 +
  28 + articles = search_result[:results]
  29 +
  30 + present_articles(articles)
  31 + end
  32 + end
  33 + end
  34 +
  35 + end
  36 + end
  37 +end
app/api/v1/session.rb 0 → 100644
@@ -0,0 +1,157 @@ @@ -0,0 +1,157 @@
  1 +require "uri"
  2 +
  3 +module Api
  4 + module V1
  5 + class Session < Grape::API
  6 +
  7 + # Login to get token
  8 + #
  9 + # Parameters:
  10 + # login (*required) - user login or email
  11 + # password (required) - user password
  12 + #
  13 + # Example Request:
  14 + # POST http://localhost:3000/api/v1/login?login=adminuser&password=admin
  15 + post "/login" do
  16 + begin
  17 + user ||= User.authenticate(params[:login], params[:password], environment)
  18 + rescue User::UserNotActivated => e
  19 + render_api_error!(e.message, 401)
  20 + end
  21 +
  22 + return unauthorized! unless user
  23 + @current_user = user
  24 + present user, :with => Entities::UserLogin, :current_person => current_person
  25 + end
  26 +
  27 + post "/login_from_cookie" do
  28 + return unauthorized! if cookies[:auth_token].blank?
  29 + user = User.where(remember_token: cookies[:auth_token]).first
  30 + return unauthorized! unless user && user.activated?
  31 + @current_user = user
  32 + present user, :with => Entities::UserLogin, :current_person => current_person
  33 + end
  34 +
  35 + # Create user.
  36 + #
  37 + # Parameters:
  38 + # email (required) - Email
  39 + # password (required) - Password
  40 + # login - login
  41 + # Example Request:
  42 + # POST /register?email=some@mail.com&password=pas&password_confirmation=pas&login=some
  43 + params do
  44 + requires :email, type: String, desc: _("Email")
  45 + requires :login, type: String, desc: _("Login")
  46 + requires :password, type: String, desc: _("Password")
  47 + end
  48 +
  49 + post "/register" do
  50 + attrs = attributes_for_keys [:email, :login, :password, :password_confirmation] + environment.signup_person_fields
  51 + name = params[:name].present? ? params[:name] : attrs[:email]
  52 + attrs[:password_confirmation] = attrs[:password] if !attrs.has_key?(:password_confirmation)
  53 + user = User.new(attrs.merge(:name => name))
  54 +
  55 + begin
  56 + user.signup!
  57 + user.generate_private_token! if user.activated?
  58 + present user, :with => Entities::UserLogin, :current_person => user.person
  59 + rescue ActiveRecord::RecordInvalid
  60 + message = user.errors.as_json.merge((user.person.present? ? user.person.errors : {}).as_json).to_json
  61 + render_api_error!(message, 400)
  62 + end
  63 + end
  64 +
  65 + params do
  66 + requires :activation_code, type: String, desc: _("Activation token")
  67 + end
  68 +
  69 + # Activate a user.
  70 + #
  71 + # Parameter:
  72 + # activation_code (required) - Activation token
  73 + # Example Request:
  74 + # PATCH /activate?activation_code=28259abd12cc6a64ef9399cf3286cb998b96aeaf
  75 + patch "/activate" do
  76 + user = User.find_by activation_code: params[:activation_code]
  77 + if user
  78 + unless user.environment.enabled?('admin_must_approve_new_users')
  79 + if user.activate
  80 + user.generate_private_token!
  81 + present user, :with => Entities::UserLogin, :current_person => current_person
  82 + end
  83 + else
  84 + if user.create_moderate_task
  85 + user.activation_code = nil
  86 + user.save!
  87 +
  88 + # Waiting for admin moderate user registration
  89 + status 202
  90 + body({
  91 + :message => 'Waiting for admin moderate user registration'
  92 + })
  93 + end
  94 + end
  95 + else
  96 + # Token not found in database
  97 + render_api_error!(_('Token is invalid'), 412)
  98 + end
  99 + end
  100 +
  101 + # Request a new password.
  102 + #
  103 + # Parameters:
  104 + # value (required) - Email or login
  105 + # Example Request:
  106 + # POST /forgot_password?value=some@mail.com
  107 + post "/forgot_password" do
  108 + requestors = fetch_requestors(params[:value])
  109 + not_found! if requestors.blank?
  110 + remote_ip = (request.respond_to?(:remote_ip) && request.remote_ip) || (env && env['REMOTE_ADDR'])
  111 + requestors.each do |requestor|
  112 + ChangePassword.create!(:requestor => requestor)
  113 + end
  114 + end
  115 +
  116 + # Resend activation code.
  117 + #
  118 + # Parameters:
  119 + # value (required) - Email or login
  120 + # Example Request:
  121 + # POST /resend_activation_code?value=some@mail.com
  122 + post "/resend_activation_code" do
  123 + requestors = fetch_requestors(params[:value])
  124 + not_found! if requestors.blank?
  125 + remote_ip = (request.respond_to?(:remote_ip) && request.remote_ip) || (env && env['REMOTE_ADDR'])
  126 + requestors.each do |requestor|
  127 + requestor.user.resend_activation_code
  128 + end
  129 + present requestors.map(&:user), :with => Entities::UserLogin
  130 + end
  131 +
  132 + params do
  133 + requires :code, type: String, desc: _("Forgot password code")
  134 + end
  135 + # Change password
  136 + #
  137 + # Parameters:
  138 + # code (required) - Change password code
  139 + # password (required)
  140 + # password_confirmation (required)
  141 + # Example Request:
  142 + # PATCH /new_password?code=xxxx&password=secret&password_confirmation=secret
  143 + patch "/new_password" do
  144 + change_password = ChangePassword.find_by code: params[:code]
  145 + not_found! if change_password.nil?
  146 +
  147 + if change_password.update_attributes(:password => params[:password], :password_confirmation => params[:password_confirmation])
  148 + change_password.finish
  149 + present change_password.requestor.user, :with => Entities::UserLogin, :current_person => current_person
  150 + else
  151 + something_wrong!
  152 + end
  153 + end
  154 +
  155 + end
  156 + end
  157 +end
app/api/v1/tags.rb 0 → 100644
@@ -0,0 +1,26 @@ @@ -0,0 +1,26 @@
  1 +module Api
  2 + module V1
  3 + class Tags < Grape::API
  4 + before { authenticate! }
  5 +
  6 + resource :articles do
  7 +
  8 + resource ':id/tags' do
  9 +
  10 + get do
  11 + article = find_article(environment.articles, params[:id])
  12 + present article.tag_list
  13 + end
  14 +
  15 + desc "Add a tag to an article"
  16 + post do
  17 + article = find_article(environment.articles, params[:id])
  18 + article.tag_list=params[:tags]
  19 + article.save
  20 + present article.tag_list
  21 + end
  22 + end
  23 + end
  24 + end
  25 + end
  26 +end
app/api/v1/tasks.rb 0 → 100644
@@ -0,0 +1,57 @@ @@ -0,0 +1,57 @@
  1 +module Api
  2 + module V1
  3 + class Tasks < Grape::API
  4 +# before { authenticate! }
  5 +
  6 +# ARTICLE_TYPES = Article.descendants.map{|a| a.to_s}
  7 +
  8 + resource :tasks do
  9 +
  10 + # Collect tasks
  11 + #
  12 + # Parameters:
  13 + # from - date where the search will begin. If nothing is passed the default date will be the date of the first article created
  14 + # oldest - Collect the oldest articles. If nothing is passed the newest articles are collected
  15 + # limit - amount of articles returned. The default value is 20
  16 + #
  17 + # Example Request:
  18 + # GET host/api/v1/tasks?from=2013-04-04-14:41:43&until=2015-04-04-14:41:43&limit=10&private_token=e96fff37c2238fdab074d1dcea8e6317
  19 + get do
  20 + tasks = select_filtered_collection_of(environment, 'tasks', params)
  21 + tasks = tasks.select {|t| current_person.has_permission?(t.permission, environment)}
  22 + present_partial tasks, :with => Entities::Task
  23 + end
  24 +
  25 + desc "Return the task id"
  26 + get ':id' do
  27 + task = find_task(environment, params[:id])
  28 + present_partial task, :with => Entities::Task
  29 + end
  30 + end
  31 +
  32 + kinds = %w[community person enterprise]
  33 + kinds.each do |kind|
  34 + resource kind.pluralize.to_sym do
  35 + segment "/:#{kind}_id" do
  36 + resource :tasks do
  37 + get do
  38 + profile = environment.send(kind.pluralize).find(params["#{kind}_id"])
  39 + present_tasks(profile)
  40 + end
  41 +
  42 + get ':id' do
  43 + profile = environment.send(kind.pluralize).find(params["#{kind}_id"])
  44 + present_task(profile)
  45 + end
  46 +
  47 + post do
  48 + profile = environment.send(kind.pluralize).find(params["#{kind}_id"])
  49 + post_task(profile, params)
  50 + end
  51 + end
  52 + end
  53 + end
  54 + end
  55 + end
  56 + end
  57 +end
app/api/v1/users.rb 0 → 100644
@@ -0,0 +1,43 @@ @@ -0,0 +1,43 @@
  1 +module Api
  2 + module V1
  3 + class Users < Grape::API
  4 +
  5 + resource :users do
  6 +
  7 + get do
  8 + users = select_filtered_collection_of(environment, 'users', params)
  9 + users = users.select{|u| u.person.display_info_to? current_person}
  10 + present users, :with => Entities::User, :current_person => current_person
  11 + end
  12 +
  13 + get "/me" do
  14 + authenticate!
  15 + present current_user, :with => Entities::User, :current_person => current_person
  16 + end
  17 +
  18 + get ":id" do
  19 + user = environment.users.find_by id: params[:id]
  20 + if user
  21 + present user, :with => Entities::User, :current_person => current_person
  22 + else
  23 + not_found!
  24 + end
  25 + end
  26 +
  27 + get ":id/permissions" do
  28 + authenticate!
  29 + user = environment.users.find(params[:id])
  30 + output = {}
  31 + user.person.role_assignments.map do |role_assigment|
  32 + if role_assigment.resource.respond_to?(:identifier) && role_assigment.resource.identifier == params[:profile]
  33 + output[:permissions] = role_assigment.role.permissions
  34 + end
  35 + end
  36 + present output
  37 + end
  38 +
  39 + end
  40 +
  41 + end
  42 + end
  43 +end
app/controllers/public/api_controller.rb
@@ -13,7 +13,7 @@ class ApiController &lt; PublicController @@ -13,7 +13,7 @@ class ApiController &lt; PublicController
13 private 13 private
14 14
15 def endpoints 15 def endpoints
16 - Noosfero::API::API.endpoints(environment) 16 + Api::App.endpoints(environment)
17 end 17 end
18 18
19 end 19 end
app/models/profile.rb
@@ -1093,6 +1093,11 @@ private :generate_url, :url_options @@ -1093,6 +1093,11 @@ private :generate_url, :url_options
1093 self.data[:fields_privacy] 1093 self.data[:fields_privacy]
1094 end 1094 end
1095 1095
  1096 + # abstract
  1097 + def active_fields
  1098 + []
  1099 + end
  1100 +
1096 def public_fields 1101 def public_fields
1097 self.active_fields 1102 self.active_fields
1098 end 1103 end
app/models/recent_documents_block.rb
@@ -31,7 +31,7 @@ class RecentDocumentsBlock &lt; Block @@ -31,7 +31,7 @@ class RecentDocumentsBlock &lt; Block
31 end 31 end
32 32
33 def api_content 33 def api_content
34 - Noosfero::API::Entities::ArticleBase.represent(docs).as_json 34 + Api::Entities::ArticleBase.represent(docs).as_json
35 end 35 end
36 36
37 def display_api_content_by_default? 37 def display_api_content_by_default?
app/views/api/playground.html.erb
1 <h1>API Playground</h1> 1 <h1>API Playground</h1>
2 2
3 <script> 3 <script>
4 -<% prefix = Noosfero::API::API.prefix %> 4 +<% prefix = Api::App.prefix %>
5 var prefix = <%= prefix.to_json %>; 5 var prefix = <%= prefix.to_json %>;
6 var endpoints = <%= 6 var endpoints = <%=
7 endpoints.map do |endpoint| 7 endpoints.map do |endpoint|
@@ -20,6 +20,6 @@ rails_app = Rack::Builder.new do @@ -20,6 +20,6 @@ rails_app = Rack::Builder.new do
20 end 20 end
21 21
22 run Rack::Cascade.new([ 22 run Rack::Cascade.new([
23 - Noosfero::API::API, 23 + Api::App,
24 rails_app 24 rails_app
25 ]) 25 ])
config/application.rb
@@ -39,6 +39,7 @@ module Noosfero @@ -39,6 +39,7 @@ module Noosfero
39 39
40 # Custom directories with classes and modules you want to be autoloadable. 40 # Custom directories with classes and modules you want to be autoloadable.
41 config.autoload_paths << config.root.join('lib') 41 config.autoload_paths << config.root.join('lib')
  42 + config.autoload_paths << config.root.join('app')
42 config.autoload_paths << config.root.join('app/jobs') 43 config.autoload_paths << config.root.join('app/jobs')
43 config.autoload_paths << config.root.join('app/sweepers') 44 config.autoload_paths << config.root.join('app/sweepers')
44 config.autoload_paths.concat Dir["#{config.root}/app/controllers/**/"] 45 config.autoload_paths.concat Dir["#{config.root}/app/controllers/**/"]
lib/noosfero/api/api.rb
@@ -1,94 +0,0 @@ @@ -1,94 +0,0 @@
1 -require 'grape'  
2 -#require 'rack/contrib'  
3 -Dir["#{Rails.root}/lib/noosfero/api/*.rb"].each {|file| require file unless file =~ /api\.rb/}  
4 -  
5 -module Noosfero  
6 - module API  
7 - class API < Grape::API  
8 - use Rack::JSONP  
9 -  
10 - logger = Logger.new(File.join(Rails.root, 'log', "#{ENV['RAILS_ENV'] || 'production'}_api.log"))  
11 - logger.formatter = GrapeLogging::Formatters::Default.new  
12 - #use GrapeLogging::Middleware::RequestLogger, { logger: logger }  
13 -  
14 - rescue_from :all do |e|  
15 - logger.error e  
16 - error! e.message, 500  
17 - end  
18 -  
19 - @@NOOSFERO_CONF = nil  
20 - def self.NOOSFERO_CONF  
21 - if @@NOOSFERO_CONF  
22 - @@NOOSFERO_CONF  
23 - else  
24 - file = Rails.root.join('config', 'noosfero.yml')  
25 - @@NOOSFERO_CONF = File.exists?(file) ? YAML.load_file(file)[Rails.env] || {} : {}  
26 - end  
27 - end  
28 -  
29 - before { set_locale }  
30 - before { setup_multitenancy }  
31 - before { detect_stuff_by_domain }  
32 - before { filter_disabled_plugins_endpoints }  
33 - before { init_noosfero_plugins }  
34 - after { set_session_cookie }  
35 -  
36 - version 'v1'  
37 - prefix [ENV['RAILS_RELATIVE_URL_ROOT'], "api"].compact.join('/')  
38 - format :json  
39 - content_type :txt, "text/plain"  
40 -  
41 - helpers APIHelpers  
42 -  
43 - mount V1::Articles  
44 - mount V1::Comments  
45 - mount V1::Users  
46 - mount V1::Communities  
47 - mount V1::People  
48 - mount V1::Enterprises  
49 - mount V1::Categories  
50 - mount V1::Tasks  
51 - mount V1::Tags  
52 - mount V1::Environments  
53 - mount V1::Search  
54 - mount V1::Contacts  
55 - mount V1::Boxes  
56 - mount V1::Blocks  
57 - mount V1::Profiles  
58 - mount V1::Activities  
59 -  
60 - mount Session  
61 -  
62 - # hook point which allow plugins to add Grape::API extensions to API::API  
63 - #finds for plugins which has api mount points classes defined (the class should extends Grape::API)  
64 - @plugins = Noosfero::Plugin.all.map { |p| p.constantize }  
65 - @plugins.each do |klass|  
66 - if klass.public_methods.include? :api_mount_points  
67 - klass.api_mount_points.each do |mount_class|  
68 - mount mount_class if mount_class && ( mount_class < Grape::API )  
69 - end  
70 - end  
71 - end  
72 -  
73 - def self.endpoint_unavailable?(endpoint, environment)  
74 - api_class = endpoint.options[:app] || endpoint.options[:for]  
75 - if api_class.present?  
76 - klass = api_class.name.deconstantize.constantize  
77 - return klass < Noosfero::Plugin && !environment.plugin_enabled?(klass)  
78 - end  
79 - end  
80 -  
81 - class << self  
82 - def endpoints_with_plugins(environment = nil)  
83 - if environment.present?  
84 - cloned_endpoints = endpoints_without_plugins.dup  
85 - cloned_endpoints.delete_if { |endpoint| endpoint_unavailable?(endpoint, environment) }  
86 - else  
87 - endpoints_without_plugins  
88 - end  
89 - end  
90 - alias_method_chain :endpoints, :plugins  
91 - end  
92 - end  
93 - end  
94 -end  
lib/noosfero/api/entities.rb
@@ -1,269 +0,0 @@ @@ -1,269 +0,0 @@
1 -module Noosfero  
2 - module API  
3 - module Entities  
4 -  
5 - Entity.format_with :timestamp do |date|  
6 - date.strftime('%Y/%m/%d %H:%M:%S') if date  
7 - end  
8 -  
9 - PERMISSIONS = {  
10 - :admin => 0,  
11 - :self => 10,  
12 - :private_content => 20,  
13 - :logged_user => 30,  
14 - :anonymous => 40  
15 - }  
16 -  
17 - def self.can_display_profile_field? profile, options, permission_options={}  
18 - permissions={:field => "", :permission => :private_content}  
19 - permissions.merge!(permission_options)  
20 - field = permissions[:field]  
21 - permission = permissions[:permission]  
22 - return true if profile.public? && profile.public_fields.map{|f| f.to_sym}.include?(field.to_sym)  
23 -  
24 - current_person = options[:current_person]  
25 -  
26 - current_permission = if current_person.present?  
27 - if current_person.is_admin?  
28 - :admin  
29 - elsif current_person == profile  
30 - :self  
31 - elsif profile.display_private_info_to?(current_person)  
32 - :private_content  
33 - else  
34 - :logged_user  
35 - end  
36 - else  
37 - :anonymous  
38 - end  
39 - PERMISSIONS[current_permission] <= PERMISSIONS[permission]  
40 - end  
41 -  
42 - class Image < Entity  
43 - root 'images', 'image'  
44 -  
45 - expose :url do |image, options|  
46 - image.public_filename  
47 - end  
48 -  
49 - expose :icon_url do |image, options|  
50 - image.public_filename(:icon)  
51 - end  
52 -  
53 - expose :minor_url do |image, options|  
54 - image.public_filename(:minor)  
55 - end  
56 -  
57 - expose :portrait_url do |image, options|  
58 - image.public_filename(:portrait)  
59 - end  
60 -  
61 - expose :thumb_url do |image, options|  
62 - image.public_filename(:thumb)  
63 - end  
64 - end  
65 -  
66 - class CategoryBase < Entity  
67 - root 'categories', 'category'  
68 - expose :name, :id, :slug  
69 - end  
70 -  
71 - class Category < CategoryBase  
72 - root 'categories', 'category'  
73 - expose :full_name do |category, options|  
74 - category.full_name  
75 - end  
76 - expose :parent, :using => CategoryBase, if: { parent: true }  
77 - expose :children, :using => CategoryBase, if: { children: true }  
78 - expose :image, :using => Image  
79 - expose :display_color  
80 - end  
81 -  
82 - class Region < Category  
83 - root 'regions', 'region'  
84 - expose :parent_id  
85 - end  
86 -  
87 - class Block < Entity  
88 - root 'blocks', 'block'  
89 - expose :id, :type, :settings, :position, :enabled  
90 - expose :mirror, :mirror_block_id, :title  
91 - expose :api_content, if: lambda { |object, options| options[:display_api_content] || object.display_api_content_by_default? }  
92 - end  
93 -  
94 - class Box < Entity  
95 - root 'boxes', 'box'  
96 - expose :id, :position  
97 - expose :blocks, :using => Block  
98 - end  
99 -  
100 - class Profile < Entity  
101 - expose :identifier, :name, :id  
102 - expose :created_at, :format_with => :timestamp  
103 - expose :updated_at, :format_with => :timestamp  
104 - expose :additional_data do |profile, options|  
105 - hash ={}  
106 - profile.public_values.each do |value|  
107 - hash[value.custom_field.name]=value.value  
108 - end  
109 -  
110 - private_values = profile.custom_field_values - profile.public_values  
111 - private_values.each do |value|  
112 - if Entities.can_display_profile_field?(profile,options)  
113 - hash[value.custom_field.name]=value.value  
114 - end  
115 - end  
116 - hash  
117 - end  
118 - expose :image, :using => Image  
119 - expose :region, :using => Region  
120 - expose :type  
121 - expose :custom_header  
122 - expose :custom_footer  
123 - end  
124 -  
125 - class UserBasic < Entity  
126 - expose :id  
127 - expose :login  
128 - end  
129 -  
130 - class Person < Profile  
131 - root 'people', 'person'  
132 - expose :user, :using => UserBasic, documentation: {type: 'User', desc: 'The user data of a person' }  
133 - expose :vote_count  
134 - expose :comments_count do |person, options|  
135 - person.comments.count  
136 - end  
137 - expose :following_articles_count do |person, options|  
138 - person.following_articles.count  
139 - end  
140 - expose :articles_count do |person, options|  
141 - person.articles.count  
142 - end  
143 - end  
144 -  
145 - class Enterprise < Profile  
146 - root 'enterprises', 'enterprise'  
147 - end  
148 -  
149 - class Community < Profile  
150 - root 'communities', 'community'  
151 - expose :description  
152 - expose :admins, :if => lambda { |community, options| community.display_info_to? options[:current_person]} do |community, options|  
153 - community.admins.map{|admin| {"name"=>admin.name, "id"=>admin.id, "username" => admin.identifier}}  
154 - end  
155 - expose :categories, :using => Category  
156 - expose :members, :using => Person , :if => lambda{ |community, options| community.display_info_to? options[:current_person] }  
157 - end  
158 -  
159 - class CommentBase < Entity  
160 - expose :body, :title, :id  
161 - expose :created_at, :format_with => :timestamp  
162 - expose :author, :using => Profile  
163 - expose :reply_of, :using => CommentBase  
164 - end  
165 -  
166 - class Comment < CommentBase  
167 - root 'comments', 'comment'  
168 - expose :children, as: :replies, :using => Comment  
169 - end  
170 -  
171 - class ArticleBase < Entity  
172 - root 'articles', 'article'  
173 - expose :id  
174 - expose :body  
175 - expose :abstract, documentation: {type: 'String', desc: 'Teaser of the body'}  
176 - expose :created_at, :format_with => :timestamp  
177 - expose :updated_at, :format_with => :timestamp  
178 - expose :title, :documentation => {:type => "String", :desc => "Title of the article"}  
179 - expose :created_by, :as => :author, :using => Profile, :documentation => {type: 'Profile', desc: 'The profile author that create the article'}  
180 - expose :profile, :using => Profile, :documentation => {type: 'Profile', desc: 'The profile associated with the article'}  
181 - expose :categories, :using => Category  
182 - expose :image, :using => Image  
183 - expose :votes_for  
184 - expose :votes_against  
185 - expose :setting  
186 - expose :position  
187 - expose :hits  
188 - expose :start_date  
189 - expose :end_date, :documentation => {type: 'DateTime', desc: 'The date of finish of the article'}  
190 - expose :tag_list  
191 - expose :children_count  
192 - expose :slug, :documentation => {:type => "String", :desc => "Trimmed and parsed name of a article"}  
193 - expose :path  
194 - expose :followers_count  
195 - expose :votes_count  
196 - expose :comments_count  
197 - expose :archived, :documentation => {:type => "Boolean", :desc => "Defines if a article is readonly"}  
198 - expose :type  
199 - expose :comments, using: CommentBase, :if => lambda{|obj,opt| opt[:params] && ['1','true',true].include?(opt[:params][:show_comments])}  
200 - expose :published  
201 - expose :accept_comments?, as: :accept_comments  
202 - end  
203 -  
204 - class Article < ArticleBase  
205 - root 'articles', 'article'  
206 - expose :parent, :using => ArticleBase  
207 - expose :children, :using => ArticleBase do |article, options|  
208 - article.children.published.limit(Noosfero::API::V1::Articles::MAX_PER_PAGE)  
209 - end  
210 - end  
211 -  
212 - class User < Entity  
213 - root 'users', 'user'  
214 -  
215 - attrs = [:id,:login,:email,:activated?]  
216 - aliases = {:activated? => :activated}  
217 -  
218 - attrs.each do |attribute|  
219 - name = aliases.has_key?(attribute) ? aliases[attribute] : attribute  
220 - expose attribute, :as => name, :if => lambda{|user,options| Entities.can_display_profile_field?(user.person, options, {:field => attribute})}  
221 - end  
222 -  
223 - expose :person, :using => Person, :if => lambda{|user,options| user.person.display_info_to? options[:current_person]}  
224 - expose :permissions, :if => lambda{|user,options| Entities.can_display_profile_field?(user.person, options, {:field => :permissions, :permission => :self})} do |user, options|  
225 - output = {}  
226 - user.person.role_assignments.map do |role_assigment|  
227 - if role_assigment.resource.respond_to?(:identifier) && !role_assigment.role.nil?  
228 - output[role_assigment.resource.identifier] = role_assigment.role.permissions  
229 - end  
230 - end  
231 - output  
232 - end  
233 - end  
234 -  
235 - class UserLogin < User  
236 - root 'users', 'user'  
237 - expose :private_token, documentation: {type: 'String', desc: 'A valid authentication code for post/delete api actions'}, if: lambda {|object, options| object.activated? }  
238 - end  
239 -  
240 - class Task < Entity  
241 - root 'tasks', 'task'  
242 - expose :id  
243 - expose :type  
244 - end  
245 -  
246 - class Environment < Entity  
247 - expose :name  
248 - expose :id  
249 - expose :description  
250 - expose :settings, if: lambda { |instance, options| options[:is_admin] }  
251 - end  
252 -  
253 - class Tag < Entity  
254 - root 'tags', 'tag'  
255 - expose :name  
256 - end  
257 -  
258 - class Activity < Entity  
259 - root 'activities', 'activity'  
260 - expose :id, :params, :verb, :created_at, :updated_at, :comments_count, :visible  
261 - expose :user, :using => Profile  
262 - expose :target do |activity, opts|  
263 - type_map = {Profile => ::Profile, ArticleBase => ::Article}.find {|h| activity.target.kind_of?(h.last)}  
264 - type_map.first.represent(activity.target) unless type_map.nil?  
265 - end  
266 - end  
267 - end  
268 - end  
269 -end  
lib/noosfero/api/entity.rb
@@ -1,25 +0,0 @@ @@ -1,25 +0,0 @@
1 -class Noosfero::API::Entity < Grape::Entity  
2 -  
3 - def initialize(object, options = {})  
4 - object = nil if object.is_a? Exception  
5 - super object, options  
6 - end  
7 -  
8 - def self.represent(objects, options = {})  
9 - if options[:has_exception]  
10 - data = super objects, options.merge(is_inner_data: true)  
11 - if objects.is_a? Exception  
12 - data.merge ok: false, error: {  
13 - type: objects.class.name,  
14 - message: objects.message  
15 - }  
16 - else  
17 - data = data.serializable_hash if data.is_a? Noosfero::API::Entity  
18 - data.merge ok: true, error: { type: 'Success', message: '' }  
19 - end  
20 - else  
21 - super objects, options  
22 - end  
23 - end  
24 -  
25 -end  
lib/noosfero/api/helpers.rb
@@ -1,425 +0,0 @@ @@ -1,425 +0,0 @@
1 -require 'grape'  
2 -require 'base64'  
3 -require 'tempfile'  
4 -require_relative '../../find_by_contents'  
5 -  
6 -module Noosfero;  
7 - module API  
8 - module APIHelpers  
9 - PRIVATE_TOKEN_PARAM = :private_token  
10 - DEFAULT_ALLOWED_PARAMETERS = [:parent_id, :from, :until, :content_type, :author_id, :identifier, :archived]  
11 -  
12 - include SanitizeParams  
13 - include Noosfero::Plugin::HotSpot  
14 - include ForgotPasswordHelper  
15 - include SearchTermHelper  
16 -  
17 - def set_locale  
18 - I18n.locale = (params[:lang] || request.env['HTTP_ACCEPT_LANGUAGE'] || 'en')  
19 - end  
20 -  
21 - def init_noosfero_plugins  
22 - plugins  
23 - end  
24 -  
25 - def current_user  
26 - private_token = (params[PRIVATE_TOKEN_PARAM] || headers['Private-Token']).to_s  
27 - @current_user ||= User.find_by private_token: private_token  
28 - @current_user ||= plugins.dispatch("api_custom_login", request).first  
29 - @current_user  
30 - end  
31 -  
32 - def current_person  
33 - current_user.person unless current_user.nil?  
34 - end  
35 -  
36 - def is_admin?(environment)  
37 - return false unless current_user  
38 - return current_person.is_admin?(environment)  
39 - end  
40 -  
41 - def logout  
42 - @current_user = nil  
43 - end  
44 -  
45 - def environment  
46 - @environment  
47 - end  
48 -  
49 - def present_partial(model, options)  
50 - if(params[:fields].present?)  
51 - begin  
52 - fields = JSON.parse(params[:fields])  
53 - if fields.present?  
54 - options.merge!(fields.symbolize_keys.slice(:only, :except))  
55 - end  
56 - rescue  
57 - fields = params[:fields]  
58 - fields = fields.split(',') if fields.kind_of?(String)  
59 - options[:only] = Array.wrap(fields)  
60 - end  
61 - end  
62 - present model, options  
63 - end  
64 -  
65 - include FindByContents  
66 -  
67 - ####################################################################  
68 - #### SEARCH  
69 - ####################################################################  
70 - def multiple_search?(searches=nil)  
71 - ['index', 'category_index'].include?(params[:action]) || (searches && searches.size > 1)  
72 - end  
73 - ####################################################################  
74 -  
75 - def logger  
76 - logger = Logger.new(File.join(Rails.root, 'log', "#{ENV['RAILS_ENV'] || 'production'}_api.log"))  
77 - logger.formatter = GrapeLogging::Formatters::Default.new  
78 - logger  
79 - end  
80 -  
81 - def limit  
82 - limit = params[:limit].to_i  
83 - limit = default_limit if limit <= 0  
84 - limit  
85 - end  
86 -  
87 - def period(from_date, until_date)  
88 - return nil if from_date.nil? && until_date.nil?  
89 -  
90 - begin_period = from_date.nil? ? Time.at(0).to_datetime : from_date  
91 - end_period = until_date.nil? ? DateTime.now : until_date  
92 -  
93 - begin_period..end_period  
94 - end  
95 -  
96 - def parse_content_type(content_type)  
97 - return nil if content_type.blank?  
98 - content_type.split(',').map do |content_type|  
99 - content_type.camelcase  
100 - end  
101 - end  
102 -  
103 - def find_article(articles, id)  
104 - article = articles.find(id)  
105 - article.display_to?(current_person) ? article : forbidden!  
106 - end  
107 -  
108 - def post_article(asset, params)  
109 - return forbidden! unless current_person.can_post_content?(asset)  
110 -  
111 - klass_type = params[:content_type] || params[:article].delete(:type) || TinyMceArticle.name  
112 - return forbidden! unless klass_type.constantize <= Article  
113 -  
114 - article = klass_type.constantize.new(params[:article])  
115 - article.last_changed_by = current_person  
116 - article.created_by= current_person  
117 - article.profile = asset  
118 -  
119 - if !article.save  
120 - render_api_errors!(article.errors.full_messages)  
121 - end  
122 - present_partial article, :with => Entities::Article  
123 - end  
124 -  
125 - def present_article(asset)  
126 - article = find_article(asset.articles, params[:id])  
127 - present_partial article, :with => Entities::Article, :params => params  
128 - end  
129 -  
130 - def present_articles_for_asset(asset, method = 'articles')  
131 - articles = find_articles(asset, method)  
132 - present_articles(articles)  
133 - end  
134 -  
135 - def present_articles(articles)  
136 - present_partial paginate(articles), :with => Entities::Article, :params => params  
137 - end  
138 -  
139 - def find_articles(asset, method = 'articles')  
140 - articles = select_filtered_collection_of(asset, method, params)  
141 - if current_person.present?  
142 - articles = articles.display_filter(current_person, nil)  
143 - else  
144 - articles = articles.published  
145 - end  
146 - articles  
147 - end  
148 -  
149 - def find_task(asset, id)  
150 - task = asset.tasks.find(id)  
151 - current_person.has_permission?(task.permission, asset) ? task : forbidden!  
152 - end  
153 -  
154 - def post_task(asset, params)  
155 - klass_type= params[:content_type].nil? ? 'Task' : params[:content_type]  
156 - return forbidden! unless klass_type.constantize <= Task  
157 -  
158 - task = klass_type.constantize.new(params[:task])  
159 - task.requestor_id = current_person.id  
160 - task.target_id = asset.id  
161 - task.target_type = 'Profile'  
162 -  
163 - if !task.save  
164 - render_api_errors!(task.errors.full_messages)  
165 - end  
166 - present_partial task, :with => Entities::Task  
167 - end  
168 -  
169 - def present_task(asset)  
170 - task = find_task(asset, params[:id])  
171 - present_partial task, :with => Entities::Task  
172 - end  
173 -  
174 - def present_tasks(asset)  
175 - tasks = select_filtered_collection_of(asset, 'tasks', params)  
176 - tasks = tasks.select {|t| current_person.has_permission?(t.permission, asset)}  
177 - return forbidden! if tasks.empty? && !current_person.has_permission?(:perform_task, asset)  
178 - present_partial tasks, :with => Entities::Task  
179 - end  
180 -  
181 - def make_conditions_with_parameter(params = {})  
182 - parsed_params = parser_params(params)  
183 - conditions = {}  
184 - from_date = DateTime.parse(parsed_params.delete(:from)) if parsed_params[:from]  
185 - until_date = DateTime.parse(parsed_params.delete(:until)) if parsed_params[:until]  
186 -  
187 - conditions[:type] = parse_content_type(parsed_params.delete(:content_type)) unless parsed_params[:content_type].nil?  
188 -  
189 - conditions[:created_at] = period(from_date, until_date) if from_date || until_date  
190 - conditions.merge!(parsed_params)  
191 -  
192 - conditions  
193 - end  
194 -  
195 - # changing make_order_with_parameters to avoid sql injection  
196 - def make_order_with_parameters(object, method, params)  
197 - order = "created_at DESC"  
198 - unless params[:order].blank?  
199 - if params[:order].include? '\'' or params[:order].include? '"'  
200 - order = "created_at DESC"  
201 - elsif ['RANDOM()', 'RANDOM'].include? params[:order].upcase  
202 - order = 'RANDOM()'  
203 - else  
204 - field_name, direction = params[:order].split(' ')  
205 - assoc = object.class.reflect_on_association(method.to_sym)  
206 - if !field_name.blank? and assoc  
207 - if assoc.klass.attribute_names.include? field_name  
208 - if direction.present? and ['ASC','DESC'].include? direction.upcase  
209 - order = "#{field_name} #{direction.upcase}"  
210 - end  
211 - end  
212 - end  
213 - end  
214 - end  
215 - return order  
216 - end  
217 -  
218 - def make_timestamp_with_parameters_and_method(params, method)  
219 - timestamp = nil  
220 - if params[:timestamp]  
221 - datetime = DateTime.parse(params[:timestamp])  
222 - table_name = method.to_s.singularize.camelize.constantize.table_name  
223 - timestamp = "#{table_name}.updated_at >= '#{datetime}'"  
224 - end  
225 -  
226 - timestamp  
227 - end  
228 -  
229 - def by_reference(scope, params)  
230 - reference_id = params[:reference_id].to_i == 0 ? nil : params[:reference_id].to_i  
231 - if reference_id.nil?  
232 - scope  
233 - else  
234 - created_at = scope.find(reference_id).created_at  
235 - scope.send("#{params.key?(:oldest) ? 'older_than' : 'younger_than'}", created_at)  
236 - end  
237 - end  
238 -  
239 - def by_categories(scope, params)  
240 - category_ids = params[:category_ids]  
241 - if category_ids.nil?  
242 - scope  
243 - else  
244 - scope.joins(:categories).where(:categories => {:id => category_ids})  
245 - end  
246 - end  
247 -  
248 - def select_filtered_collection_of(object, method, params)  
249 - conditions = make_conditions_with_parameter(params)  
250 - order = make_order_with_parameters(object,method,params)  
251 - timestamp = make_timestamp_with_parameters_and_method(params, method)  
252 -  
253 - objects = object.send(method)  
254 - objects = by_reference(objects, params)  
255 - objects = by_categories(objects, params)  
256 -  
257 - objects = objects.where(conditions).where(timestamp).reorder(order)  
258 -  
259 - params[:page] ||= 1  
260 - params[:per_page] ||= limit  
261 - paginate(objects)  
262 - end  
263 -  
264 - def authenticate!  
265 - unauthorized! unless current_user  
266 - end  
267 -  
268 - def profiles_for_person(profiles, person)  
269 - if person  
270 - profiles.listed_for_person(person)  
271 - else  
272 - profiles.visible  
273 - end  
274 - end  
275 -  
276 - # Checks the occurrences of uniqueness of attributes, each attribute must be present in the params hash  
277 - # or a Bad Request error is invoked.  
278 - #  
279 - # Parameters:  
280 - # keys (unique) - A hash consisting of keys that must be unique  
281 - def unique_attributes!(obj, keys)  
282 - keys.each do |key|  
283 - cant_be_saved_request!(key) if obj.find_by(key.to_s => params[key])  
284 - end  
285 - end  
286 -  
287 - def attributes_for_keys(keys)  
288 - attrs = {}  
289 - keys.each do |key|  
290 - attrs[key] = params[key] if params[key].present? or (params.has_key?(key) and params[key] == false)  
291 - end  
292 - attrs  
293 - end  
294 -  
295 - ##########################################  
296 - # error helpers #  
297 - ##########################################  
298 -  
299 - def not_found!  
300 - render_api_error!('404 Not found', 404)  
301 - end  
302 -  
303 - def forbidden!  
304 - render_api_error!('403 Forbidden', 403)  
305 - end  
306 -  
307 - def cant_be_saved_request!(attribute)  
308 - message = _("(Invalid request) %s can't be saved") % attribute  
309 - render_api_error!(message, 400)  
310 - end  
311 -  
312 - def bad_request!(attribute)  
313 - message = _("(Invalid request) %s not given") % attribute  
314 - render_api_error!(message, 400)  
315 - end  
316 -  
317 - def something_wrong!  
318 - message = _("Something wrong happened")  
319 - render_api_error!(message, 400)  
320 - end  
321 -  
322 - def unauthorized!  
323 - render_api_error!(_('Unauthorized'), 401)  
324 - end  
325 -  
326 - def not_allowed!  
327 - render_api_error!(_('Method Not Allowed'), 405)  
328 - end  
329 -  
330 - # javascript_console_message is supposed to be executed as console.log()  
331 - def render_api_error!(user_message, status, log_message = nil, javascript_console_message = nil)  
332 - message_hash = {'message' => user_message, :code => status}  
333 - message_hash[:javascript_console_message] = javascript_console_message if javascript_console_message.present?  
334 - log_msg = "#{status}, User message: #{user_message}"  
335 - log_msg = "#{log_message}, #{log_msg}" if log_message.present?  
336 - log_msg = "#{log_msg}, Javascript Console Message: #{javascript_console_message}" if javascript_console_message.present?  
337 - logger.error log_msg unless Rails.env.test?  
338 - error!(message_hash, status)  
339 - end  
340 -  
341 - def render_api_errors!(messages)  
342 - messages = messages.to_a if messages.class == ActiveModel::Errors  
343 - render_api_error!(messages.join(','), 400)  
344 - end  
345 -  
346 - protected  
347 -  
348 - def set_session_cookie  
349 - cookies['_noosfero_api_session'] = { value: @current_user.private_token, httponly: true } if @current_user.present?  
350 - end  
351 -  
352 - def setup_multitenancy  
353 - Noosfero::MultiTenancy.setup!(request.host)  
354 - end  
355 -  
356 - def detect_stuff_by_domain  
357 - @domain = Domain.by_name(request.host)  
358 - if @domain.nil?  
359 - @environment = Environment.default  
360 - if @environment.nil? && Rails.env.development?  
361 - # This should only happen in development ...  
362 - @environment = Environment.create!(:name => "Noosfero", :is_default => true)  
363 - end  
364 - else  
365 - @environment = @domain.environment  
366 - end  
367 - end  
368 -  
369 - def filter_disabled_plugins_endpoints  
370 - not_found! if Noosfero::API::API.endpoint_unavailable?(self, @environment)  
371 - end  
372 -  
373 - def asset_with_image params  
374 - if params.has_key? :image_builder  
375 - asset_api_params = params  
376 - asset_api_params[:image_builder] = base64_to_uploadedfile(asset_api_params[:image_builder])  
377 - return asset_api_params  
378 - end  
379 - params  
380 - end  
381 -  
382 - def base64_to_uploadedfile(base64_image)  
383 - tempfile = base64_to_tempfile base64_image  
384 - converted_image = base64_image  
385 - converted_image[:tempfile] = tempfile  
386 - return {uploaded_data: ActionDispatch::Http::UploadedFile.new(converted_image)}  
387 - end  
388 -  
389 - def base64_to_tempfile base64_image  
390 - base64_img_str = base64_image[:tempfile]  
391 - decoded_base64_str = Base64.decode64(base64_img_str)  
392 - tempfile = Tempfile.new(base64_image[:filename])  
393 - tempfile.write(decoded_base64_str.encode("ascii-8bit").force_encoding("utf-8"))  
394 - tempfile.rewind  
395 - tempfile  
396 - end  
397 - private  
398 -  
399 - def parser_params(params)  
400 - parsed_params = {}  
401 - params.map do |k,v|  
402 - parsed_params[k.to_sym] = v if DEFAULT_ALLOWED_PARAMETERS.include?(k.to_sym)  
403 - end  
404 - parsed_params  
405 - end  
406 -  
407 - def default_limit  
408 - 20  
409 - end  
410 -  
411 - def parse_content_type(content_type)  
412 - return nil if content_type.blank?  
413 - content_type.split(',').map do |content_type|  
414 - content_type.camelcase  
415 - end  
416 - end  
417 -  
418 - def period(from_date, until_date)  
419 - begin_period = from_date.nil? ? Time.at(0).to_datetime : from_date  
420 - end_period = until_date.nil? ? DateTime.now : until_date  
421 - begin_period..end_period  
422 - end  
423 - end  
424 - end  
425 -end  
lib/noosfero/api/session.rb
@@ -1,157 +0,0 @@ @@ -1,157 +0,0 @@
1 -require "uri"  
2 -  
3 -module Noosfero  
4 - module API  
5 - class Session < Grape::API  
6 -  
7 - # Login to get token  
8 - #  
9 - # Parameters:  
10 - # login (*required) - user login or email  
11 - # password (required) - user password  
12 - #  
13 - # Example Request:  
14 - # POST http://localhost:3000/api/v1/login?login=adminuser&password=admin  
15 - post "/login" do  
16 - begin  
17 - user ||= User.authenticate(params[:login], params[:password], environment)  
18 - rescue User::UserNotActivated => e  
19 - render_api_error!(e.message, 401)  
20 - end  
21 -  
22 - return unauthorized! unless user  
23 - @current_user = user  
24 - present user, :with => Entities::UserLogin, :current_person => current_person  
25 - end  
26 -  
27 - post "/login_from_cookie" do  
28 - return unauthorized! if cookies[:auth_token].blank?  
29 - user = User.where(remember_token: cookies[:auth_token]).first  
30 - return unauthorized! unless user && user.activated?  
31 - @current_user = user  
32 - present user, :with => Entities::UserLogin, :current_person => current_person  
33 - end  
34 -  
35 - # Create user.  
36 - #  
37 - # Parameters:  
38 - # email (required) - Email  
39 - # password (required) - Password  
40 - # login - login  
41 - # Example Request:  
42 - # POST /register?email=some@mail.com&password=pas&password_confirmation=pas&login=some  
43 - params do  
44 - requires :email, type: String, desc: _("Email")  
45 - requires :login, type: String, desc: _("Login")  
46 - requires :password, type: String, desc: _("Password")  
47 - end  
48 -  
49 - post "/register" do  
50 - attrs = attributes_for_keys [:email, :login, :password, :password_confirmation] + environment.signup_person_fields  
51 - name = params[:name].present? ? params[:name] : attrs[:email]  
52 - attrs[:password_confirmation] = attrs[:password] if !attrs.has_key?(:password_confirmation)  
53 - user = User.new(attrs.merge(:name => name))  
54 -  
55 - begin  
56 - user.signup!  
57 - user.generate_private_token! if user.activated?  
58 - present user, :with => Entities::UserLogin, :current_person => user.person  
59 - rescue ActiveRecord::RecordInvalid  
60 - message = user.errors.as_json.merge((user.person.present? ? user.person.errors : {}).as_json).to_json  
61 - render_api_error!(message, 400)  
62 - end  
63 - end  
64 -  
65 - params do  
66 - requires :activation_code, type: String, desc: _("Activation token")  
67 - end  
68 -  
69 - # Activate a user.  
70 - #  
71 - # Parameter:  
72 - # activation_code (required) - Activation token  
73 - # Example Request:  
74 - # PATCH /activate?activation_code=28259abd12cc6a64ef9399cf3286cb998b96aeaf  
75 - patch "/activate" do  
76 - user = User.find_by activation_code: params[:activation_code]  
77 - if user  
78 - unless user.environment.enabled?('admin_must_approve_new_users')  
79 - if user.activate  
80 - user.generate_private_token!  
81 - present user, :with => Entities::UserLogin, :current_person => current_person  
82 - end  
83 - else  
84 - if user.create_moderate_task  
85 - user.activation_code = nil  
86 - user.save!  
87 -  
88 - # Waiting for admin moderate user registration  
89 - status 202  
90 - body({  
91 - :message => 'Waiting for admin moderate user registration'  
92 - })  
93 - end  
94 - end  
95 - else  
96 - # Token not found in database  
97 - render_api_error!(_('Token is invalid'), 412)  
98 - end  
99 - end  
100 -  
101 - # Request a new password.  
102 - #  
103 - # Parameters:  
104 - # value (required) - Email or login  
105 - # Example Request:  
106 - # POST /forgot_password?value=some@mail.com  
107 - post "/forgot_password" do  
108 - requestors = fetch_requestors(params[:value])  
109 - not_found! if requestors.blank?  
110 - remote_ip = (request.respond_to?(:remote_ip) && request.remote_ip) || (env && env['REMOTE_ADDR'])  
111 - requestors.each do |requestor|  
112 - ChangePassword.create!(:requestor => requestor)  
113 - end  
114 - end  
115 -  
116 - # Resend activation code.  
117 - #  
118 - # Parameters:  
119 - # value (required) - Email or login  
120 - # Example Request:  
121 - # POST /resend_activation_code?value=some@mail.com  
122 - post "/resend_activation_code" do  
123 - requestors = fetch_requestors(params[:value])  
124 - not_found! if requestors.blank?  
125 - remote_ip = (request.respond_to?(:remote_ip) && request.remote_ip) || (env && env['REMOTE_ADDR'])  
126 - requestors.each do |requestor|  
127 - requestor.user.resend_activation_code  
128 - end  
129 - present requestors.map(&:user), :with => Entities::UserLogin  
130 - end  
131 -  
132 - params do  
133 - requires :code, type: String, desc: _("Forgot password code")  
134 - end  
135 - # Change password  
136 - #  
137 - # Parameters:  
138 - # code (required) - Change password code  
139 - # password (required)  
140 - # password_confirmation (required)  
141 - # Example Request:  
142 - # PATCH /new_password?code=xxxx&password=secret&password_confirmation=secret  
143 - patch "/new_password" do  
144 - change_password = ChangePassword.find_by code: params[:code]  
145 - not_found! if change_password.nil?  
146 -  
147 - if change_password.update_attributes(:password => params[:password], :password_confirmation => params[:password_confirmation])  
148 - change_password.finish  
149 - present change_password.requestor.user, :with => Entities::UserLogin, :current_person => current_person  
150 - else  
151 - something_wrong!  
152 - end  
153 - end  
154 -  
155 - end  
156 - end  
157 -end  
lib/noosfero/api/v1/activities.rb
@@ -1,22 +0,0 @@ @@ -1,22 +0,0 @@
1 -module Noosfero  
2 - module API  
3 - module V1  
4 - class Activities < Grape::API  
5 - before { authenticate! }  
6 -  
7 - resource :profiles do  
8 -  
9 - get ':id/activities' do  
10 - profile = Profile.find_by id: params[:id]  
11 -  
12 - not_found! if profile.blank? || profile.secret || !profile.visible  
13 - forbidden! if !profile.secret && profile.visible && !profile.display_private_info_to?(current_person)  
14 -  
15 - activities = profile.activities.map(&:activity)  
16 - present activities, :with => Entities::Activity, :current_person => current_person  
17 - end  
18 - end  
19 - end  
20 - end  
21 - end  
22 -end  
lib/noosfero/api/v1/articles.rb
@@ -1,305 +0,0 @@ @@ -1,305 +0,0 @@
1 -module Noosfero  
2 - module API  
3 - module V1  
4 - class Articles < Grape::API  
5 -  
6 - ARTICLE_TYPES = Article.descendants.map{|a| a.to_s}  
7 -  
8 - MAX_PER_PAGE = 50  
9 -  
10 - resource :articles do  
11 -  
12 - paginate max_per_page: MAX_PER_PAGE  
13 - # Collect articles  
14 - #  
15 - # Parameters:  
16 - # from - date where the search will begin. If nothing is passed the default date will be the date of the first article created  
17 - # oldest - Collect the oldest articles. If nothing is passed the newest articles are collected  
18 - # limit - amount of articles returned. The default value is 20  
19 - #  
20 - # Example Request:  
21 - # GET host/api/v1/articles?from=2013-04-04-14:41:43&until=2015-04-04-14:41:43&limit=10&private_token=e96fff37c2238fdab074d1dcea8e6317  
22 -  
23 - desc 'Return all articles of all kinds' do  
24 - detail 'Get all articles filtered by fields in query params'  
25 - params Noosfero::API::Entities::Article.documentation  
26 - success Noosfero::API::Entities::Article  
27 - failure [[403, 'Forbidden']]  
28 - named 'ArticlesList'  
29 - headers [  
30 - 'Per-Page' => {  
31 - description: 'Total number of records',  
32 - required: false  
33 - }  
34 - ]  
35 - end  
36 - get do  
37 - present_articles_for_asset(environment)  
38 - end  
39 -  
40 - desc "Return one article by id" do  
41 - detail 'Get only one article by id. If not found the "forbidden" http error is showed'  
42 - params Noosfero::API::Entities::Article.documentation  
43 - success Noosfero::API::Entities::Article  
44 - failure [[403, 'Forbidden']]  
45 - named 'ArticleById'  
46 - end  
47 - get ':id', requirements: {id: /[0-9]+/} do  
48 - present_article(environment)  
49 - end  
50 -  
51 - post ':id' do  
52 - article = environment.articles.find(params[:id])  
53 - return forbidden! unless article.allow_edit?(current_person)  
54 - article.update_attributes!(asset_with_image(params[:article]))  
55 - present_partial article, :with => Entities::Article  
56 - end  
57 -  
58 - desc 'Report a abuse and/or violent content in a article by id' do  
59 - detail 'Submit a abuse (in general, a content violation) report about a specific article'  
60 - params Noosfero::API::Entities::Article.documentation  
61 - failure [[400, 'Bad Request']]  
62 - named 'ArticleReportAbuse'  
63 - end  
64 - post ':id/report_abuse' do  
65 - article = find_article(environment.articles, params[:id])  
66 - profile = article.profile  
67 - begin  
68 - abuse_report = AbuseReport.new(:reason => params[:report_abuse])  
69 - if !params[:content_type].blank?  
70 - article = params[:content_type].constantize.find(params[:content_id])  
71 - abuse_report.content = article_reported_version(article)  
72 - end  
73 -  
74 - current_person.register_report(abuse_report, profile)  
75 -  
76 - if !params[:content_type].blank?  
77 - abuse_report = AbuseReport.find_by reporter_id: current_person.id, abuse_complaint_id: profile.opened_abuse_complaint.id  
78 - Delayed::Job.enqueue DownloadReportedImagesJob.new(abuse_report, article)  
79 - end  
80 -  
81 - {  
82 - :success => true,  
83 - :message => _('Your abuse report was registered. The administrators are reviewing your report.'),  
84 - }  
85 - rescue Exception => exception  
86 - #logger.error(exception.to_s)  
87 - render_api_error!(_('Your report couldn\'t be saved due to some problem. Please contact the administrator.'), 400)  
88 - end  
89 -  
90 - end  
91 -  
92 - desc "Returns the articles I voted" do  
93 - detail 'Get the Articles I make a vote'  
94 - failure [[403, 'Forbidden']]  
95 - named 'ArticleFollowers'  
96 - end  
97 - #FIXME refactor this method  
98 - get 'voted_by_me' do  
99 - present_articles(current_person.votes.where(:voteable_type => 'Article').collect(&:voteable))  
100 - end  
101 -  
102 - desc 'Perform a vote on a article by id' do  
103 - detail 'Vote on a specific article with values: 1 (if you like) or -1 (if not)'  
104 - params Noosfero::API::Entities::UserLogin.documentation  
105 - failure [[401,'Unauthorized']]  
106 - named 'ArticleVote'  
107 - end  
108 - post ':id/vote' do  
109 - authenticate!  
110 - value = (params[:value] || 1).to_i  
111 - # FIXME verify allowed values  
112 - render_api_error!('Vote value not allowed', 400) unless [-1, 1].include?(value)  
113 - article = find_article(environment.articles, params[:id])  
114 - begin  
115 - vote = Vote.new(:voteable => article, :voter => current_person, :vote => value)  
116 - {:vote => vote.save!}  
117 - rescue ActiveRecord::RecordInvalid => e  
118 - render_api_error!(e.message, 400)  
119 - end  
120 - end  
121 -  
122 - desc "Returns the total followers for the article" do  
123 - detail 'Get the followers of a specific article by id'  
124 - failure [[403, 'Forbidden']]  
125 - named 'ArticleFollowers'  
126 - end  
127 - get ':id/followers' do  
128 - article = find_article(environment.articles, params[:id])  
129 - total = article.person_followers.count  
130 - {:total_followers => total}  
131 - end  
132 -  
133 - desc "Return the articles followed by me"  
134 - get 'followed_by_me' do  
135 - present_articles_for_asset(current_person, 'following_articles')  
136 - end  
137 -  
138 - desc "Add a follower for the article" do  
139 - detail 'Add the current user identified by private token, like a follower of a article'  
140 - params Noosfero::API::Entities::UserLogin.documentation  
141 - failure [[401, 'Unauthorized']]  
142 - named 'ArticleFollow'  
143 - end  
144 - post ':id/follow' do  
145 - authenticate!  
146 - article = find_article(environment.articles, params[:id])  
147 - if article.article_followers.exists?(:person_id => current_person.id)  
148 - {:success => false, :already_follow => true}  
149 - else  
150 - article_follower = ArticleFollower.new  
151 - article_follower.article = article  
152 - article_follower.person = current_person  
153 - article_follower.save!  
154 - {:success => true}  
155 - end  
156 - end  
157 -  
158 - desc 'Return the children of a article identified by id' do  
159 - detail 'Get all children articles of a specific article'  
160 - params Noosfero::API::Entities::Article.documentation  
161 - failure [[403, 'Forbidden']]  
162 - named 'ArticleChildren'  
163 - end  
164 -  
165 - paginate per_page: MAX_PER_PAGE, max_per_page: MAX_PER_PAGE  
166 - get ':id/children' do  
167 - article = find_article(environment.articles, params[:id])  
168 -  
169 - #TODO make tests for this situation  
170 - votes_order = params.delete(:order) if params[:order]=='votes_score'  
171 - articles = select_filtered_collection_of(article, 'children', params)  
172 - articles = articles.display_filter(current_person, article.profile)  
173 -  
174 - #TODO make tests for this situation  
175 - if votes_order  
176 - articles = articles.joins('left join votes on articles.id=votes.voteable_id').group('articles.id').reorder('sum(coalesce(votes.vote, 0)) DESC')  
177 - end  
178 - Article.hit(articles)  
179 - present_articles(articles)  
180 - end  
181 -  
182 - desc 'Return one child of a article identified by id' do  
183 - detail 'Get a child of a specific article'  
184 - params Noosfero::API::Entities::Article.documentation  
185 - success Noosfero::API::Entities::Article  
186 - failure [[403, 'Forbidden']]  
187 - named 'ArticleChild'  
188 - end  
189 - get ':id/children/:child_id' do  
190 - article = find_article(environment.articles, params[:id])  
191 - child = find_article(article.children, params[:child_id])  
192 - child.hit  
193 - present_partial child, :with => Entities::Article  
194 - end  
195 -  
196 - desc 'Suggest a article to another profile' do  
197 - detail 'Suggest a article to another profile (person, community...)'  
198 - params Noosfero::API::Entities::Article.documentation  
199 - success Noosfero::API::Entities::Task  
200 - failure [[401,'Unauthorized']]  
201 - named 'ArticleSuggest'  
202 - end  
203 - post ':id/children/suggest' do  
204 - authenticate!  
205 - parent_article = environment.articles.find(params[:id])  
206 -  
207 - suggest_article = SuggestArticle.new  
208 - suggest_article.article = params[:article]  
209 - suggest_article.article[:parent_id] = parent_article.id  
210 - suggest_article.target = parent_article.profile  
211 - suggest_article.requestor = current_person  
212 -  
213 - unless suggest_article.save  
214 - render_api_errors!(suggest_article.article_object.errors.full_messages)  
215 - end  
216 - present_partial suggest_article, :with => Entities::Task  
217 - end  
218 -  
219 - # Example Request:  
220 - # POST api/v1/articles/:id/children?private_token=234298743290432&article[name]=title&article[body]=body  
221 - desc 'Add a child article to a parent identified by id' do  
222 - detail 'Create a new article and associate to a parent'  
223 - params Noosfero::API::Entities::Article.documentation  
224 - success Noosfero::API::Entities::Article  
225 - failure [[401,'Unauthorized']]  
226 - named 'ArticleAddChild'  
227 - end  
228 - post ':id/children' do  
229 - parent_article = environment.articles.find(params[:id])  
230 - params[:article][:parent_id] = parent_article.id  
231 - post_article(parent_article.profile, params)  
232 - end  
233 - end  
234 -  
235 - resource :profiles do  
236 - get ':id/home_page' do  
237 - profiles = environment.profiles  
238 - profiles = profiles.visible_for_person(current_person)  
239 - profile = profiles.find_by id: params[:id]  
240 - present_partial profile.home_page, :with => Entities::Article  
241 - end  
242 - end  
243 -  
244 - kinds = %w[profile community person enterprise]  
245 - kinds.each do |kind|  
246 - resource kind.pluralize.to_sym do  
247 - segment "/:#{kind}_id" do  
248 - resource :articles do  
249 -  
250 - desc "Return all articles associate with a profile of type #{kind}" do  
251 - detail 'Get a list of articles of a profile'  
252 - params Noosfero::API::Entities::Article.documentation  
253 - success Noosfero::API::Entities::Article  
254 - failure [[403, 'Forbidden']]  
255 - named 'ArticlesOfProfile'  
256 - end  
257 - get do  
258 - profile = environment.send(kind.pluralize).find(params["#{kind}_id"])  
259 -  
260 - if params[:path].present?  
261 - article = profile.articles.find_by path: params[:path]  
262 - if !article || !article.display_to?(current_person)  
263 - article = forbidden!  
264 - end  
265 -  
266 - present_partial article, :with => Entities::Article  
267 - else  
268 -  
269 - present_articles_for_asset(profile)  
270 - end  
271 - end  
272 -  
273 - desc "Return a article associate with a profile of type #{kind}" do  
274 - detail 'Get only one article of a profile'  
275 - params Noosfero::API::Entities::Article.documentation  
276 - success Noosfero::API::Entities::Article  
277 - failure [[403, 'Forbidden']]  
278 - named 'ArticleOfProfile'  
279 - end  
280 - get ':id' do  
281 - profile = environment.send(kind.pluralize).find(params["#{kind}_id"])  
282 - present_article(profile)  
283 - end  
284 -  
285 - # Example Request:  
286 - # POST api/v1/{people,communities,enterprises}/:asset_id/articles?private_token=234298743290432&article[name]=title&article[body]=body  
287 - desc "Add a new article associated with a profile of type #{kind}" do  
288 - detail 'Create a new article and associate with a profile'  
289 - params Noosfero::API::Entities::Article.documentation  
290 - success Noosfero::API::Entities::Article  
291 - failure [[403, 'Forbidden']]  
292 - named 'ArticleCreateToProfile'  
293 - end  
294 - post do  
295 - profile = environment.send(kind.pluralize).find(params["#{kind}_id"])  
296 - post_article(profile, params)  
297 - end  
298 - end  
299 - end  
300 - end  
301 - end  
302 - end  
303 - end  
304 - end  
305 -end  
lib/noosfero/api/v1/blocks.rb
@@ -1,17 +0,0 @@ @@ -1,17 +0,0 @@
1 -module Noosfero  
2 - module API  
3 - module V1  
4 -  
5 - class Blocks < Grape::API  
6 - resource :blocks do  
7 - get ':id' do  
8 - block = Block.find(params["id"])  
9 - return forbidden! unless block.visible_to_user?(current_person)  
10 - present block, :with => Entities::Block, display_api_content: true  
11 - end  
12 - end  
13 - end  
14 -  
15 - end  
16 - end  
17 -end  
lib/noosfero/api/v1/boxes.rb
@@ -1,46 +0,0 @@ @@ -1,46 +0,0 @@
1 -module Noosfero  
2 - module API  
3 - module V1  
4 -  
5 - class Boxes < Grape::API  
6 -  
7 - kinds = %w[profile community person enterprise]  
8 - kinds.each do |kind|  
9 -  
10 - resource kind.pluralize.to_sym do  
11 -  
12 - segment "/:#{kind}_id" do  
13 - resource :boxes do  
14 - get do  
15 - profile = environment.send(kind.pluralize).find(params["#{kind}_id"])  
16 - present profile.boxes, :with => Entities::Box  
17 - end  
18 - end  
19 - end  
20 - end  
21 -  
22 - end  
23 -  
24 - resource :environments do  
25 - [ '/default', '/context', ':environment_id' ].each do |route|  
26 - segment route do  
27 - resource :boxes do  
28 - get do  
29 - if (route.match(/default/))  
30 - env = Environment.default  
31 - elsif (route.match(/context/))  
32 - env = environment  
33 - else  
34 - env = Environment.find(params[:environment_id])  
35 - end  
36 - present env.boxes, :with => Entities::Box  
37 - end  
38 - end  
39 - end  
40 - end  
41 - end  
42 - end  
43 -  
44 - end  
45 - end  
46 -end  
lib/noosfero/api/v1/categories.rb
@@ -1,27 +0,0 @@ @@ -1,27 +0,0 @@
1 -module Noosfero  
2 - module API  
3 - module V1  
4 - class Categories < Grape::API  
5 -  
6 - resource :categories do  
7 -  
8 - get do  
9 - type = params[:category_type]  
10 - include_parent = params[:include_parent] == 'true'  
11 - include_children = params[:include_children] == 'true'  
12 -  
13 - categories = type.nil? ? environment.categories : environment.categories.where(:type => type)  
14 - present categories, :with => Entities::Category, parent: include_parent, children: include_children  
15 - end  
16 -  
17 - desc "Return the category by id"  
18 - get ':id' do  
19 - present environment.categories.find(params[:id]), :with => Entities::Category, parent: true, children: true  
20 - end  
21 -  
22 - end  
23 -  
24 - end  
25 - end  
26 - end  
27 -end  
lib/noosfero/api/v1/comments.rb
@@ -1,51 +0,0 @@ @@ -1,51 +0,0 @@
1 -module Noosfero  
2 - module API  
3 - module V1  
4 - class Comments < Grape::API  
5 - MAX_PER_PAGE = 20  
6 -  
7 -  
8 - resource :articles do  
9 - paginate max_per_page: MAX_PER_PAGE  
10 - # Collect comments from articles  
11 - #  
12 - # Parameters:  
13 - # reference_id - comment id used as reference to collect comment  
14 - # oldest - Collect the oldest comments from reference_id comment. If nothing is passed the newest comments are collected  
15 - # limit - amount of comments returned. The default value is 20  
16 - #  
17 - # Example Request:  
18 - # GET /articles/12/comments?oldest&limit=10&reference_id=23  
19 - get ":id/comments" do  
20 - article = find_article(environment.articles, params[:id])  
21 - comments = select_filtered_collection_of(article, :comments, params)  
22 - comments = comments.without_spam  
23 - comments = comments.without_reply if(params[:without_reply].present?)  
24 - comments = plugins.filter(:unavailable_comments, comments)  
25 - present paginate(comments), :with => Entities::Comment, :current_person => current_person  
26 - end  
27 -  
28 - get ":id/comments/:comment_id" do  
29 - article = find_article(environment.articles, params[:id])  
30 - present article.comments.find(params[:comment_id]), :with => Entities::Comment, :current_person => current_person  
31 - end  
32 -  
33 - # Example Request:  
34 - # POST api/v1/articles/12/comments?private_token=2298743290432&body=new comment&title=New  
35 - post ":id/comments" do  
36 - authenticate!  
37 - article = find_article(environment.articles, params[:id])  
38 - options = params.select { |key,v| !['id','private_token'].include?(key) }.merge(:author => current_person, :source => article)  
39 - begin  
40 - comment = Comment.create!(options)  
41 - rescue ActiveRecord::RecordInvalid => e  
42 - render_api_error!(e.message, 400)  
43 - end  
44 - present comment, :with => Entities::Comment, :current_person => current_person  
45 - end  
46 - end  
47 -  
48 - end  
49 - end  
50 - end  
51 -end  
lib/noosfero/api/v1/communities.rb
@@ -1,84 +0,0 @@ @@ -1,84 +0,0 @@
1 -module Noosfero  
2 - module API  
3 - module V1  
4 - class Communities < Grape::API  
5 -  
6 - resource :communities do  
7 -  
8 - # Collect comments from articles  
9 - #  
10 - # Parameters:  
11 - # from - date where the search will begin. If nothing is passed the default date will be the date of the first article created  
12 - # oldest - Collect the oldest comments from reference_id comment. If nothing is passed the newest comments are collected  
13 - # limit - amount of comments returned. The default value is 20  
14 - #  
15 - # Example Request:  
16 - # GET /communities?from=2013-04-04-14:41:43&until=2014-04-04-14:41:43&limit=10  
17 - # GET /communities?reference_id=10&limit=10&oldest  
18 - get do  
19 - communities = select_filtered_collection_of(environment, 'communities', params)  
20 - communities = profiles_for_person(communities, current_person)  
21 - communities = communities.by_location(params) # Must be the last. May return Exception obj  
22 - present communities, :with => Entities::Community, :current_person => current_person  
23 - end  
24 -  
25 -  
26 - # Example Request:  
27 - # POST api/v1/communties?private_token=234298743290432&community[name]=some_name  
28 - # for each custom field for community, add &community[field_name]=field_value to the request  
29 - post do  
30 - authenticate!  
31 - params[:community] ||= {}  
32 -  
33 - params[:community][:custom_values]={}  
34 - params[:community].keys.each do |key|  
35 - params[:community][:custom_values][key]=params[:community].delete(key) if Community.custom_fields(environment).any?{|cf| cf.name==key}  
36 - end  
37 -  
38 - begin  
39 - community = Community.create_after_moderation(current_person, params[:community].merge({:environment => environment}))  
40 - rescue  
41 - community = Community.new(params[:community])  
42 - end  
43 -  
44 - if !community.save  
45 - render_api_errors!(community.errors.full_messages)  
46 - end  
47 -  
48 - present community, :with => Entities::Community, :current_person => current_person  
49 - end  
50 -  
51 - get ':id' do  
52 - community = profiles_for_person(environment.communities, current_person).find_by_id(params[:id])  
53 - present community, :with => Entities::Community, :current_person => current_person  
54 - end  
55 -  
56 - end  
57 -  
58 - resource :people do  
59 -  
60 - segment '/:person_id' do  
61 -  
62 - resource :communities do  
63 -  
64 - get do  
65 - person = environment.people.find(params[:person_id])  
66 -  
67 - not_found! if person.blank?  
68 - forbidden! if !person.display_info_to?(current_person)  
69 -  
70 - communities = select_filtered_collection_of(person, 'communities', params)  
71 - communities = communities.visible  
72 - present communities, :with => Entities::Community, :current_person => current_person  
73 - end  
74 -  
75 - end  
76 -  
77 - end  
78 -  
79 - end  
80 -  
81 - end  
82 - end  
83 - end  
84 -end  
lib/noosfero/api/v1/contacts.rb
@@ -1,28 +0,0 @@ @@ -1,28 +0,0 @@
1 -module Noosfero  
2 - module API  
3 - module V1  
4 - class Contacts < Grape::API  
5 -  
6 - resource :communities do  
7 -  
8 - resource ':id/contact' do  
9 - #contact => {:name => 'some name', :email => 'test@mail.com', :subject => 'some title', :message => 'some message'}  
10 - desc "Send a contact message"  
11 - post do  
12 - profile = environment.communities.find(params[:id])  
13 - forbidden! unless profile.present?  
14 - contact = Contact.new params[:contact].merge(dest: profile)  
15 - if contact.deliver  
16 - {:success => true}  
17 - else  
18 - {:success => false}  
19 - end  
20 - end  
21 -  
22 - end  
23 - end  
24 -  
25 - end  
26 - end  
27 - end  
28 -end  
lib/noosfero/api/v1/enterprises.rb
@@ -1,57 +0,0 @@ @@ -1,57 +0,0 @@
1 -module Noosfero  
2 - module API  
3 - module V1  
4 - class Enterprises < Grape::API  
5 -  
6 - resource :enterprises do  
7 -  
8 - # Collect enterprises from environment  
9 - #  
10 - # Parameters:  
11 - # from - date where the search will begin. If nothing is passed the default date will be the date of the first article created  
12 - # oldest - Collect the oldest comments from reference_id comment. If nothing is passed the newest comments are collected  
13 - # limit - amount of comments returned. The default value is 20  
14 - # georef params - read `Profile.by_location` for more information.  
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 - enterprises = enterprises.visible  
22 - enterprises = enterprises.by_location(params) # Must be the last. May return Exception obj.  
23 - present enterprises, :with => Entities::Enterprise, :current_person => current_person  
24 - end  
25 -  
26 - desc "Return one enterprise by id"  
27 - get ':id' do  
28 - enterprise = environment.enterprises.visible.find_by(id: params[:id])  
29 - present enterprise, :with => Entities::Enterprise, :current_person => current_person  
30 - end  
31 -  
32 - end  
33 -  
34 - resource :people do  
35 -  
36 - segment '/:person_id' do  
37 -  
38 - resource :enterprises do  
39 -  
40 - get do  
41 - person = environment.people.find(params[:person_id])  
42 - enterprises = select_filtered_collection_of(person, 'enterprises', params)  
43 - enterprises = enterprises.visible.by_location(params)  
44 - present enterprises, :with => Entities::Enterprise, :current_person => current_person  
45 - end  
46 -  
47 - end  
48 -  
49 - end  
50 -  
51 - end  
52 -  
53 -  
54 - end  
55 - end  
56 - end  
57 -end  
lib/noosfero/api/v1/environments.rb
@@ -1,30 +0,0 @@ @@ -1,30 +0,0 @@
1 -module Noosfero  
2 - module API  
3 - module V1  
4 - class Environments < Grape::API  
5 -  
6 - resource :environment do  
7 -  
8 - desc "Return the person information"  
9 - get '/signup_person_fields' do  
10 - present environment.signup_person_fields  
11 - end  
12 -  
13 - get ':id' do  
14 - local_environment = nil  
15 - if (params[:id] == "default")  
16 - local_environment = Environment.default  
17 - elsif (params[:id] == "context")  
18 - local_environment = environment  
19 - else  
20 - local_environment = Environment.find(params[:id])  
21 - end  
22 - present_partial local_environment, :with => Entities::Environment, :is_admin => is_admin?(local_environment)  
23 - end  
24 -  
25 - end  
26 -  
27 - end  
28 - end  
29 - end  
30 -end  
lib/noosfero/api/v1/people.rb
@@ -1,129 +0,0 @@ @@ -1,129 +0,0 @@
1 -module Noosfero  
2 - module API  
3 - module V1  
4 - class People < Grape::API  
5 -  
6 - MAX_PER_PAGE = 50  
7 -  
8 - desc 'API Root'  
9 -  
10 - resource :people do  
11 - paginate max_per_page: MAX_PER_PAGE  
12 -  
13 - # -- A note about privacy --  
14 - # We wold find people by location, but we must test if the related  
15 - # fields are public. We can't do it now, with SQL, while the location  
16 - # data and the fields_privacy are a serialized settings.  
17 - # We must build a new table for profile data, where we can set meta-data  
18 - # like:  
19 - # | id | profile_id | key | value | privacy_level | source |  
20 - # | 1 | 99 | city | Salvador | friends | user |  
21 - # | 2 | 99 | lng | -38.521 | me only | automatic |  
22 -  
23 - # Collect people from environment  
24 - #  
25 - # Parameters:  
26 - # from - date where the search will begin. If nothing is passed the default date will be the date of the first article created  
27 - # oldest - Collect the oldest comments from reference_id comment. If nothing is passed the newest comments are collected  
28 - # limit - amount of comments returned. The default value is 20  
29 - #  
30 - # Example Request:  
31 - # GET /people?from=2013-04-04-14:41:43&until=2014-04-04-14:41:43&limit=10  
32 - # GET /people?reference_id=10&limit=10&oldest  
33 -  
34 - desc "Find environment's people"  
35 - get do  
36 - people = select_filtered_collection_of(environment, 'people', params)  
37 - people = people.visible  
38 - present_partial people, :with => Entities::Person, :current_person => current_person  
39 - end  
40 -  
41 - desc "Return the logged user information"  
42 - get "/me" do  
43 - authenticate!  
44 - present_partial current_person, :with => Entities::Person, :current_person => current_person  
45 - end  
46 -  
47 - desc "Return the person information"  
48 - get ':id' do  
49 - person = environment.people.visible.find_by(id: params[:id])  
50 - return not_found! if person.blank?  
51 - present person, :with => Entities::Person, :current_person => current_person  
52 - end  
53 -  
54 - desc "Update person information"  
55 - post ':id' do  
56 - authenticate!  
57 - return forbidden! if current_person.id.to_s != params[:id]  
58 - current_person.update_attributes!(asset_with_image(params[:person]))  
59 - present current_person, :with => Entities::Person, :current_person => current_person  
60 - end  
61 -  
62 - # POST api/v1/people?person[login]=some_login&person[password]=some_password&person[name]=Jack  
63 - # for each custom field for person, add &person[field_name]=field_value to the request  
64 - desc "Create person"  
65 - post do  
66 - authenticate!  
67 - user_data = {}  
68 - user_data[:login] = params[:person].delete(:login) || params[:person][:identifier]  
69 - user_data[:email] = params[:person].delete(:email)  
70 - user_data[:password] = params[:person].delete(:password)  
71 - user_data[:password_confirmation] = params[:person].delete(:password_confirmation)  
72 -  
73 - params[:person][:custom_values]={}  
74 - params[:person].keys.each do |key|  
75 - params[:person][:custom_values][key]=params[:person].delete(key) if Person.custom_fields(environment).any?{|cf| cf.name==key}  
76 - end  
77 -  
78 - user = User.build(user_data, asset_with_image(params[:person]), environment)  
79 -  
80 - begin  
81 - user.signup!  
82 - rescue ActiveRecord::RecordInvalid  
83 - render_api_errors!(user.errors.full_messages)  
84 - end  
85 -  
86 - present user.person, :with => Entities::Person, :current_person => user.person  
87 - end  
88 -  
89 - desc "Return the person friends"  
90 - get ':id/friends' do  
91 - person = environment.people.visible.find_by(id: params[:id])  
92 - return not_found! if person.blank?  
93 - friends = person.friends.visible  
94 - present friends, :with => Entities::Person, :current_person => current_person  
95 - end  
96 -  
97 - desc "Return the person permissions on other profiles"  
98 - get ":id/permissions" do  
99 - authenticate!  
100 - person = environment.people.find(params[:id])  
101 - return not_found! if person.blank?  
102 - return forbidden! unless current_person == person || environment.admins.include?(current_person)  
103 -  
104 - output = {}  
105 - person.role_assignments.map do |role_assigment|  
106 - if role_assigment.resource.respond_to?(:identifier)  
107 - output[role_assigment.resource.identifier] = role_assigment.role.permissions  
108 - end  
109 - end  
110 - present output  
111 - end  
112 - end  
113 -  
114 - resource :profiles do  
115 - segment '/:profile_id' do  
116 - resource :members do  
117 - paginate max_per_page: MAX_PER_PAGE  
118 - get do  
119 - profile = environment.profiles.find_by id: params[:profile_id]  
120 - members = select_filtered_collection_of(profile, 'members', params)  
121 - present members, :with => Entities::Person, :current_person => current_person  
122 - end  
123 - end  
124 - end  
125 - end  
126 - end  
127 - end  
128 - end  
129 -end  
lib/noosfero/api/v1/profiles.rb
@@ -1,44 +0,0 @@ @@ -1,44 +0,0 @@
1 -module Noosfero  
2 - module API  
3 - module V1  
4 - class Profiles < Grape::API  
5 -  
6 - resource :profiles do  
7 -  
8 - get do  
9 - profiles = select_filtered_collection_of(environment, 'profiles', params)  
10 - profiles = profiles.visible  
11 - profiles = profiles.by_location(params) # Must be the last. May return Exception obj.  
12 - present profiles, :with => Entities::Profile, :current_person => current_person  
13 - end  
14 -  
15 - get ':id' do  
16 - profiles = environment.profiles  
17 - profiles = profiles.visible  
18 - profile = profiles.find_by id: params[:id]  
19 -  
20 - if profile  
21 - present profile, :with => Entities::Profile, :current_person => current_person  
22 - else  
23 - not_found!  
24 - end  
25 - end  
26 -  
27 - delete ':id' do  
28 - authenticate!  
29 - profiles = environment.profiles  
30 - profile = profiles.find_by id: params[:id]  
31 -  
32 - not_found! if profile.blank?  
33 -  
34 - if current_person.has_permission?(:destroy_profile, profile)  
35 - profile.destroy  
36 - else  
37 - forbidden!  
38 - end  
39 - end  
40 - end  
41 - end  
42 - end  
43 - end  
44 -end  
lib/noosfero/api/v1/search.rb
@@ -1,39 +0,0 @@ @@ -1,39 +0,0 @@
1 -module Noosfero  
2 - module API  
3 - module V1  
4 - class Search < Grape::API  
5 -  
6 - resource :search do  
7 - resource :article do  
8 - paginate max_per_page: 200  
9 - get do  
10 - # Security checks  
11 - sanitize_params_hash(params)  
12 - # APIHelpers  
13 - asset = :articles  
14 - context = environment  
15 -  
16 - profile = environment.profiles.find(params[:profile_id]) if params[:profile_id]  
17 - scope = profile.nil? ? environment.articles.is_public : profile.articles.is_public  
18 - scope = scope.where(:type => params[:type]) if params[:type] && !(params[:type] == 'Article')  
19 - scope = scope.where(make_conditions_with_parameter(params))  
20 - scope = scope.joins(:categories).where(:categories => {:id => params[:category_ids]}) if params[:category_ids].present?  
21 - scope = scope.where('articles.children_count > 0') if params[:has_children].present?  
22 - query = params[:query] || ""  
23 - order = "more_recent"  
24 -  
25 - options = {:filter => order, :template_id => params[:template_id]}  
26 -  
27 - search_result = find_by_contents(asset, context, scope, query, {:page => 1}, options)  
28 -  
29 - articles = search_result[:results]  
30 -  
31 - present_articles(articles)  
32 - end  
33 - end  
34 - end  
35 -  
36 - end  
37 - end  
38 - end  
39 -end  
lib/noosfero/api/v1/tags.rb
@@ -1,28 +0,0 @@ @@ -1,28 +0,0 @@
1 -module Noosfero  
2 - module API  
3 - module V1  
4 - class Tags < Grape::API  
5 - before { authenticate! }  
6 -  
7 - resource :articles do  
8 -  
9 - resource ':id/tags' do  
10 -  
11 - get do  
12 - article = find_article(environment.articles, params[:id])  
13 - present article.tag_list  
14 - end  
15 -  
16 - desc "Add a tag to an article"  
17 - post do  
18 - article = find_article(environment.articles, params[:id])  
19 - article.tag_list=params[:tags]  
20 - article.save  
21 - present article.tag_list  
22 - end  
23 - end  
24 - end  
25 - end  
26 - end  
27 - end  
28 -end  
lib/noosfero/api/v1/tasks.rb
@@ -1,59 +0,0 @@ @@ -1,59 +0,0 @@
1 -module Noosfero  
2 - module API  
3 - module V1  
4 - class Tasks < Grape::API  
5 -# before { authenticate! }  
6 -  
7 -# ARTICLE_TYPES = Article.descendants.map{|a| a.to_s}  
8 -  
9 - resource :tasks do  
10 -  
11 - # Collect tasks  
12 - #  
13 - # Parameters:  
14 - # from - date where the search will begin. If nothing is passed the default date will be the date of the first article created  
15 - # oldest - Collect the oldest articles. If nothing is passed the newest articles are collected  
16 - # limit - amount of articles returned. The default value is 20  
17 - #  
18 - # Example Request:  
19 - # GET host/api/v1/tasks?from=2013-04-04-14:41:43&until=2015-04-04-14:41:43&limit=10&private_token=e96fff37c2238fdab074d1dcea8e6317  
20 - get do  
21 - tasks = select_filtered_collection_of(environment, 'tasks', params)  
22 - tasks = tasks.select {|t| current_person.has_permission?(t.permission, environment)}  
23 - present_partial tasks, :with => Entities::Task  
24 - end  
25 -  
26 - desc "Return the task id"  
27 - get ':id' do  
28 - task = find_task(environment, params[:id])  
29 - present_partial task, :with => Entities::Task  
30 - end  
31 - end  
32 -  
33 - kinds = %w[community person enterprise]  
34 - kinds.each do |kind|  
35 - resource kind.pluralize.to_sym do  
36 - segment "/:#{kind}_id" do  
37 - resource :tasks do  
38 - get do  
39 - profile = environment.send(kind.pluralize).find(params["#{kind}_id"])  
40 - present_tasks(profile)  
41 - end  
42 -  
43 - get ':id' do  
44 - profile = environment.send(kind.pluralize).find(params["#{kind}_id"])  
45 - present_task(profile)  
46 - end  
47 -  
48 - post do  
49 - profile = environment.send(kind.pluralize).find(params["#{kind}_id"])  
50 - post_task(profile, params)  
51 - end  
52 - end  
53 - end  
54 - end  
55 - end  
56 - end  
57 - end  
58 - end  
59 -end  
lib/noosfero/api/v1/users.rb
@@ -1,45 +0,0 @@ @@ -1,45 +0,0 @@
1 -module Noosfero  
2 - module API  
3 - module V1  
4 - class Users < Grape::API  
5 -  
6 - resource :users do  
7 -  
8 - get do  
9 - users = select_filtered_collection_of(environment, 'users', params)  
10 - users = users.select{|u| u.person.display_info_to? current_person}  
11 - present users, :with => Entities::User, :current_person => current_person  
12 - end  
13 -  
14 - get "/me" do  
15 - authenticate!  
16 - present current_user, :with => Entities::User, :current_person => current_person  
17 - end  
18 -  
19 - get ":id" do  
20 - user = environment.users.find_by id: params[:id]  
21 - if user  
22 - present user, :with => Entities::User, :current_person => current_person  
23 - else  
24 - not_found!  
25 - end  
26 - end  
27 -  
28 - get ":id/permissions" do  
29 - authenticate!  
30 - user = environment.users.find(params[:id])  
31 - output = {}  
32 - user.person.role_assignments.map do |role_assigment|  
33 - if role_assigment.resource.respond_to?(:identifier) && role_assigment.resource.identifier == params[:profile]  
34 - output[:permissions] = role_assigment.role.permissions  
35 - end  
36 - end  
37 - present output  
38 - end  
39 -  
40 - end  
41 -  
42 - end  
43 - end  
44 - end  
45 -end  
lib/tasks/grape_routes.rb
1 desc "Print out grape routes" 1 desc "Print out grape routes"
2 task :grape_routes => :environment do 2 task :grape_routes => :environment do
3 #require 'api/api.rb' 3 #require 'api/api.rb'
4 - Noosfero::API::API.routes.each do |route| 4 + Api::App.routes.each do |route|
5 puts route 5 puts route
6 method = route.route_method 6 method = route.route_method
7 path = route.route_path 7 path = route.route_path
plugins/comment_paragraph/lib/comment_paragraph_plugin/api.rb
  1 +# Can't be called Api as will result in:
  2 +# warning: toplevel constant Api referenced by CommentParagraphPlugin::Api
  3 +# To fix this CommentParagraphPlugin should be a module
1 class CommentParagraphPlugin::API < Grape::API 4 class CommentParagraphPlugin::API < Grape::API
2 MAX_PER_PAGE = 20 5 MAX_PER_PAGE = 20
3 6
@@ -9,7 +12,7 @@ class CommentParagraphPlugin::API &lt; Grape::API @@ -9,7 +12,7 @@ class CommentParagraphPlugin::API &lt; Grape::API
9 comments = comments.without_spam 12 comments = comments.without_spam
10 comments = comments.in_paragraph(params[:paragraph_uuid]) 13 comments = comments.in_paragraph(params[:paragraph_uuid])
11 comments = comments.without_reply if(params[:without_reply].present?) 14 comments = comments.without_reply if(params[:without_reply].present?)
12 - present paginate(comments), :with => Noosfero::API::Entities::Comment, :current_person => current_person 15 + present paginate(comments), :with => Api::Entities::Comment, :current_person => current_person
13 end 16 end
14 17
15 {activate: true, deactivate: false}.each do |method, value| 18 {activate: true, deactivate: false}.each do |method, value|
@@ -19,7 +22,7 @@ class CommentParagraphPlugin::API &lt; Grape::API @@ -19,7 +22,7 @@ class CommentParagraphPlugin::API &lt; Grape::API
19 return forbidden! unless article.comment_paragraph_plugin_enabled? && article.allow_edit?(current_person) 22 return forbidden! unless article.comment_paragraph_plugin_enabled? && article.allow_edit?(current_person)
20 article.comment_paragraph_plugin_activate = value 23 article.comment_paragraph_plugin_activate = value
21 article.save! 24 article.save!
22 - present_partial article, :with => Noosfero::API::Entities::Article 25 + present_partial article, :with => Api::Entities::Article
23 end 26 end
24 end 27 end
25 28
plugins/comment_paragraph/lib/ext/entities.rb
1 -require File.join(Rails.root,'lib','noosfero','api','entities')  
2 -module Noosfero  
3 - module API  
4 - module Entities  
5 - class Comment < CommentBase  
6 - expose :paragraph_uuid  
7 - expose :comment_paragraph_selected_area  
8 - expose :comment_paragraph_selected_content  
9 - end 1 +require_dependency 'api/entities'
  2 +
  3 +module Api
  4 + module Entities
  5 + class Comment
  6 + expose :paragraph_uuid
  7 + expose :comment_paragraph_selected_area
  8 + expose :comment_paragraph_selected_content
10 end 9 end
11 end 10 end
12 end 11 end
plugins/push_notification/lib/push_notification_plugin.rb
@@ -39,7 +39,7 @@ class PushNotificationPlugin &lt; Noosfero::Plugin @@ -39,7 +39,7 @@ class PushNotificationPlugin &lt; Noosfero::Plugin
39 end 39 end
40 40
41 def self.api_mount_points 41 def self.api_mount_points
42 - [PushNotificationPlugin::API] 42 + [PushNotificationPlugin::Api]
43 end 43 end
44 44
45 def self.plugin_description 45 def self.plugin_description
plugins/push_notification/lib/push_notification_plugin/api.rb
1 -require File.dirname(__FILE__) + '/../../../../../lib/noosfero/api/helpers' 1 +require_dependency 'api/helpers'
2 require_relative 'api_entities' 2 require_relative 'api_entities'
3 3
4 -class PushNotificationPlugin::API < Grape::API 4 +class PushNotificationPlugin::Api < Grape::API
5 5
6 - include Noosfero::API::APIHelpers 6 + include Api::Helpers
7 7
8 resource :push_notification_plugin do 8 resource :push_notification_plugin do
9 9
plugins/push_notification/lib/push_notification_plugin/api_entities.rb
1 module PushNotificationPlugin::Entities 1 module PushNotificationPlugin::Entities
2 - class DeviceUser < Noosfero::API::Entities::User 2 + class DeviceUser < Api::Entities::User
3 expose :device_token_list, :as => :device_tokens 3 expose :device_token_list, :as => :device_tokens
4 expose :notification_settings do |user, options| 4 expose :notification_settings do |user, options|
5 user.notification_settings.hash_flags 5 user.notification_settings.hash_flags
plugins/recent_content/lib/recent_content_block.rb
@@ -50,7 +50,7 @@ class RecentContentBlock &lt; Block @@ -50,7 +50,7 @@ class RecentContentBlock &lt; Block
50 50
51 def api_content 51 def api_content
52 children = self.articles_of_folder(self.root, self.total_items) 52 children = self.articles_of_folder(self.root, self.total_items)
53 - Noosfero::API::Entities::ArticleBase.represent(children).as_json 53 + Api::Entities::ArticleBase.represent(children).as_json
54 end 54 end
55 55
56 def display_api_content_by_default? 56 def display_api_content_by_default?
plugins/statistics/lib/ext/entities.rb
1 -require File.join(Rails.root,'lib','noosfero','api','entities')  
2 -module Noosfero  
3 - module API  
4 - module Entities  
5 - class Block < Entity  
6 - available_counters = (StatisticsBlock::USER_COUNTERS + StatisticsBlock::COMMUNITY_COUNTERS + StatisticsBlock::ENTERPRISE_COUNTERS).uniq  
7 - expose :statistics, :if => lambda { |block, options| block.is_a? StatisticsBlock } do |block, options|  
8 - statistics = []  
9 - available_counters.each do |counter_attr|  
10 - counter_method = counter_attr.to_s.gsub('_counter','').pluralize.to_sym  
11 - counter = {  
12 - name: counter_method,  
13 - display: block.is_counter_available?(counter_attr) && block.is_visible?(counter_attr),  
14 - quantity: (block.respond_to?(counter_method) && block.is_visible?(counter_attr)) ? block.send(counter_method) : nil  
15 - }  
16 - statistics << counter  
17 - end  
18 - statistics  
19 - end 1 +require_dependency 'api/entities'
20 2
  3 +module Api
  4 + module Entities
  5 + class Block
  6 + available_counters = (StatisticsBlock::USER_COUNTERS + StatisticsBlock::COMMUNITY_COUNTERS + StatisticsBlock::ENTERPRISE_COUNTERS).uniq
  7 + expose :statistics, :if => lambda { |block, options| block.is_a? StatisticsBlock } do |block, options|
  8 + statistics = []
  9 + available_counters.each do |counter_attr|
  10 + counter_method = counter_attr.to_s.gsub('_counter','').pluralize.to_sym
  11 + counter = {
  12 + name: counter_method,
  13 + display: block.is_counter_available?(counter_attr) && block.is_visible?(counter_attr),
  14 + quantity: (block.respond_to?(counter_method) && block.is_visible?(counter_attr)) ? block.send(counter_method) : nil
  15 + }
  16 + statistics << counter
  17 + end
  18 + statistics
21 end 19 end
  20 +
22 end 21 end
23 end 22 end
24 end 23 end
25 -  
test/api/api_test.rb
1 require_relative 'test_helper' 1 require_relative 'test_helper'
2 2
3 -class MyPlugin < Noosfero::Plugin;end  
4 -class MyPlugin::API;end 3 +class MyPlugin < Noosfero::Plugin; end
  4 +class MyPlugin::Api; end
5 5
6 -class APITest < ActiveSupport::TestCase 6 +class ApiTest < ActiveSupport::TestCase
7 7
8 should 'endpoint should not be available if its plugin is unavailable' do 8 should 'endpoint should not be available if its plugin is unavailable' do
9 endpoint = mock() 9 endpoint = mock()
10 environment = Environment.default 10 environment = Environment.default
11 environment.stubs(:plugin_enabled?).returns(false) 11 environment.stubs(:plugin_enabled?).returns(false)
12 - endpoint.stubs(:options).returns({:for => MyPlugin::API}) 12 + endpoint.stubs(:options).returns({:for => MyPlugin::Api})
13 13
14 - assert Noosfero::API::API.endpoint_unavailable?(endpoint, environment) 14 + assert Api::App.endpoint_unavailable?(endpoint, environment)
15 end 15 end
16 16
17 should 'endpoint should be available if its plugin is available' do 17 should 'endpoint should be available if its plugin is available' do
18 - class MyPlugin < Noosfero::Plugin;end  
19 - class MyPlugin::API;end  
20 -  
21 endpoint = mock() 18 endpoint = mock()
22 environment = Environment.default 19 environment = Environment.default
23 environment.stubs(:plugin_enabled?).returns(true) 20 environment.stubs(:plugin_enabled?).returns(true)
24 - endpoint.stubs(:options).returns({:for => MyPlugin::API}) 21 + endpoint.stubs(:options).returns({:for => MyPlugin::Api})
25 22
26 - assert !Noosfero::API::API.endpoint_unavailable?(endpoint, environment) 23 + assert !Api::App.endpoint_unavailable?(endpoint, environment)
27 end 24 end
28 25
29 end 26 end
test/api/helpers_test.rb
1 require_relative 'test_helper' 1 require_relative 'test_helper'
2 -require "base64"  
3 -require 'noosfero/api/helpers' 2 +require 'base64'
4 3
5 -class APIHelpersTest < ActiveSupport::TestCase 4 +class Api::HelpersTest < ActiveSupport::TestCase
6 5
7 - include Noosfero::API::APIHelpers 6 + include Api::Helpers
8 7
9 def setup 8 def setup
10 create_and_activate_user 9 create_and_activate_user
@@ -206,7 +205,7 @@ class APIHelpersTest &lt; ActiveSupport::TestCase @@ -206,7 +205,7 @@ class APIHelpersTest &lt; ActiveSupport::TestCase
206 end 205 end
207 206
208 should 'render not_found if endpoint is unavailable' do 207 should 'render not_found if endpoint is unavailable' do
209 - Noosfero::API::API.stubs(:endpoint_unavailable?).returns(true) 208 + Api::App.stubs(:endpoint_unavailable?).returns(true)
210 self.expects(:not_found!) 209 self.expects(:not_found!)
211 210
212 filter_disabled_plugins_endpoints 211 filter_disabled_plugins_endpoints
test/api/test_helper.rb
@@ -8,7 +8,7 @@ class ActiveSupport::TestCase @@ -8,7 +8,7 @@ class ActiveSupport::TestCase
8 USER_LOGIN = "testapi" 8 USER_LOGIN = "testapi"
9 9
10 def app 10 def app
11 - Noosfero::API::API 11 + Api::App
12 end 12 end
13 13
14 def create_and_activate_user 14 def create_and_activate_user