Merge remote-tracking branch 'origin/staff-tools'

This commit is contained in:
byte[] 2019-12-06 17:57:26 -05:00
commit 2a9cbb0ff0
23 changed files with 1429 additions and 752 deletions

View file

@ -24,13 +24,32 @@ module.exports = {
sass: { sass: {
mode: 'native', mode: 'native',
options: { options: {
includePaths: ['css', 'node_modules/font-awesome/scss'] includePaths: ['css', 'node_modules/@fortawesome/fontawesome-free/scss']
} }
}, },
copycat: { copycat: {
fonts: ['node_modules/font-awesome/fonts'], fonts: ['node_modules/@fortawesome/fontawesome-free/webfonts'],
verbose: false, verbose: false,
onlyChanged: true onlyChanged: true
},
postcss: {
processors: [
require('autoprefixer')({
overrideBrowserslist: [
'last 2 Android versions',
'last 2 Chrome versions',
'last 2 ChromeAndroid versions',
'last 2 Edge versions',
'last 1 Explorer version',
'last 1 ExplorerMobile versions',
'last 2 Firefox versions',
'last 2 FirefoxAndroid versions',
'last 2 iOS versions',
'last 2 Opera versions'
],
add: true
})
]
} }
}, },
conventions: { conventions: {

View file

@ -11,8 +11,14 @@
@import "global"; @import "global";
@import "../../node_modules/font-awesome/scss/font-awesome.scss"; // Because FA is a SPECIAL SNOWFLAKE.
@import "../../node_modules/normalize-scss/sass/_normalize.scss"; $fa-font-path: "/fonts";
@import "../../node_modules/@fortawesome/fontawesome-free/scss/fontawesome.scss";
@import "../../node_modules/@fortawesome/fontawesome-free/scss/solid.scss";
@import "../../node_modules/@fortawesome/fontawesome-free/scss/regular.scss";
@import "../../node_modules/@fortawesome/fontawesome-free/scss/brands.scss";
@import "../../node_modules/normalize-scss/sass/normalize/import-now";
body { body {
background-color: $background_color; background-color: $background_color;

1873
assets/package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -6,14 +6,15 @@
"dependencies": { "dependencies": {
"brunch": "^2.10.17", "brunch": "^2.10.17",
"copycat-brunch": "^1.1.1", "copycat-brunch": "^1.1.1",
"font-awesome": "^4.7.0" "@fortawesome/fontawesome-free": "^5.11.2"
}, },
"devDependencies": { "devDependencies": {
"acorn": "^7.0.0", "acorn": "^7.1.0",
"autoprefixer": "^9.5.1", "autoprefixer": "^9.7.3",
"normalize-scss": "^7.0.1", "normalize-scss": "^7.0.1",
"rollup-brunch": "git+https://github.com/liamwhite/rollup-brunch#31967fc", "rollup-brunch": "git+https://github.com/liamwhite/rollup-brunch.git#31967fc",
"sass-brunch": "git+https://github.com/brunch/sass-brunch#e9c0bfe", "sass-brunch": "git+https://github.com/brunch/sass-brunch.git#e9c0bfe",
"spostcss-brunch": "git+https://github.com/Meow/spostcss-brunch.git#b64df45",
"uglify-js-brunch": "^2.10.0" "uglify-js-brunch": "^2.10.0"
} }
} }

View file

@ -101,4 +101,14 @@ defmodule Philomena.DnpEntries do
def change_dnp_entry(%DnpEntry{} = dnp_entry) do def change_dnp_entry(%DnpEntry{} = dnp_entry) do
DnpEntry.changeset(dnp_entry, %{}) DnpEntry.changeset(dnp_entry, %{})
end end
def count_dnp_entries(user) do
if Canada.Can.can?(user, :manage, DnpEntry) do
DnpEntry
|> where([dnp], dnp.aasm_state in ["requested", "claimed", "acknowledged"])
|> Repo.aggregate(:count, :id)
else
nil
end
end
end end

View file

@ -114,4 +114,14 @@ defmodule Philomena.DuplicateReports do
def change_duplicate_report(%DuplicateReport{} = duplicate_report) do def change_duplicate_report(%DuplicateReport{} = duplicate_report) do
DuplicateReport.changeset(duplicate_report, %{}) DuplicateReport.changeset(duplicate_report, %{})
end end
def count_duplicate_reports(user) do
if Canada.Can.can?(user, :manage, DuplicateReport) do
DuplicateReport
|> where(state: "open")
|> Repo.aggregate(:count, :id)
else
nil
end
end
end end

View file

@ -116,4 +116,14 @@ defmodule Philomena.Reports do
report report
end end
def count_reports(user) do
if Canada.Can.can?(user, :manage, Report) do
Report
|> where(open: true)
|> Repo.aggregate(:count, :id)
else
nil
end
end
end end

View file

@ -104,4 +104,14 @@ defmodule Philomena.UserLinks do
def change_user_link(%UserLink{} = user_link) do def change_user_link(%UserLink{} = user_link) do
UserLink.changeset(user_link, %{}) UserLink.changeset(user_link, %{})
end end
def count_user_links(user) do
if Canada.Can.can?(user, :edit, UserLink) do
UserLink
|> where(aasm_state: "unverified")
|> Repo.aggregate(:count, :id)
else
nil
end
end
end end

View file

@ -0,0 +1,48 @@
defmodule PhilomenaWeb.AdminCountersPlug do
@moduledoc """
This plug stores the counts used by the admin bar.
## Example
plug PhilomenaWeb.AdminCountersPlug
"""
alias Plug.Conn
alias Philomena.DuplicateReports
alias Philomena.Reports
alias Philomena.UserLinks
alias Philomena.DnpEntries
import Plug.Conn, only: [assign: 3]
@doc false
@spec init(any()) :: any()
def init(opts), do: opts
@doc false
@spec call(Plug.Conn.t()) :: Plug.Conn.t()
def call(conn), do: call(conn, nil)
@doc false
@spec call(Plug.Conn.t(), any()) :: Plug.Conn.t()
def call(conn, _opts) do
user = conn.assigns.current_user
maybe_assign_admin_metrics(conn, user, staff?(user))
end
defp maybe_assign_admin_metrics(conn, _user, false), do: conn
defp maybe_assign_admin_metrics(conn, user, true) do
duplicate_reports = DuplicateReports.count_duplicate_reports(user)
reports = Reports.count_reports(user)
user_links = UserLinks.count_user_links(user)
dnps = DnpEntries.count_dnp_entries(user)
conn
|> assign(:duplicate_report_count, duplicate_reports)
|> assign(:report_count, reports)
|> assign(:user_link_count, user_links)
|> assign(:dnp_entry_count, dnps)
end
defp staff?(%{role: role}) when role in ["assistant", "moderator", "admin"], do: true
defp staff?(_user), do: false
end

View file

@ -20,6 +20,7 @@ defmodule PhilomenaWeb.Router do
plug PhilomenaWeb.ForumListPlug plug PhilomenaWeb.ForumListPlug
plug PhilomenaWeb.FilterSelectPlug plug PhilomenaWeb.FilterSelectPlug
plug PhilomenaWeb.ChannelPlug plug PhilomenaWeb.ChannelPlug
plug PhilomenaWeb.AdminCountersPlug
end end
pipeline :api do pipeline :api do

View file

@ -2,14 +2,10 @@ article.block.communication id="comment_#{@comment.id}"
.block__content.flex.flex--no-wrap .block__content.flex.flex--no-wrap
.flex__fixed.spacing-right .flex__fixed.spacing-right
= render PhilomenaWeb.UserAttributionView, "_anon_user_avatar.html", object: @comment, conn: @conn = render PhilomenaWeb.UserAttributionView, "_anon_user_avatar.html", object: @comment, conn: @conn
.flex__grow.communication__body .flex__grow.communication__body
span.communication__body__sender-name = render PhilomenaWeb.UserAttributionView, "_anon_user.html", object: @comment, awards: true, conn: @conn span.communication__body__sender-name = render PhilomenaWeb.UserAttributionView, "_anon_user.html", object: @comment, awards: true, conn: @conn
br br
= render PhilomenaWeb.UserAttributionView, "_anon_user_title.html", object: @comment, conn: @conn = render PhilomenaWeb.UserAttributionView, "_anon_user_title.html", object: @comment, conn: @conn
.communication__body__text .communication__body__text
= if @comment.hidden_from_users do = if @comment.hidden_from_users do
strong.comment_deleted strong.comment_deleted
@ -17,10 +13,20 @@ article.block.communication id="comment_#{@comment.id}"
=> @comment.deletion_reason => @comment.deletion_reason
- else - else
==<> @body ==<> @body
.block__content.communication__options .block__content.communication__options
.flex.flex--wrap.flex--spaced-out .flex.flex--wrap.flex--spaced-out
= render PhilomenaWeb.CommentView, "_comment_options.html", comment: @comment, conn: @conn = render PhilomenaWeb.CommentView, "_comment_options.html", comment: @comment, conn: @conn
= if can?(@conn, :hide, @comment) do
.js-staff-action
/ todo: make delete button work
a.communication__interaction.togglable-delete-form-link href="#"
i.fa.fa-times
=<> "Delete"
= if can?(@conn, :manage, @comment) do
.communication__info
=<> link_to_ip(@comment.ip)
.communication__info
=<> link_to_fingerprint(@comment.fingerprint)
/- if can?(:hide, Comment) /- if can?(:hide, Comment)
/ .js-staff-action / .js-staff-action
/ - if !comment.hidden_from_users && !comment.destroyed_content / - if !comment.hidden_from_users && !comment.destroyed_content

View file

@ -2,11 +2,11 @@ div
p p
= if can?(@conn, :edit_description, @image) do = if can?(@conn, :edit_description, @image) do
a.button#edit-description href="#" data-click-focus="#description" data-click-hide=".image-description" data-click-show="#description-form" title="Edit description" accessKey="d" a.button#edit-description href="#" data-click-focus="#description" data-click-hide=".image-description" data-click-show="#description-form" title="Edit description" accessKey="d"
i.fa.fa-pencil> i.fas.fa-edit>
' Description: ' Description:
- else - else
' Description: ' Description:
.image-description__text .image-description__text
== @body == @body

View file

@ -51,8 +51,14 @@
div div
' Uploaded ' Uploaded
=> pretty_time(@image.created_at) => pretty_time(@image.created_at)
' by span.image_uploader
=> render PhilomenaWeb.UserAttributionView, "_anon_user.html", object: @image, awards: true, conn: @conn ' by
=> render PhilomenaWeb.UserAttributionView, "_anon_user.html", object: @image, awards: true, conn: @conn
= if can?(@conn, :manage, @image) do
=<> link_to_ip(@image.ip)
=<> link_to_fingerprint(@image.fingerprint)
a href="#"
i.fa.fa-edit
span.image-size span.image-size
| &nbsp; | &nbsp;
= @image.image_width = @image.image_width

View file

@ -23,7 +23,7 @@
.flex.flex--wrap#image-source .flex.flex--wrap#image-source
p p
a.button.button--separate-right#edit-source data-click-focus="#source-field" data-click-hide="#image-source" data-click-show="#source-form" title="Edit source" accessKey="s" a.button.button--separate-right#edit-source data-click-focus="#source-field" data-click-hide="#image-source" data-click-show="#source-form" title="Edit source" accessKey="s"
i.fa.fa-pencil> i.fas.fa-edit>
' Source: ' Source:
p p
@ -37,4 +37,4 @@
a.button.button--link.button--separate-left href=Routes.image_source_change_path(@conn, :index, @image) title="Source history" a.button.button--link.button--separate-left href=Routes.image_source_change_path(@conn, :index, @image) title="Source history"
i.fa.fa-history> i.fa.fa-history>
' History ' History

View file

@ -52,11 +52,11 @@
.tagsauce .tagsauce
.block .block
a.button.js-tag-sauce-toggle#edit-tags data-click-toggle=".tagsauce, .js-imageform" data-click-focus=".js-taginput-plain:not(.hidden), .js-taginput-input" title="Edit tags" accessKey="t" a.button.js-tag-sauce-toggle#edit-tags data-click-toggle=".tagsauce, .js-imageform" data-click-focus=".js-taginput-plain:not(.hidden), .js-taginput-input" title="Edit tags" accessKey="t"
i.fa.fa-pencil> i.fas.fa-edit>
' Tags: ' Tags:
a.button.button--link.button--separate-left href=Routes.image_tag_change_path(@conn, :index, @image) title="Tag history" a.button.button--link.button--separate-left href=Routes.image_tag_change_path(@conn, :index, @image) title="Tag history"
i.fa.fa-history> i.fa.fa-history>
' History ' History
= render PhilomenaWeb.TagView, "_tag_list.html", tags: display_order(@image.tags), conn: @conn = render PhilomenaWeb.TagView, "_tag_list.html", tags: display_order(@image.tags), conn: @conn

View file

@ -6,7 +6,7 @@
.block .block
.block__header.block__header--js-tabbed .block__header.block__header--js-tabbed
a.selected href="#" data-click-tab="write" a.selected href="#" data-click-tab="write"
i.fa.fa-pencil> i.fas.fa-edit>
' Edit ' Edit
a href="#" data-click-tab="preview" a href="#" data-click-tab="preview"
@ -29,4 +29,4 @@
= if @conn.assigns.current_user do = if @conn.assigns.current_user do
= checkbox f, :anonymous, value: anonymous_by_default?(@conn) = checkbox f, :anonymous, value: anonymous_by_default?(@conn)
= label f, :anonymous, "Anonymous" = label f, :anonymous, "Anonymous"

View file

@ -10,6 +10,7 @@ elixir:
=> pluralize("comment", "comments", @image.comments_count) => pluralize("comment", "comments", @image.comments_count)
' posted ' posted
button.button#js-refresh-comments title="Refresh" data-disable-with="..." button.button#js-refresh-comments title="Refresh" data-disable-with="..."
i.fa.fa-sync
span.hide-mobile<> Refresh span.hide-mobile<> Refresh
= for {comment, body} <- @comments do = for {comment, body} <- @comments do
@ -17,4 +18,4 @@ elixir:
.block .block
.block__header.block__header--light .block__header.block__header--light
= pagination = pagination

View file

@ -73,7 +73,7 @@ header.header
i.fa.fa-fw.fa-comments> i.fa.fa-fw.fa-comments>
| Comments | Comments
a.header__link href="/posts?pq=my:posts" a.header__link href="/posts?pq=my:posts"
i.fa.fa-fw.fa-pencil> i.fas.fa-fw.fa-pen-square>
| Posts | Posts
a.header__link href='/user_links' a.header__link href='/user_links'
i.fa.fa-fw.fa-link> i.fa.fa-fw.fa-link>
@ -88,7 +88,7 @@ header.header
i.fa.fa-fw.fa-user> i.fa.fa-fw.fa-user>
| Account | Account
a.header__link href="/session" data-method='delete' a.header__link href="/session" data-method='delete'
i.fa.fa-fw.fa-sign-out> i.fa.fa-fw.fa-sign-out-alt>
| Logout | Logout
- else - else
a.header__link.hide-mobile href="/filters" a.header__link.hide-mobile href="/filters"
@ -107,5 +107,5 @@ header.header
nav.header.header--secondary nav.header.header--secondary
.flex.flex--centered.flex--spaced-out.flex--wrap .flex.flex--centered.flex--spaced-out.flex--wrap
= render PhilomenaWeb.LayoutView, "_header_navigation.html", assigns = render PhilomenaWeb.LayoutView, "_header_navigation.html", assigns
/- if current_user.try(:staff?) = if @current_user.role != "user" do
include _header_staff_links.html = render PhilomenaWeb.LayoutView, "_header_staff_links.html", assigns

View file

@ -0,0 +1,85 @@
/ Dummy view for the admin bar
.flex.flex--centered.header--secondary__admin-links.stretched-mobile-links.js-staff-action
.dropdown.hide-mobile
/a.header__link title="Admin"
' A
i.fa.fa-caret-down
.dropdown__content.js-burger-links
/ todo: make some sort of permission for this
= if @current_user.role == "admin" do
= link to: "/admin/flipper", class: "header__link" do
i.fa.fa-fw.fa-toggle-on>
' Site Settings
= if can?(@conn, :manage, SiteNotice) do
= link to: "/admin/site_notices", class: "header__link" do
i.fa.fa-fw.fa-info-circle>
' Site Notices
= if can?(@conn, :manage, Tag) do
= link to: "#", class: "header__link" do
i.fa.fa-fw.fa-tags>
' Tags
= if can?(@conn, :mod_read, User) do
= link to: "#", class: "header__link" do
i.fa.fa-fw.fa-users>
' Users
= if can?(@conn, :mod_read, Comment) do
= link to: "#", class: "header__link" do
i.fa.fa-fw.fa-comments>
' Comments
= if can?(@conn, :mod_read, Forum) do
= link to: "#", class: "header__link" do
i.fa.fa-fw.fa-paragraph>
' Forums
= if can?(@conn, :manage, Advert) do
= link to: "#", class: "header__link" do
i.fa.fa-fw.fa-shopping-bag>
' Advertisements
= if can?(@conn, :award, Badge) do
= link to: "#", class: "header__link" do
i.fa.fa-fw.fa-trophy>
' Badges
= if can?(@conn, :manage, StaticPage) do
= link to: "#", class: "header__link" do
i.fa.fa-fw.fa-sticky-note>
' Pages
= if can?(@conn, :manage, ModNote) do
= link to: "#", class: "header__link" do
i.fa.fa-fw.fa-sticky-note>
' Mod Notes
= if @duplicate_report_count do
= link to: "#", class: "header__link", title: "Duplicates" do
' D
span.header__counter__admin
= @duplicate_report_count
= if @report_count do
= link to: "#", class: "header__link", title: "Reports" do
' R
span.header__counter__admin
= @report_count
= if @user_link_count do
= link to: "#", class: "header__link", title: "User Links" do
' L
span.header__counter__admin
= @user_link_count
= if @dnp_entry_count do
= link to: "#", class: "header__link", title: "DNP Requests" do
' S
span.header__counter__admin
= @dnp_entry_count
.dropdown.hide-mobile
a.header__link title="Bans"
' B
i.fa.fa-caret-down
.dropdown__content.dropdown__content-right.js-burger-links
= if can?(@conn, :mod_read, UserBan) do
= link to: "#", class: "header__link" do
i.fa.fa-fw.fa-user>
' User Bans
= if can?(@conn, :mod_read, SubnetBan) do
= link to: "#", class: "header__link" do
i.fab.fa-fw.fa-internet-explorer>
' IP Bans
= if can?(@conn, :mod_read, FingerprintBan) do
= link to: "#", class: "header__link" do
i.fa.fa-fw.fa-desktop>
' FP Bans

View file

@ -2,13 +2,10 @@ article.block.communication id="post_#{@post.id}"
.block__content.flex.flex--no-wrap .block__content.flex.flex--no-wrap
.flex__fixed.spacing-right .flex__fixed.spacing-right
= render PhilomenaWeb.UserAttributionView, "_anon_user_avatar.html", object: @post, conn: @conn = render PhilomenaWeb.UserAttributionView, "_anon_user_avatar.html", object: @post, conn: @conn
.flex__grow.communication__body .flex__grow.communication__body
span.communication__body__sender-name = render PhilomenaWeb.UserAttributionView, "_anon_user.html", object: @post, awards: true, conn: @conn span.communication__body__sender-name = render PhilomenaWeb.UserAttributionView, "_anon_user.html", object: @post, awards: true, conn: @conn
br br
= render PhilomenaWeb.UserAttributionView, "_anon_user_title.html", object: @post, conn: @conn = render PhilomenaWeb.UserAttributionView, "_anon_user_title.html", object: @post, conn: @conn
.communication__body__text .communication__body__text
= if @post.hidden_from_users do = if @post.hidden_from_users do
strong.comment_deleted strong.comment_deleted
@ -16,12 +13,19 @@ article.block.communication id="post_#{@post.id}"
=> @post.deletion_reason => @post.deletion_reason
- else - else
==<> @body ==<> @body
.block__content.communication__options .block__content.communication__options
.flex.flex--wrap.flex--spaced-out .flex.flex--wrap.flex--spaced-out
= render PhilomenaWeb.PostView, "_post_options.html", conn: @conn, post: @post = render PhilomenaWeb.PostView, "_post_options.html", conn: @conn, post: @post
= if can?(@conn, :hide, @post) do
/ todo: make post deletion work
a.communication__interaction.togglable-delete-form-link href="#"
i.fa.fa-times
=<> "Delete"
= if can?(@conn, :manage, @post) do
.communication__info
=<> link_to_ip(@post.ip)
.communication__info
=<> link_to_fingerprint(@post.fingerprint)
/- if can?(:hide, Post) /- if can?(:hide, Post)
/ .js-staff-action / .js-staff-action
/ - if !post.hidden_from_users && !post.destroyed_content / - if !post.hidden_from_users && !post.destroyed_content

View file

@ -6,7 +6,7 @@
.block .block
.block__header.block__header--js-tabbed .block__header.block__header--js-tabbed
a.selected href="#" data-click-tab="write" a.selected href="#" data-click-tab="write"
i.fa.fa-pencil> i.fas.fa-pencil-alt>
' Create a Topic ' Create a Topic
a href="#" data-click-tab="preview" a href="#" data-click-tab="preview"
@ -83,4 +83,4 @@
' [Loading preview...] ' [Loading preview...]
.block__content.communication-edit__actions .block__content.communication-edit__actions
= submit "Post", class: "button" = submit "Post", class: "button"

View file

@ -6,7 +6,7 @@
.block .block
.block__header.block__header--js-tabbed .block__header.block__header--js-tabbed
a.selected href="#" data-click-tab="write" a.selected href="#" data-click-tab="write"
i.fa.fa-pencil> i.fas.fa-edit>
' Edit ' Edit
a href="#" data-click-tab="preview" a href="#" data-click-tab="preview"
@ -29,4 +29,4 @@
= if @conn.assigns.current_user do = if @conn.assigns.current_user do
= checkbox f, :anonymous, value: anonymous_by_default?(@conn) = checkbox f, :anonymous, value: anonymous_by_default?(@conn)
= label f, :anonymous, "Anonymous" = label f, :anonymous, "Anonymous"

View file

@ -113,4 +113,17 @@ defmodule PhilomenaWeb.AppView do
]) ])
|> to_string() |> to_string()
end end
defp text_or_na(text), do: text
defp text_or_na(nil), do: "N/A"
# todo: make ip a real link
def link_to_ip(ip) do
link(text_or_na(ip), to: "#")
end
# todo: make fp a real link
def link_to_fingerprint(fp) do
link(String.slice(text_or_na(fp), 0..6), to: "#")
end
end end