add forums visibility

This commit is contained in:
byte[] 2019-10-06 17:31:48 -04:00
parent a37699338e
commit 02f30391f6
13 changed files with 326 additions and 1 deletions

View file

@ -2,6 +2,7 @@ defmodule Philomena.Forums.Forum do
use Ecto.Schema
import Ecto.Changeset
@derive {Phoenix.Param, key: :short_name}
schema "forums" do
belongs_to :last_post, Philomena.Posts.Post
belongs_to :last_topic, Philomena.Topics.Topic
@ -22,4 +23,4 @@ defmodule Philomena.Forums.Forum do
|> cast(attrs, [])
|> validate_required([])
end
end
end

View file

@ -2,12 +2,14 @@ defmodule Philomena.Topics.Topic do
use Ecto.Schema
import Ecto.Changeset
@derive {Phoenix.Param, key: :slug}
schema "topics" do
belongs_to :user, Philomena.Users.User
belongs_to :deleted_by, Philomena.Users.User
belongs_to :locked_by, Philomena.Users.User
belongs_to :last_post, Philomena.Posts.Post
belongs_to :forum, Philomena.Forums.Forum
has_one :poll, Philomena.Polls.Poll
field :title, :string
field :post_count, :integer, default: 0

View file

@ -0,0 +1,35 @@
defmodule PhilomenaWeb.ForumController do
use PhilomenaWeb, :controller
alias Philomena.{Forums.Forum, Topics.Topic}
alias Philomena.Repo
import Ecto.Query
plug :load_and_authorize_resource, model: Forum, id_field: "short_name"
def index(conn, _params) do
user = conn.assigns.current_user
forums =
Forum
|> preload([last_post: [:topic, :user]])
|> Repo.all()
|> Enum.filter(&Canada.Can.can?(user, :show, &1))
topic_count = Repo.aggregate(Forum, :sum, :topic_count)
render(conn, "index.html", forums: forums, topic_count: topic_count)
end
def show(conn, %{"id" => _id}) do
topics =
Topic
|> where(forum_id: ^conn.assigns.forum.id)
|> where(hidden_from_users: false)
|> order_by(desc: :sticky, desc: :last_replied_to_at)
|> preload([:poll, :forum, :user, last_post: :user])
|> limit(25)
|> Repo.all()
render(conn, "show.html", forum: conn.assigns.forum, topics: topics)
end
end

View file

@ -0,0 +1,22 @@
defmodule PhilomenaWeb.TopicController do
use PhilomenaWeb, :controller
alias Philomena.{Forums.Forum, Topics.Topic, Posts.Post}
alias Philomena.Repo
import Ecto.Query
plug :load_and_authorize_resource, model: Forum, id_name: "forum_id", id_field: "short_name", persisted: true
plug :load_and_authorize_resource, model: Topic, id_name: "id", id_field: "slug", preload: :user
def show(conn, %{"id" => _id}) do
posts =
Post
|> where(topic_id: ^conn.assigns.topic.id)
|> order_by(asc: :created_at, asc: :id)
|> preload([:user, topic: :forum])
|> limit(25)
|> Repo.all()
render(conn, "show.html", posts: posts)
end
end

View file

@ -29,6 +29,9 @@ defmodule PhilomenaWeb.Router do
resources "/images", ImageController, only: [:index, :show]
resources "/tags", TagController, only: [:index, :show]
resources "/search", SearchController, only: [:index]
resources "/forums", ForumController, only: [:index, :show] do
resources "/topics", TopicController, only: [:show]
end
get "/:id", ImageController, :show
end

View file

@ -0,0 +1,33 @@
h1 Discussion Forums
.block
.block__header
/= icon_link 'Search Posts', 'fa fa-fw fa-search', posts_path
span.block__header__item
=> @topic_count
' topics
.block__content
table.table.table--communication-list
thead
tr
th.table--communication-list__name Forum
th.table--communication-list__stats.hide-mobile Topics
th.table--communication-list__stats.hide-mobile Posts
th.table--communication-list__last-post Last Post
tbody
= for forum <- @forums do
tr
td.table--communication-list__name
=> link(forum.name, to: Routes.forum_path(@conn, :show, forum))
.small-text = forum.description
td.table--communication-list__stats.hide-mobile = forum.topic_count
td.table--communication-list__stats.hide-mobile = forum.post_count
td.table--communication-list__last-post
= if forum.last_post do
strong
=> link(forum.last_post.topic.title, to: Routes.forum_topic_path(@conn, :show, forum, forum.last_post.topic))
br
=> link("Go to post", to: Routes.forum_topic_path(@conn, :show, forum, forum.last_post.topic, post_id: forum.last_post.id))
' by
=> render PhilomenaWeb.UserAttributionView, "_anon_user.html", object: forum.last_post
br
=> pretty_time(forum.last_post.created_at)

View file

