Conflicts: - app/javascript/packs/public.js - app/models/user.rb - config/settings.yml - db/schema.rb Moved public.js changes to settings.js.th-downstream
commit
b62953b3d2
@ -0,0 +1,44 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module Admin
|
||||
class TagsController < BaseController
|
||||
before_action :set_tags, only: :index
|
||||
before_action :set_tag, except: :index
|
||||
before_action :set_filter_params
|
||||
|
||||
def index
|
||||
authorize :tag, :index?
|
||||
end
|
||||
|
||||
def hide
|
||||
authorize @tag, :hide?
|
||||
@tag.account_tag_stat.update!(hidden: true)
|
||||
redirect_to admin_tags_path(@filter_params)
|
||||
end
|
||||
|
||||
def unhide
|
||||
authorize @tag, :unhide?
|
||||
@tag.account_tag_stat.update!(hidden: true)
|
||||
redirect_to admin_tags_path(@filter_params)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def set_tags
|
||||
@tags = Tag.discoverable
|
||||
@tags.merge!(Tag.hidden) if filter_params[:hidden]
|
||||
end
|
||||
|
||||
def set_tag
|
||||
@tag = Tag.find(params[:id])
|
||||
end
|
||||
|
||||
def set_filter_params
|
||||
@filter_params = filter_params.to_hash.symbolize_keys
|
||||
end
|
||||
|
||||
def filter_params
|
||||
params.permit(:hidden)
|
||||
end
|
||||
end
|
||||
end
|
@ -0,0 +1,48 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class DirectoriesController < ApplicationController
|
||||
layout 'public'
|
||||
|
||||
before_action :set_instance_presenter
|
||||
before_action :set_tag, only: :show
|
||||
before_action :set_tags
|
||||
before_action :set_accounts
|
||||
|
||||
def index
|
||||
render :index
|
||||
end
|
||||
|
||||
def show
|
||||
render :index
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def set_tag
|
||||
@tag = Tag.discoverable.find_by!(name: params[:id].downcase)
|
||||
end
|
||||
|
||||
def set_tags
|
||||
@tags = Tag.discoverable.limit(30)
|
||||
end
|
||||
|
||||
def set_accounts
|
||||
@accounts = Account.searchable.discoverable.page(params[:page]).per(50).tap do |query|
|
||||
query.merge!(Account.tagged_with(@tag.id)) if @tag
|
||||
|
||||
if popular_requested?
|
||||
query.merge!(Account.popular)
|
||||
else
|
||||
query.merge!(Account.by_recent_status)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def set_instance_presenter
|
||||
@instance_presenter = InstancePresenter.new
|
||||
end
|
||||
|
||||
def popular_requested?
|
||||
request.path.ends_with?('/popular')
|
||||
end
|
||||
end
|
@ -0,0 +1,24 @@
|
||||
# frozen_string_literal: true
|
||||
# == Schema Information
|
||||
#
|
||||
# Table name: account_tag_stats
|
||||
#
|
||||
# id :bigint(8) not null, primary key
|
||||
# tag_id :bigint(8) not null
|
||||
# accounts_count :bigint(8) default(0), not null
|
||||
# hidden :boolean default(FALSE), not null
|
||||
# created_at :datetime not null
|
||||
# updated_at :datetime not null
|
||||
#
|
||||
|
||||
class AccountTagStat < ApplicationRecord
|
||||
belongs_to :tag, inverse_of: :account_tag_stat
|
||||
|
||||
def increment_count!(key)
|
||||
update(key => public_send(key) + 1)
|
||||
end
|
||||
|
||||
def decrement_count!(key)
|
||||
update(key => [public_send(key) - 1, 0].max)
|
||||
end
|
||||
end
|
@ -0,0 +1,15 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class TagPolicy < ApplicationPolicy
|
||||
def index?
|
||||
staff?
|
||||
end
|
||||
|
||||
def hide?
|
||||
staff?
|
||||
end
|
||||
|
||||
def unhide?
|
||||
staff?
|
||||
end
|
||||
end
|
@ -0,0 +1,12 @@
|
||||
%tr
|
||||
%td
|
||||
= link_to explore_hashtag_path(tag) do
|
||||
= fa_icon 'hashtag'
|
||||
= tag.name
|
||||
%td
|
||||
= t('directories.people', count: tag.accounts_count)
|
||||
%td
|
||||
- if tag.hidden?
|
||||
= table_link_to 'eye', t('admin.tags.unhide'), unhide_admin_tag_path(tag.id, **@filter_params), method: :post
|
||||
- else
|
||||
= table_link_to 'eye-slash', t('admin.tags.hide'), hide_admin_tag_path(tag.id, **@filter_params), method: :post
|
@ -0,0 +1,19 @@
|
||||
- content_for :page_title do
|
||||
= t('admin.tags.title')
|
||||
|
||||
.filters
|
||||
.filter-subset
|
||||
%strong= t('admin.reports.status')
|
||||
%ul
|
||||
%li= filter_link_to t('admin.tags.visible'), hidden: nil
|
||||
%li= filter_link_to t('admin.tags.hidden'), hidden: '1'
|
||||
|
||||
.table-wrapper
|
||||
%table.table
|
||||
%thead
|
||||
%tr
|
||||
%th= t('admin.tags.name')
|
||||
%th= t('admin.tags.accounts')
|
||||
%th
|
||||
%tbody
|
||||
= render @tags
|
@ -0,0 +1,61 @@
|
||||
- content_for :page_title do
|
||||
= t('directories.explore_mastodon', title: site_title)
|
||||
|
||||
- content_for :header_tags do
|
||||
%meta{ name: 'description', content: t('directories.explanation') }
|
||||
|
||||
= opengraph 'og:site_name', t('about.hosted_on', domain: site_hostname)
|
||||
= opengraph 'og:type', 'website'
|
||||
= opengraph 'og:title', t('directories.explore_mastodon', title: site_title)
|
||||
= opengraph 'og:description', t('directories.explanation')
|
||||
= opengraph 'og:image', File.join(root_url, 'android-chrome-192x192.png')
|
||||
|
||||
.page-header
|
||||
%h1= t('directories.explore_mastodon', title: site_title)
|
||||
%p= t('directories.explanation')
|
||||
|
||||
.grid
|
||||
.column-0
|
||||
.account__section-headline
|
||||
= active_link_to t('directories.most_recently_active'), @tag ? explore_hashtag_path(@tag) : explore_path
|
||||
= active_link_to t('directories.most_popular'), @tag ? explore_hashtag_popular_path(@tag) : explore_popular_path
|
||||
|
||||
- if @accounts.empty?
|
||||
= nothing_here
|
||||
- else
|
||||
.directory
|
||||
%table.accounts-table
|
||||
%tbody
|
||||
- @accounts.each do |account|
|
||||
%tr
|
||||
%td= account_link_to account
|
||||
%td.accounts-table__count
|
||||
= number_to_human account.statuses_count, strip_insignificant_zeros: true
|
||||
%small= t('accounts.posts', count: account.statuses_count).downcase
|
||||
%td.accounts-table__count
|
||||
= number_to_human account.followers_count, strip_insignificant_zeros: true
|
||||
%small= t('accounts.followers', count: account.followers_count).downcase
|
||||
%td.accounts-table__count
|
||||
- if account.last_status_at.present?
|
||||
%time.time-ago{ datetime: account.last_status_at.iso8601, title: l(account.last_status_at) }= l account.last_status_at
|
||||
- else
|
||||
\-
|
||||
%small= t('accounts.last_active')
|
||||
|
||||
= paginate @accounts
|
||||
|
||||
.column-1
|
||||
- if @tags.empty?
|
||||
.nothing-here.nothing-here--flexible
|
||||
- else
|
||||
- @tags.each do |tag|
|
||||
.directory__tag{ class: tag.id == @tag&.id ? 'active' : nil }
|
||||
= link_to explore_hashtag_path(tag) do
|
||||
%h4
|
||||
= fa_icon 'hashtag'
|
||||
= tag.name
|
||||
%small= t('directories.people', count: tag.accounts_count)
|
||||
|
||||
.avatar-stack
|
||||
- tag.cached_sample_accounts.each do |account|
|
||||
= image_tag current_account&.user&.setting_auto_play_gif ? account.avatar_original_url : account.avatar_static_url, width: 48, height: 48, alt: '', class: 'account__avatar'
|
@ -0,0 +1,8 @@
|
||||
class CreateAccountsTagsJoinTable < ActiveRecord::Migration[5.2]
|
||||
def change
|
||||
create_join_table :accounts, :tags do |t|
|
||||
t.index [:account_id, :tag_id]
|
||||
t.index [:tag_id, :account_id], unique: true
|
||||
end
|
||||
end
|
||||
end
|
@ -0,0 +1,5 @@
|
||||
class AddDiscoverableToAccounts < ActiveRecord::Migration[5.2]
|
||||
def change
|
||||
add_column :accounts, :discoverable, :boolean
|
||||
end
|
||||
end
|
@ -0,0 +1,5 @@
|
||||
class AddLastStatusAtToAccountStats < ActiveRecord::Migration[5.2]
|
||||
def change
|
||||
add_column :account_stats, :last_status_at, :datetime
|
||||
end
|
||||
end
|
@ -0,0 +1,11 @@
|
||||
class CreateAccountTagStats < ActiveRecord::Migration[5.2]
|
||||
def change
|
||||
create_table :account_tag_stats do |t|
|
||||
t.belongs_to :tag, null: false, foreign_key: { on_delete: :cascade }, index: { unique: true }
|
||||
t.bigint :accounts_count, default: 0, null: false
|
||||
t.boolean :hidden, default: false, null: false
|
||||
|
||||
t.timestamps
|
||||
end
|
||||
end
|
||||
end
|
@ -1,7 +1,29 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe ActivityPub::InboxesController, type: :controller do
|
||||
describe 'POST #create' do
|
||||
pending
|
||||
context 'if signed_request_account' do
|
||||
it 'returns 202' do
|
||||
allow(controller).to receive(:signed_request_account) do
|
||||
Fabricate(:account)
|
||||
end
|
||||
|
||||
post :create
|
||||
expect(response).to have_http_status(202)
|
||||
end
|
||||
end
|
||||
|
||||
context 'not signed_request_account' do
|
||||
it 'returns 401' do
|
||||
allow(controller).to receive(:signed_request_account) do
|
||||
false
|
||||
end
|
||||
|
||||
post :create
|
||||
expect(response).to have_http_status(401)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -0,0 +1,3 @@
|
||||
Fabricator(:account_tag_stat) do
|
||||
accounts_count ""
|
||||
end
|
@ -1,15 +1,55 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
# Specs in this file have access to a helper object that includes
|
||||
# the Admin::AccountModerationNotesHelper. For example:
|
||||
#
|
||||
# describe Admin::AccountModerationNotesHelper do
|
||||
# describe "string concat" do
|
||||
# it "concats two strings with spaces" do
|
||||
# expect(helper.concat_strings("this","that")).to eq("this that")
|
||||
# end
|
||||
# end
|
||||
# end
|
||||
RSpec.describe Admin::AccountModerationNotesHelper, type: :helper do
|
||||
pending "add some examples to (or delete) #{__FILE__}"
|
||||
include StreamEntriesHelper
|
||||
|
||||
describe '#admin_account_link_to' do
|
||||
context 'account is nil' do
|
||||
let(:account) { nil }
|
||||
|
||||
it 'returns nil' do
|
||||
expect(helper.admin_account_link_to(account)).to be_nil
|
||||
end
|
||||
end
|
||||
|
||||
context 'with account' do
|
||||
let(:account) { Fabricate(:account) }
|
||||
|
||||
it 'calls #link_to' do
|
||||
expect(helper).to receive(:link_to).with(
|
||||
admin_account_path(account.id),
|
||||
class: name_tag_classes(account),
|
||||
title: account.acct
|
||||
)
|
||||
|
||||
helper.admin_account_link_to(account)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#admin_account_inline_link_to' do
|
||||
context 'account is nil' do
|
||||
let(:account) { nil }
|
||||
|
||||
it 'returns nil' do
|
||||
expect(helper.admin_account_inline_link_to(account)).to be_nil
|
||||
end
|
||||
end
|
||||
|
||||
context 'with account' do
|
||||
let(:account) { Fabricate(:account) }
|
||||
|
||||
it 'calls #link_to' do
|
||||
expect(helper).to receive(:link_to).with(
|
||||
admin_account_path(account.id),
|
||||
class: name_tag_classes(account, true),
|
||||
title: account.acct
|
||||
)
|
||||
|
||||
helper.admin_account_inline_link_to(account)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -1,5 +0,0 @@
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe AccountPin, type: :model do
|
||||
pending "add some examples to (or delete) #{__FILE__}"
|
||||
end
|
@ -0,0 +1,38 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe AccountTagStat, type: :model do
|
||||
key = 'accounts_count'
|
||||
let(:account_tag_stat) { Fabricate(:tag).account_tag_stat }
|
||||
|
||||
describe '#increment_count!' do
|
||||
it 'calls #update' do
|
||||
args = { key => account_tag_stat.public_send(key) + 1 }
|
||||
expect(account_tag_stat).to receive(:update).with(args)
|
||||
account_tag_stat.increment_count!(key)
|
||||
end
|
||||
|
||||
it 'increments value by 1' do
|
||||
expect do
|
||||
account_tag_stat.increment_count!(key)
|
||||
end.to change { account_tag_stat.accounts_count }.by(1)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#decrement_count!' do
|
||||
it 'calls #update' do
|
||||
args = { key => [account_tag_stat.public_send(key) - 1, 0].max }
|
||||
expect(account_tag_stat).to receive(:update).with(args)
|
||||
account_tag_stat.decrement_count!(key)
|
||||
end
|
||||
|
||||
it 'decrements value by 1' do
|
||||
account_tag_stat.update(key => 1)
|
||||
|
||||
expect do
|
||||
account_tag_stat.decrement_count!(key)
|
||||
end.to change { account_tag_stat.accounts_count }.by(-1)
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Reference in new issue