Noosfero/noosfero

View on GitHub
app/api/v1/articles.rb

Summary

Maintainability
A
3 hrs
Test Coverage
module Api
  module V1
    class Articles < Grape::API::Instance
      ARTICLE_TYPES = Article.descendants.map { |a| a.to_s }

      MAX_PER_PAGE = 50

      resource :articles do
        paginate max_per_page: MAX_PER_PAGE
        # Collect articles
        #
        # Parameters:
        #   from             - date where the search will begin. If nothing is passed the default date will be the date of the first article created
        #   oldest           - Collect the oldest articles. If nothing is passed the newest articles are collected
        #   limit            - amount of articles returned. The default value is 20
        #
        # Example Request:
        #  GET host/api/v1/articles?from=2013-04-04-14:41:43&until=2015-04-04-14:41:43&limit=10&private_token=e96fff37c2238fdab074d1dcea8e6317

        desc "Return all articles of all kinds" do
          detail "Get all articles filtered by fields in query params"
          params Entities::Article.documentation
          success Entities::Article
          failure [[Api::Status::Http::FORBIDDEN, "Forbidden"]]
          named "ArticlesList"
          headers [
            "Per-Page" => {
              description: "Total number of records",
              required: false
            }
          ]
        end
        get do
          present_articles_for_asset(environment)
        end

        desc "Return one article by id" do
          detail 'Get only one article by id. If not found the "forbidden" http error is showed'
          params Entities::Article.documentation
          success Entities::Article
          failure [[Api::Status::Http::FORBIDDEN, "Forbidden"]]
          named "ArticleById"
        end
        get ":id", requirements: { id: /[0-9]+/ } do
          present_article(environment)
        end

        post ":id" do
          article = environment.articles.find(params[:id])
          return forbidden! unless article.allow_edit?(current_person)

          begin
            article.update_attributes!(asset_with_image(params[:article]))
            present_partial article, with: Entities::Article
          rescue ActiveRecord::RecordInvalid
            render_model_errors!(article.errors)
          end
        end

        delete ":id" do
          article = environment.articles.find(params[:id])
          return forbidden! unless article.allow_delete?(current_person)

          begin
            article.destroy
            output = { success: true }
            output[:message] = _("The article %s was removed.") % article.title
            output[:code] = Api::Status::Http::NO_CONTENT
            present output, with: Entities::Response
          rescue Exception => exception
            render_api_error!(_("The article couldn't be removed due to some problem. Please contact the administrator."), Api::Status::Http::BAD_REQUEST)
          end
        end

        desc "Report a abuse and/or violent content in a article by id" do
          detail "Submit a abuse (in general, a content violation) report about a specific article"
          params Entities::Article.documentation
          failure [[Api::Status::Http::BAD_REQUEST, "Bad Request"]]
          named "ArticleReportAbuse"
        end
        post ":id/report_abuse" do
          article = find_article(environment.articles, id: params[:id])
          profile = article.profile
          begin
            abuse_report = AbuseReport.new(reason: params[:report_abuse])
            if !params[:content_type].blank?
              article = params[:content_type].constantize.find(params[:content_id])
              abuse_report.content = article_reported_version(article)
            end

            current_person.register_report(abuse_report, profile)

            if !params[:content_type].blank?
              abuse_report = AbuseReport.find_by reporter_id: current_person.id, abuse_complaint_id: profile.opened_abuse_complaint.id
              Delayed::Job.enqueue DownloadReportedImagesJob.new(abuse_report, article)
            end

            output = { success: true }
            output[:message] = _("Your abuse report was registered. The administrators are reviewing your report."),
                               output[:code] = Api::Status::WAITING_FOR_REVIEW

            present output, with: Entities::Response
          rescue Exception => exception
            # logger.error(exception.to_s)
            render_api_error!(_("Your report couldn't be saved due to some problem. Please contact the administrator."), Api::Status::Http::BAD_REQUEST)
          end
        end

        desc "Returns the articles I voted" do
          detail "Get the Articles I make a vote"
          failure [[Api::Status::Http::FORBIDDEN, "Forbidden"]]
          named "ArticleFollowers"
        end
        # FIXME refactor this method
        get "voted_by_me" do
          present_articles(current_person.votes.where(voteable_type: "Article").collect(&:voteable))
        end

        desc "Perform a vote on a article by id" do
          detail "Vote on a specific article with values: 1 (if you like) or -1 (if not)"
          params Entities::UserLogin.documentation
          failure [[Api::Status::Http::UNAUTHORIZED, "Unauthorized"]]
          named "ArticleVote"
        end
        post ":id/vote" do
          authenticate!
          value = (params[:value] || 1).to_i
          # FIXME verify allowed values
          render_api_error!("Vote value not allowed", Api::Status::Http::BAD_REQUEST) unless [-1, 1].include?(value)
          article = find_article(environment.articles, id: params[:id])
          begin
            vote = Vote.new(voteable: article, voter: current_person, vote: value)
            vote.save!

            output = { success: true }
            output[:message] = _("Your vote was created.")
            output[:code] = Api::Status::Http::CREATED

            present output, with: Entities::Response
          rescue ActiveRecord::RecordInvalid => e
            render_model_errors!(vote.errors)
          end
        end

        desc "Return the articles followed by me"
        get "followed_by_me" do
          present_articles_for_asset(current_person, "following_articles")
        end

        desc "Add a follower for the article" do
          detail "Add the current user identified by private token, like a follower of a article"
          params Entities::UserLogin.documentation
          failure [[Api::Status::Http::UNAUTHORIZED, "Unauthorized"]]
          named "ArticleFollow"
        end
        post ":id/follow" do
          authenticate!
          article = find_article(environment.articles, id: params[:id])
          if article.article_followers.exists?(person_id: current_person.id)
            { success: false, already_follow: true }
            output = { success: false }
            output[:message] = _("You already follow this article.")
            output[:code] = Api::Status::Http::ALREADY_FOLLOW
          else
            article_follower = ArticleFollower.new
            article_follower.article = article
            article_follower.person = current_person
            article_follower.save!
            { success: true }
            output = { success: true }
            output[:message] = _("You are now following the article %s.") % article.title
            output[:code] = Api::Status::Http::CREATED
          end

          present output, with: Entities::Response
        end

        desc "Return the children of a article identified by id" do
          detail "Get all children articles of a specific article"
          params Entities::Article.documentation
          failure [[Api::Status::Http::FORBIDDEN, "Forbidden"]]
          named "ArticleChildren"
        end

        paginate per_page: MAX_PER_PAGE, max_per_page: MAX_PER_PAGE
        get ":id/children" do
          article = find_article(environment.articles, id: params[:id])

          # TODO make tests for this situation
          votes_order = params.delete(:order) if params[:order] == "votes_score"
          articles = select_filtered_collection_of(article, "children", params)
          articles = articles.accessible_to(current_person)

          # TODO make tests for this situation
          if votes_order
            articles = articles.joins("left join votes on articles.id=votes.voteable_id").group("articles.id").reorder("sum(coalesce(votes.vote, 0)) DESC")
          end
          Article.hit(articles)
          present_articles(articles)
        end

        desc "Return one child of a article identified by id" do
          detail "Get a child of a specific article"
          params Entities::Article.documentation
          success Entities::Article
          failure [[Api::Status::Http::FORBIDDEN, "Forbidden"]]
          named "ArticleChild"
        end
        get ":id/children/:child_id" do
          article = find_article(environment.articles, id: params[:id])
          child_params = {}
          child_params[:id] = params[:child_id]
          child = find_article(article.children, child_params)
          child.hit
          present_partial child, with: Entities::Article
        end

        desc "Suggest a article to another profile" do
          detail "Suggest a article to another profile (person, community...)"
          params Entities::Article.documentation
          success Entities::Task
          failure [[Api::Status::Http::UNAUTHORIZED, "Unauthorized"]]
          named "ArticleSuggest"
        end
        post ":id/children/suggest" do
          authenticate!
          parent_article = environment.articles.find(params[:id])

          suggest_article = SuggestArticle.new
          suggest_article.article = params[:article]
          suggest_article.article[:parent_id] = parent_article.id
          suggest_article.target = parent_article.profile
          suggest_article.requestor = current_person

          unless suggest_article.save
            render_model_errors!(suggest_article.article_object.errors)
          end
          present_partial suggest_article, with: Entities::Task
        end

        # Example Request:
        #  POST api/v1/articles/:id/children?private_token=234298743290432&article[name]=title&article[body]=body
        desc "Add a child article to a parent identified by id" do
          detail "Create a new article and associate to a parent"
          params Entities::Article.documentation
          success Entities::Article
          failure [[Api::Status::Http::UNAUTHORIZED, "Unauthorized"]]
          named "ArticleAddChild"
        end
        post ":id/children" do
          parent_article = environment.articles.find(params[:id])
          params[:article][:parent_id] = parent_article.id
          post_article(parent_article.profile, params)
        end
      end

      resource :profiles do
        get ":id/home_page" do
          profiles = environment.profiles
          profiles = profiles.accessible_to(current_person)
          profile = profiles.find_by id: params[:id]
          present_partial profile.home_page, with: Entities::Article
        end
      end

      kinds = %w[profile community person enterprise]
      kinds.each do |kind|
        resource kind.pluralize.to_sym do
          segment "/:#{kind}_id" do
            resource :articles do
              desc "Return all articles associate with a profile of type #{kind}" do
                detail "Get a list of articles of a profile"
                params Entities::Article.documentation
                success Entities::Article
                failure [[Api::Status::Http::FORBIDDEN, "Forbidden"]]
                named "ArticlesOfProfile"
              end
              get do
                profile = environment.send(kind.pluralize).find(params["#{kind}_id"])

                present_articles_for_asset(profile)
              end

              desc "Return a article associate with a profile of type #{kind}" do
                detail "Get only one article of a profile"
                params Entities::Article.documentation
                success Entities::Article
                failure [[Api::Status::Http::FORBIDDEN, "Forbidden"]]
                named "ArticleOfProfile"
              end
              get "/*id" do
                profile = environment.send(kind.pluralize).find(params["#{kind}_id"])
                key = (params[:key].present? && params[:key] == "path") ? :path : :id

                article = profile.articles.find_by(key => params[:id])
                if article && !article.display_to?(current_person)
                  article = forbidden!
                end
                article ||= not_found!

                present_partial article, with: Entities::Article, current_person: current_person
              end

              # Example Request:
              #  POST api/v1/{people,communities,enterprises}/:asset_id/articles?private_token=234298743290432&article[name]=title&article[body]=body
              desc "Add a new article associated with a profile of type #{kind}" do
                detail "Create a new article and associate with a profile"
                params Entities::Article.documentation
                success Entities::Article
                failure [[Api::Status::Http::FORBIDDEN, "Forbidden"]]
                named "ArticleCreateToProfile"
              end
              post do
                profile = environment.send(kind.pluralize).find(params["#{kind}_id"])
                post_article(profile, params)
              end
            end
          end
        end
      end
    end
  end
end