publiclab/plots2

View on GitHub
app/controllers/wiki_controller.rb

Summary

Maintainability
F
4 days
Test Coverage
require 'rss'

class WikiController < ApplicationController
  before_action :require_user, only: %i(new create edit update delete replace)

  def subdomain
    url = "//#{request.host}/wiki/"
    case request.subdomain
    when 'new-york-city',
         'gulf-coast',
         'boston',
         'espana' then
      redirect_to url + request.subdomain
    when 'nyc'
      redirect_to url + 'new-york-city'
    else
      redirect_to url
    end
  end

  def show
    @node = if params[:lang]
              Node.find_wiki(params[:lang] + '/' + params[:id])
            else
              Node.find_wiki(params[:id])
    end

    if @node&.has_power_tag('redirect') && Node.where(nid: @node.power_tag('redirect')).exists?
      if current_user.nil? || !current_user.can_moderate?
        redirect_to Node.find(@node.power_tag('redirect')).path
        return
      elsif current_user.can_moderate?
        flash.now[:warning] = "Only moderators and admins see this page, as it is redirected to <a href='#{Node.find(@node.power_tag('redirect')).path}'>#{Node.find(@node.power_tag('redirect')).title}</a>.
        To remove the redirect, delete the tag beginning with 'redirect:'"
      end

    elsif @node&.has_power_tag('redirect') && Node.where(slug: @node.power_tag('redirect')).exists?
      if current_user.nil? || !current_user.can_moderate?
        redirect_to Node.find_by(slug: @node.power_tag('redirect')).path
        return
      elsif current_user.can_moderate?
        flash.now[:warning] = "Only moderators and admins see this page, as it is redirected to <a href='#{Node.find_by(slug: @node.power_tag('redirect')).path}'>#{Node.find_by(slug: @node.power_tag('redirect')).title}</a>.
        To remove the redirect, delete the tag beginning with 'redirect:'"
      end
      if @node&.has_power_tag('abtest') && !Node.where(nid: @node.power_tag('abtest')).empty?
        if current_user.nil? || !current_user.can_moderate?
          if Random.rand(2) == 0
            redirect_to Node.find(@node.power_tag('abtest')).path
            return
          end
        elsif current_user.can_moderate?
          flash.now[:warning] = "Only moderators and admins see this page, as it is redirected to #{Node.find(@node.power_tag('abtest')).title} roughly around 50% of the time.
        To remove this behavior, delete the tag beginning with 'abtest:'"
        end
      end
    end

    return if redirect_to_node_path?(@node)

    if !@node.nil? # it's a place page!
      @tags = @node.tags
      @tags += [Tag.find_by(name: params[:id])] if Tag.find_by(name: params[:id])
    else # it's a new wiki page!
      @title = I18n.t('wiki_controller.new_wiki_page')
      if current_user
        new
      else
        flash[:warning] = I18n.t('wiki_controller.pages_does_not_exist')
        redirect_to '/login'
      end
    end

    unless @title # the page exists
      if @node.status == 0
        flash[:warning] = I18n.t('wiki_controller.page_moderated_as_spam')
        redirect_to '/wiki'
      end
      @tagnames = @tags.collect(&:name)
      @wikis = Tag.find_pages(@node.slug_from_path, 30) if @node.has_tag('chapter') || @node.has_tag('tabbed:wikis')

      impressionist(@node, 'show', unique: [:ip_address])
      @revision = @node.latest # needed for template, so it can be used for past revisions too in the "revision" action
      @title = @revision.title
    end
    @unpaginated = true
  end

  # display a revision, raw
  def raw
    response.headers['Content-Type'] = 'text/plain; charset=utf-8'
    render plain: Revision.find(params[:id]).body
  end

  def print
    @node = Node.find_by(nid: params[:id], type: 'page')
    return if redirect_to_node_path?(@node)
    @revision = @node.latest

    if @node
      impressionist(@node, 'print', unique: [:ip_address])
      render layout: "print"

    else
      page_not_found
    end
  end

  def edit
    @revision = Revision.new
    @node = if params[:lang]
              Node.find_wiki(params[:lang] + '/' + params[:id])
            else
              Node.find_wiki(params[:id])
    end

    if @node.has_tag('locked') && !current_user.can_moderate?
      flash[:warning] = "This page is <a href='/wiki/power-tags#Locking'>locked</a>, and only <a href='/wiki/moderators'>moderators</a> can edit it."
      redirect_to @node.path
    elsif current_user &.first_time_poster
      flash[:notice] = "You can edit this wiki once your research note/question has been approved by moderators. Click <a href='https://publiclab.org/notes/tester/04-23-2016/new-moderation-system-for-first-time-posters'>here</a> to learn why."
      redirect_to Node.find_wiki(params[:id]).path
      return
    end
    if ((Time.now.to_i - @node.latest.timestamp) < 5.minutes.to_i) && @node.latest.author.uid != current_user.uid
      flash.now[:warning] = I18n.t('wiki_controller.someone_clicked_edit_5_minutes_ago')
    end
    # we could do this...
    # @node.locked = true
    # @node.save
    @title = I18n.t('wiki_controller.editing', title: @node.title).html_safe

    @tags = @node.tags
  end

  def new
    @revision = Revision.new
    if current_user &.first_time_poster
      flash[:notice] = "You can create a wiki once your research note/question has been approved by moderators. Click <a href='https://publiclab.org/notes/tester/04-23-2016/new-moderation-system-for-first-time-posters'>here</a> to learn why."
      redirect_to '/'
      return
    end
    @node = Node.new
    if params[:n] && !params[:body] # use another node body as a template
      node = Node.find(params[:n])
      params[:body] = node.latest.body if node&.latest
    end
    @tags = []
    if params[:id]
      flash.now[:notice] = I18n.t('wiki_controller.page_does_not_exist_create')
      title = params[:id].tr('-', ' ')
      @related = Node.limit(10)
        .order('node.nid DESC')
        .where('type = "page" AND node.status = 1 AND (node.title LIKE ? OR node_revisions.body LIKE ?)', '%' + title + '%', '%' + title + '%')
        .includes(:revision)
        .references(:node_revisions)
      tag = Tag.find_by(name: params[:id]) # add page name as a tag, too
      @tags << tag if tag
      @related += Tag.find_nodes_by_type(@tags.collect(&:name), 'page', 10)
    end
    if params[:rich]
      render template: 'editor/wikiRich'
    else
      respond_to do |format|
        format.html { render 'wiki/edit' }
        format.all { head :ok }
      end
    end
  end

  def create
    if current_user.status == 1
      # we no longer allow custom urls, just titles which are parameterized automatically into urls
      # slug = params[:title].parameterize
      # slug = params[:id].parameterize if params[:id] != "" && !params[:id].nil?
      # slug = params[:url].parameterize if params[:url] != "" && !params[:url].nil?
      saved, @node, @revision = Node.new_wiki(uid:   current_user.uid,
                                              title: params[:title],
                                              body:  params[:body])
      if saved
        flash[:notice] = I18n.t('wiki_controller.wiki_page_created')
        params[:tags]&.tr(' ', ',')&.split(',')&.each do |tagname|
          @node.add_tag(tagname.strip, current_user)
        end
        if params[:main_image] && params[:main_image] != ''
          img = Image.find params[:main_image]
          img.nid = @node.id
          img.save
        end
        redirect_to @node.path
      else
        if params[:main_image] && Image.find_by(id: params[:main_image])
          @main_image = Image.find_by(id: params[:main_image]).path
        end
        if params[:n] && !params[:body] # use another node body as a template
          node = Node.find(params[:n])
          params[:body] = node.body if node
        end
        flash[:error] = "Please enter both body and title"
        render template: 'editor/wikiRich'
      end
    else
      flash.keep[:error] = I18n.t('wiki_controller.you_have_been_banned').html_safe
      redirect_to '/logout'
    end
  end

  def update
    @node = Node.find(params[:id])
    @revision = @node.new_revision(uid:   current_user.uid,
                                   title: params[:title],
                                   body:  params[:body])

    if @node.has_tag('locked') && !current_user.can_moderate?
      flash[:warning] = "This page is <a href='/wiki/power-tags#Locking'>locked</a>, and only <a href='/wiki/moderators'>moderators</a> can update it."
      redirect_to @node.path

    elsif @revision.valid?
      @revision.save
      update_node_attributes

      flash[:notice] = I18n.t('wiki_controller.edits_saved')
      redirect_to @node.path
    else
      flash[:error] = I18n.t('wiki_controller.edit_could_not_be_saved')
      render action: :edit
    end
  end

  def delete
    @node = Node.find(params[:id])
    if current_user&.admin?
      @node.destroy
      flash[:notice] = I18n.t('wiki_controller.wiki_page_deleted')
      redirect_to '/dashboard'
    else
      flash[:error] = I18n.t('wiki_controller.only_admins_delete_pages')
      redirect_to @node.path
    end
  end

  def revert
    revision = Revision.find params[:id]
    node = revision.parent
    if current_user&.can_moderate?
      new_rev = revision.dup
      new_rev.timestamp = DateTime.now.to_i
      if new_rev.save!
        flash[:notice] = I18n.t('wiki_controller.wiki_page_reverted')
      else
        flash[:error] = I18n.t('wiki_controller.problem_reverting')
      end
    else
      flash[:error] = I18n.t('wiki_controller.moderators_admin_delete_pages')
    end
    redirect_to node.path
  end

  # wiki pages which have a root URL, like /about
  # also just redirect anything else matching /____ to /wiki/____
  def root
    @node = Node.find_by(path: "/" + params[:id])
    return if redirect_to_node_path?(@node)

    if @node
      @revision = @node.latest
      @title = @revision.title
      @tags = @node.tags
      @tagnames = @tags.collect(&:name)
      render template: 'wiki/show'
    elsif !Node.find_by(slug: params[:id]).nil?
      redirect_to URI.parse('/wiki/' + params[:id]).path
    else
      redirect_to URI.parse('/tag/' + params[:id]).path
    end
  end

  def revisions
    @node = Node.find_wiki(params[:id])
    if @node
      @revisions = @node.revisions
      @pagy_revisions, @revisions = pagy(@revisions.where(status: 1), items: 20) unless current_user&.can_moderate?
      @title = I18n.t('wiki_controller.revisions_for', title: @node.title).html_safe
      @tags = @node.tags
      @paginated = true unless current_user&.can_moderate?
    else
      flash[:error] = I18n.t('wiki_controller.invalid_wiki_page')
    end
  end

  def revision
    @node = Node.find_wiki(params[:id])
    if @node
      @tags = @node.tags
      @tagnames = @tags.collect(&:name)
      @unpaginated = true
      @is_revision = true
      @revision = Revision.find_by_nid_and_vid(@node.id, params[:vid])
      if @revision.nil?
        flash[:error] = I18n.t('wiki_controller.revision_not_found')
        redirect_to action: 'revisions'
      elsif @revision.status == 1 || current_user&.can_moderate?
        @title = I18n.t('wiki_controller.revisions_for', title: @revision.title).html_safe
        render template: 'wiki/show'
      else
        flash[:error] = I18n.t('wiki_controller.revision_has_been_moderated').html_safe
        redirect_to @node.path
      end
    else
      flash[:error] = I18n.t('wiki_controller.invalid_wiki_page')
    end
  end

  def diff
    @a = Revision.find_by(vid: params[:a])
    @b = Revision.find_by(vid: params[:b])
    if @a.body == @b.body
      render plain: I18n.t('wiki_controller.lead_image_or_title_change').html_safe
    else
      render partial: 'wiki/diff'
    end
  end

  def index
    @title = I18n.t('wiki_controller.wiki')
    sort_param = params[:sort]
    order_string = 'node_revisions.timestamp DESC'

    if sort_param == 'title'
      order_string = 'node_revisions.title ASC'
    elsif sort_param == 'last_edited'
      order_string = 'node_revisions.timestamp DESC'
    elsif sort_param == 'edits'
      order_string = 'drupal_node_revisions_count DESC'
    elsif sort_param == 'page_views'
      order_string = 'views DESC'
    elsif sort_param == 'likes'
      order_string = 'cached_likes DESC'
    end

    @pagy, @wikis = pagy(Node.includes(:revision)
      .references(:node_revisions)
      .group('node_revisions.nid, node_revisions.vid')
      .order(order_string)
      .where("node_revisions.status = 1 AND node.status = 1 AND type = 'page'"), items: 10).uniq

    @paginated = true
  end

  def stale
    @title = I18n.t('wiki_controller.wiki')

    @pagy, @wikis = pagy(Node.includes(:revision)
      .references(:node_revisions)
      .group('node_revisions.nid, node_revisions.vid')
      .order('node_revisions.timestamp ASC')
      .where("node_revisions.status = 1 AND node.status = 1 AND type = 'page'"), items: 10).uniq

    @paginated = true
    render template: 'wiki/index'
  end

  def popular
    @title = I18n.t('wiki_controller.popular_wiki_pages')
    @wikis = Node.limit(40)
      .joins(:revision)
      .group('node_revisions.nid, node_revisions.vid')
      .order('node_revisions.timestamp DESC')
      .where("node.status = 1 AND node_revisions.status = 1 AND node.nid != 259 AND type = 'page'")
      .sort_by(&:views).reverse.uniq
    render template: 'wiki/index'
  end

  def liked
    @title = I18n.t('wiki_controller.well_liked_wiki_pages')
    @wikis = Node.limit(40)
      .order('node.cached_likes DESC')
      .where("status = 1 AND nid != 259 AND (type = 'page') AND cached_likes >= 0").uniq

    render template: 'wiki/index'
  end

  # replace subsection of wiki body
  def replace
    @node = Node.find(params[:id])
    if params[:before] && params[:after]
      # during round trip, strings are getting "\r\n" newlines converted to "\n",
      # so we're ensuring they remain "\r\n"; this may vary based on platform, unfortunately
      before = params[:before] # params[:before].gsub("\n", "\r\n") # actually we're stopping this bc it didn't work...
      after  = params[:after] # .gsub( "\n", "\r\n")
      if output = @node.replace(before, after, current_user)
        flash[:notice] = 'New revision created with your additions.' unless request.xhr?
      else
        flash[:error] = 'There was a problem replacing that text.' unless request.xhr?
      end
    else
      flash[:error] = "You must specify 'before' and 'after' terms to replace content in a wiki page."
    end
    if request.xhr?
      if output.blank?
        render json: output, status: 500
      else
        render json: output
      end
    else
      redirect_to @node.path
    end
  end

  def techniques
    redirect_to '/methods', status: 302
  end

  def methods
    @nodes = Node.where(status: 1, type: %w(page))
      .where('term_data.name = ?', 'method')
      .includes(:revision, :tag)
      .references(:node_revision)
      .order('node_revisions.timestamp DESC')
    # deprecating the following in favor of javascript implementation in /app/assets/javascripts/methods.js
    if params[:topic]
      nids = @nodes.collect(&:nid) || []
      @notes = Node.where(status: 1, type: %w(page))
        .where('node.nid IN (?)', nids)
        .where('(type = "note" OR type = "page" OR type = "map") AND node.status = 1 AND (node.title LIKE ? OR node_revisions.title LIKE ? OR node_revisions.body LIKE ? OR term_data.name = ?)',
          '%' + params[:topic] + '%',
          '%' + params[:topic] + '%',
          '%' + params[:topic] + '%',
          params[:topic])
        .includes(:revision, :tag)
        .references(:node_revision, :term_data)
        .order('node_revisions.timestamp DESC')
    end
    if params[:topic]
      nids = @nodes.collect(&:nid) || []
      @nodes = Node.where(status: 1, type: %w(page))
        .where('node.nid IN (?)', nids)
        .where('(type = "note" OR type = "page" OR type = "map") AND node.status = 1 AND (node.title LIKE ? OR node_revisions.title LIKE ? OR node_revisions.body LIKE ? OR term_data.name = ?)',
          '%' + params[:topic] + '%',
          '%' + params[:topic] + '%',
          '%' + params[:topic] + '%',
          params[:topic])
        .includes(:revision, :tag)
        .references(:node_revision, :term_data)
        .order('node_revisions.timestamp DESC')
    end

    @unpaginated = true
    @topics = [
      'agriculture',
      'drinking-water',
      'fracking',
      'indoor-air',
      'chemicals',
      'industry',
      'land-use',
      'land-change',
      'mining',
      'oil-and-gas',
      'transportation',
      'urban-planning',
      'sensors',
      'community-organizing'
    ]
    render template: 'wiki/methods'
  end

  def comments
    show
    render :show
  end

  def update_node_attributes
    ActiveRecord::Base.transaction do
      @node.vid = @revision.vid
      @node.title = @revision.title

      if main_image = @node.drupal_main_image && params[:main_image].blank?
        main_image.vid = @revision.vid
        main_image.save
      end

      if params[:main_image].to_i == 0
        @node.main_image_id = nil
      elsif params[:main_image].present? && img = Image.find(params[:main_image])
        img.nid = @node.id
        @node.main_image_id = img.id
        img.save
      end
      @node.save
      update_tags if @node.valid?
    end
  end

  def update_tags
    tids = @node.tag.pluck(:tid)
    Tag.update_tags_activity(tids, @node.nid)
  end

  def author
    @user = User.find_by(name: params[:id])
    @title = @user.name
    @pagy, @wikis = pagy(Node
      .order('nid DESC')
      .where("uid = ? AND type = 'page' AND status = 1", @user.uid), items: 24)
    render template: 'wiki/index'
  end
end