@ -0,0 +1,58 @@
h1 = @forum.name
.block
.block__header
=> link("Forums", to: Routes.forum_path(@conn, :index))
' &raquo;
=> link(@forum.name, to: Routes.forum_path(@conn, :show, @forum))
/= icon_link 'New Topic', 'fas fa-fw fa-pen-square', new_forum_topic_path(@forum)
/= icon_link 'Search Posts', 'fa fa-fw fa-search', posts_path(forum_id: @forum.id)
span.spacing-left
=> @forum.topic_count
' topics
.block__header--sub.block__header--light
/- if @forum.topic_count >= Topic.topics_per_page do
/ = paginate @topics
span.block__header__title = @forum.description
/- if current_user
/ = subscription_link(@forum, current_user)
/- else
/ | Login to subscribe to new threads
.block__content
table.table.table--communication-list
thead
tr
th.table--communication-list__name Topic
th.table--communication-list__stats.hide-mobile Views
th.table--communication-list__stats.hide-mobile Posts
th.table--communication-list__last-post Last Post
tbody
= for topic <- @topics do
tr
td.table--communication-list__name
= if topic.sticky do
i.fa.fa-thumbtack
= if topic.locked_at do
i.fa.fa-lock
= if topic.poll do
i.fas.fa-poll-h
=< link(topic.title, to: Routes.forum_topic_path(@conn, :show, @forum, topic))
.small-text
' Posted
=> pretty_time(topic.created_at)
' by
= render PhilomenaWeb.UserAttributionView, "_anon_user.html", object: topic
td.table--communication-list__stats.hide-mobile = topic.view_count
td.table--communication-list__stats.hide-mobile = topic.post_count
td.table--communication-list__last-post
= if topic.last_post do
=> link("Go to post", to: Routes.forum_topic_path(@conn, :show, @forum, topic, post_id: topic.last_post) <> "post_#{topic.last_post.id}")
' by
= render PhilomenaWeb.UserAttributionView, "_anon_user.html", object: topic.last_post
br
=> pretty_time(topic.last_post.created_at)
/= if @forum.topic_count >= Topic.topics_per_page do
/ .block__header.block__header--light
/ = paginate @topics
/- if current_user
/ = render partial: 'topics/form'

View file

@ -0,0 +1,36 @@
article.block.communication id="post_#{@post.id}"
.block__content.flex.flex--no-wrap
.flex__fixed.spacing-right
/=<> user_avatar((post.user if post.user_visible?), 'avatar--100px', post.author)
.flex__grow.communication__body
span.communication__body__sender-name = render PhilomenaWeb.UserAttributionView, "_anon_user.html", object: @post
.communication__body__text
= if !@post.hidden_from_users do
=<> @post.body
.block__content.communication__options
.flex.flex--wrap.flex--spaced-out
= render PhilomenaWeb.PostView, "_post_options.html", conn: @conn, post: @post
/- if can?(:hide, Post)
/ .js-staff-action
/ - if !post.hidden_from_users && !post.destroyed_content
/ =<> link_to '#', class: 'communication__interaction togglable-delete-form-link', 'data-click-toggle': "#inline-del-form-post-#{post.id}" do
/ i.fa.fa-times
/ =<> 'Delete'
/ - elsif post.hidden_from_users && !post.destroyed_content
/ =<> link_to forum_topic_post_hide_path(post.topic.forum, post.topic, post), data: { confirm: t('are_you_sure') }, method: :delete, class: 'communication__interaction' do
/ i.fa.fa-check
/ =<> 'Restore'
/ - if can?(:manage, Post)
/ =<> link_to forum_topic_post_path(post.topic.forum, post.topic, post, deletion_reason: post.deletion_reason), method: :delete, data: { confirm: t('are_you_sure') }, class: 'communication__interaction' do
/ i.fa.fa-times
/ =<> 'Delete Contents'
/ - if can?(:manage, Post)
/ .communication__info
/ =<> link_to_ip(post.ip)
/ .communication__info
/ =<> link_to_fingerprint(post.fingerprint, post.user_agent)
/ = form_tag forum_topic_post_hide_path(post.topic.forum, post.topic, post), class: 'togglable-delete-form hidden flex', id: "inline-del-form-post-#{post.id}"
/ = text_field_tag :deletion_reason, nil, class: 'input input--wide', placeholder: 'Deletion Reason', id: "inline-del-reason-post-#{post.id}", required: true
/ = submit_tag 'Delete', class: 'button'

View file

@ -0,0 +1,31 @@
div
' Posted
=> pretty_time(@post.created_at)
/=<> link_to new_report_path(reportable_class: 'Post', reportable_id: post.id), class: 'communication__interaction' do
/ i.fa.fa-flag
/ =<> 'Report'
/- if post.edited_at && can?(:read, post)
/ br
/ a href=forum_topic_post_history_path(post.topic.forum, post.topic, post)
/ | Edited
/ =<> friendly_time(post.edited_at)
/ - if post.edit_reason.present?
/ | because:
/ =<> post.edit_reason
div
- link_path = Routes.forum_topic_path(@conn, :show, @post.topic.forum, @post.topic, post_id: @post.id) <> "post_#{@post.id}"
a.communication__interaction title="Link to post" href=link_path
i.fa.fa-link>
' Link
/=<> link_to link_path, 'data-author': safe_author(post), 'data-reply-url': link_path, 'data-post': (post.hidden_from_users ? '' : post.body), class: 'communication__interaction post-reply post-reply-quote' do
a.communication__interaction.post-reply.post-reply-quote href=link_path data-reply-url=link_path data-author="" data-post=""
i.fa.fa-quote-right>
' Quote
/=<> link_to link_path, 'data-author': safe_author(post), 'data-reply-url': link_path, class: 'communication__interaction post-reply' do
a.communication__interaction.post-reply href=link_path data-reply-url=link_path data-author=""
i.fa.fa-reply
' Reply
/span.owner-options.hidden
/ strong =<> link_to edit_forum_topic_post_path(post.topic.forum, post.topic, post), class: 'communication__interaction' do
/ i.fas.fa-edit
/ ' Edit

