mirror of
https://github.com/philomena-dev/philomena.git
synced 2024-11-27 13:47:58 +01:00
add forums visibility
This commit is contained in:
parent
a37699338e
commit
02f30391f6
13 changed files with 326 additions and 1 deletions
|
@ -2,6 +2,7 @@ defmodule Philomena.Forums.Forum do
|
||||||
use Ecto.Schema
|
use Ecto.Schema
|
||||||
import Ecto.Changeset
|
import Ecto.Changeset
|
||||||
|
|
||||||
|
@derive {Phoenix.Param, key: :short_name}
|
||||||
schema "forums" do
|
schema "forums" do
|
||||||
belongs_to :last_post, Philomena.Posts.Post
|
belongs_to :last_post, Philomena.Posts.Post
|
||||||
belongs_to :last_topic, Philomena.Topics.Topic
|
belongs_to :last_topic, Philomena.Topics.Topic
|
||||||
|
@ -22,4 +23,4 @@ defmodule Philomena.Forums.Forum do
|
||||||
|> cast(attrs, [])
|
|> cast(attrs, [])
|
||||||
|> validate_required([])
|
|> validate_required([])
|
||||||
end
|
end
|
||||||
end
|
end
|
|
@ -2,12 +2,14 @@ defmodule Philomena.Topics.Topic do
|
||||||
use Ecto.Schema
|
use Ecto.Schema
|
||||||
import Ecto.Changeset
|
import Ecto.Changeset
|
||||||
|
|
||||||
|
@derive {Phoenix.Param, key: :slug}
|
||||||
schema "topics" do
|
schema "topics" do
|
||||||
belongs_to :user, Philomena.Users.User
|
belongs_to :user, Philomena.Users.User
|
||||||
belongs_to :deleted_by, Philomena.Users.User
|
belongs_to :deleted_by, Philomena.Users.User
|
||||||
belongs_to :locked_by, Philomena.Users.User
|
belongs_to :locked_by, Philomena.Users.User
|
||||||
belongs_to :last_post, Philomena.Posts.Post
|
belongs_to :last_post, Philomena.Posts.Post
|
||||||
belongs_to :forum, Philomena.Forums.Forum
|
belongs_to :forum, Philomena.Forums.Forum
|
||||||
|
has_one :poll, Philomena.Polls.Poll
|
||||||
|
|
||||||
field :title, :string
|
field :title, :string
|
||||||
field :post_count, :integer, default: 0
|
field :post_count, :integer, default: 0
|
||||||
|
|
35
lib/philomena_web/controllers/forum_controller.ex
Normal file
35
lib/philomena_web/controllers/forum_controller.ex
Normal 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
|
22
lib/philomena_web/controllers/topic_controller.ex
Normal file
22
lib/philomena_web/controllers/topic_controller.ex
Normal 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
|
|
@ -29,6 +29,9 @@ defmodule PhilomenaWeb.Router do
|
||||||
resources "/images", ImageController, only: [:index, :show]
|
resources "/images", ImageController, only: [:index, :show]
|
||||||
resources "/tags", TagController, only: [:index, :show]
|
resources "/tags", TagController, only: [:index, :show]
|
||||||
resources "/search", SearchController, only: [:index]
|
resources "/search", SearchController, only: [:index]
|
||||||
|
resources "/forums", ForumController, only: [:index, :show] do
|
||||||
|
resources "/topics", TopicController, only: [:show]
|
||||||
|
end
|
||||||
|
|
||||||
get "/:id", ImageController, :show
|
get "/:id", ImageController, :show
|
||||||
end
|
end
|
||||||
|
|
33
lib/philomena_web/templates/forum/index.html.slime
Normal file
33
lib/philomena_web/templates/forum/index.html.slime
Normal 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)
|
58
lib/philomena_web/templates/forum/show.html.slime
Normal file
58
lib/philomena_web/templates/forum/show.html.slime
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
h1 = @forum.name
|
||||||
|
.block
|
||||||
|
.block__header
|
||||||
|
=> link("Forums", to: Routes.forum_path(@conn, :index))
|
||||||
|
' »
|
||||||
|
=> 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'
|
36
lib/philomena_web/templates/post/_post.html.slime
Normal file
36
lib/philomena_web/templates/post/_post.html.slime
Normal 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'
|
31
lib/philomena_web/templates/post/_post_options.html.slime
Normal file
31
lib/philomena_web/templates/post/_post_options.html.slime
Normal 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
|
95
lib/philomena_web/templates/topic/show.html.slime
Normal file
95
lib/philomena_web/templates/topic/show.html.slime
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
h1 = @topic.title
|
||||||
|
/ Header section
|
||||||
|
.block
|
||||||
|
.block__header
|
||||||
|
=> link("Forums", to: Routes.forum_path(@conn, :index))
|
||||||
|
' »
|
||||||
|
=> link(@forum.name, to: Routes.forum_path(@conn, :show, @forum))
|
||||||
|
' »
|
||||||
|
=> 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
|
3
lib/philomena_web/views/forum_view.ex
Normal file
3
lib/philomena_web/views/forum_view.ex
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
defmodule PhilomenaWeb.ForumView do
|
||||||
|
use PhilomenaWeb, :view
|
||||||
|
end
|
3
lib/philomena_web/views/post_view.ex
Normal file
3
lib/philomena_web/views/post_view.ex
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
defmodule PhilomenaWeb.PostView do
|
||||||
|
use PhilomenaWeb, :view
|
||||||
|
end
|
3
lib/philomena_web/views/topic_view.ex
Normal file
3
lib/philomena_web/views/topic_view.ex
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
defmodule PhilomenaWeb.TopicView do
|
||||||
|
use PhilomenaWeb, :view
|
||||||
|
end
|
Loading…
Reference in a new issue