drabkirn/feedka

View on GitHub
app/controllers/feeds_controller.rb

Summary

Maintainability
A
1 hr
Test Coverage
A
100%
class FeedsController < ApplicationController
  before_action :authenticate_user!, only: [:index, :destroy, :public, :private, :export]
  before_action :set_feed, only: [:destroy, :public, :private]
  before_action :decrypt_feed, only: [:public, :private]

  ## GET /feeds
  ## Only logged in users can see their feeds
  def index
    @feeds = current_user.feeds.all.order("updated_at DESC")
  end

  ## GET /f/:username
  ## Anyone can use this link and submit feedback
  def feedback
    ## Pick the user by username params
    ## If user is not found, redirect to root_path with alert message
    user = User.find_by(username: params[:username])
    if !user
      redirect_to root_path, alert: Message.user_not_found
      return
    end

    ## If users email is not confirmed, don't show this page
    if !user.confirmed?
      redirect_to root_path, alert: Message.user_email_not_confirmed
      return
    end

    @feed = Feed.new

    ## Send public only feeds to the view
    public_feeds = []
    user.feeds && user.feeds.order("updated_at DESC").each do |feed|
      public_feeds << feed if feed.public?
    end

    @public_feeds = public_feeds
  end

  def create
    require 'uri'
    require 'net/http'
    require 'json'

    @feed = Feed.new(feed_params)

    ## We cannot use `user_id` as hidden field in forms
    ## So this workfix, helps get the username
    ref_path = URI(request.referer).path
    username = ref_path.split("/").last
    user = User.find_by(username: username)

    ## Now set the user
    ## If user is somehow not set, Feed won't save and returns the error to view
    @feed.user = user if user

    if @feed.valid?
      ## Take the content, apply content moderation to it
      ## Sends back success and error arrays
      ## If error is empty move on, if success is empty move on
      ## Run only if `content_moderation_api_key` is present, else do normal operation
      if ENV["content_moderation_api_key"].present?
        moderation_success, moderation_error = content_moderation(@feed.content)
      else
        moderation_success, moderation_error = [], []
      end
      
      ## If error is not empty -> Throw error
      if !moderation_error.empty?
        redirect_to root_path, custom_alert: moderation_error
        return
      end

      ## If success is not empty -> Means problem in content -> Throw error
      if !moderation_success.empty?
        redirect_to submit_report_path(username: @feed.user.username, feed_content: @feed.content), custom_alert: moderation_success
        return
      end

      ## Send the feedback from 10 - 300 mins later generated randomly
      generate_mins = rand(10..300)
      @feed.content = Encryption.encrypt_data(@feed.content)
      FeedSaveJob.set(wait: generate_mins.minutes).perform_later(@feed.user.id, @feed.content)
      redirect_to root_path, notice: Message.feed_created
    else
      redirect_to ref_path, custom_alert: @feed.errors.full_messages
    end
  end

  ## DELETE /feeds
  ## Only logged in users can delete their feeds
  def destroy
    @feed.destroy
    redirect_to feeds_path, alert: Message.feed_destroyed
  end

  ## PATCH /feeds/:id/public
  ## Only logged in users can make this feed public
  def public
    @feed.update_attribute(:public, true)
    redirect_to feeds_path, notice: Message.feed_public
  end

  ## PATCH /feeds/:id/private
  ## Defaults by private itself
  ## Only logged in users can make this feed private
  def private
    @feed.update_attribute(:public, false)
    redirect_to feeds_path, notice: Message.feed_private
  end

  ## GET /feeds/export
  ## Let's you export all your feedbacks
  ## in a text file
  def export
    @feeds = current_user.feeds.all
    text_content = ""
    @feeds.each_with_index do |feed, index|
      decrypted_content = Encryption.decrypt_data(feed.content)
      text_content = text_content + "\n" + (index + 1).to_s + ". " + decrypted_content
    end
    send_data text_content, filename: "#{current_user.username}.txt", type: :text, disposition: 'attachment'
  end


  private
    ## Set the feed, DRY
    def set_feed
      @feed = Feed.find(params[:id])
    end

    ## Whitelist params for feeds, anything else will be rejected
    def feed_params
      params.require(:feed).permit(:content)
    end

    ## Decrypt the content before showing it to users
    def decrypt_feed
      @feed.content = Encryption.decrypt_data(@feed.content)
    end

    ## Make the API call for moderation, then send the results back as success, error
    def content_moderation(content)
      url = ENV["content_moderation_url"]
      uri = URI(url)

      ## Add empty arrays: Error and Success
      error = []
      success = []

      request = Net::HTTP::Post.new(uri.request_uri)
        
      # Request headers
      request['Content-Type'] = ' text/plain'
      request['Ocp-Apim-Subscription-Key'] = ENV["content_moderation_api_key"]
      
      # Request body
      request.body = content

      begin
        response = Net::HTTP.start(uri.host, uri.port, :use_ssl => uri.scheme == 'https') do |http|
          http.request(request)
        end
      rescue StandardError => e
        error << Message.api_error
        return success, error
      end

      response_body = JSON.parse(response.body)

      if response_body["error"]
        error << response_body["error"]["message"]
      end

      if response_body["PII"]
        success << Message.pii_info_found
      end

      if response_body["Terms"]
        success << Message.abuse_found
      end

      return success, error
    end
end