View file

@ -0,0 +1,95 @@
h1 = @topic.title
/ Header section
.block
.block__header
=> link("Forums", to: Routes.forum_path(@conn, :index))
' &raquo;
=> link(@forum.name, to: Routes.forum_path(@conn, :show, @forum))
' &raquo;
=> link(@topic.title, to: Routes.forum_topic_path(@conn, :show, @forum, @topic))
/a href=posts_path(forum_id: @forum.id, subject: @topic.title)
/ i.fa.fa-fw.fa-search>
/ | Search Posts
.flex.flex--wrap.block__header.block__header--light
/.flex--fixed
/ = paginate @posts
.flex--fixed.block__header__item
' Started by
=> render PhilomenaWeb.UserAttributionView, "_anon_user.html", object: @topic
.flex--fixed.block__header__item
' Posted
=< pretty_time(@topic.created_at)
.flex--fixed.block__header__item
=> @topic.post_count - 1
' replies
/= if current_user
/ = subscription_link(@topic, current_user)
/- else
' Login to subscribe to responses
/ Display the poll, if any
/= render partial: 'polls/display', locals: { poll: @topic.poll }
/ The actual posts
.posts-area
.post-list
= for post <- @posts, !post.destroyed_content do
= render PhilomenaWeb.PostView, "_post.html", conn: @conn, post: post
/include ../adverts/_box.html.slim
/ Post editability data for JS
/.js-editable-posts data-editable=editable_communications(@posts).to_json
/ Footer section
/.block: .block__header.block__header--light = paginate @posts
/ Post form
= if @topic.post_count < 200_000 do
/= render partial: 'topics/posts/form'
- else
/h3 Okay, we're impressed
/p You're looking at a thread with over 200,000 posts in it!
/p For various reasons, we'd like to ask you to start a new topic.
/ Mod tools
/- if can? :assist, Topic
/ .block__content
/ input.toggle-box id="administrator_tools" type="checkbox" checked=false
/ label for="administrator_tools" Topic Admin Tools
/ .toggle-box-container
/ .toggle-box-container__content
/ p
/ - if can?(:unlock, @topic) && !@topic.locked_at.nil?
/ => button_to forum_topic_lock_path(@forum, @topic), method: :delete, class: 'button' do
/ i.fa.fa-lock>
/ | Unlock
/ - if can?(:stick, @topic) && !@topic.sticky
/ => button_to forum_topic_stick_path(@forum, @topic), method: :post, class: 'button' do
/ i.fa.fa-thumbtack>
/ | Stick
/ - if can?(:stick, @topic) && @topic.sticky
/ => button_to forum_topic_stick_path(@forum, @topic), method: :delete, class: 'button' do
/ i.fa.fa-thumbtack>
/ | Unstick
/ - if can?(:lock, @topic) && @topic.locked_at.nil?
/ = form_tag forum_topic_lock_path(@forum, @topic), method: :post, class: 'hform' do
/ .field
/ => text_field_tag :lock_reason, '', placeholder: 'Lock reason', class: 'input hform__text'
/ => button_tag class: 'hform__button button' do
/ i.fa.fa-unlock>
/ | Lock
/ - if can? :move, @topic
/ = form_tag forum_topic_move_path(@forum, @topic), method: :post, class: 'hform' do
/ .field
/ => select_tag :target_forum_id, options_from_collection_for_select(Forum.where.not(id: @forum.id).all, :short_name, :name), class: 'input hform__text'
/ => button_tag class: 'hform__button button' do
/ i.fa.fa-truck>
/ | Move
/ - if can?(:destroy, @topic) && !@topic.hidden_from_users
/ = form_tag forum_topic_hide_path(@forum, @topic), method: :post, class: 'hform' do
/ .field
/ => text_field_tag :deletion_reason, '', placeholder: 'Deletion reason', required: true, class: 'input hform__text'
/ => button_tag class: 'hform__button button' do
/ i.fa.fa-trash>
/ | Delete

View file

@ -0,0 +1,3 @@
defmodule PhilomenaWeb.ForumView do
use PhilomenaWeb, :view
end

View file

@ -0,0 +1,3 @@
defmodule PhilomenaWeb.PostView do
use PhilomenaWeb, :view
end

View file

@ -0,0 +1,3 @@
defmodule PhilomenaWeb.TopicView do
use PhilomenaWeb, :view
end