toc_generator = TOCGenerator.new(@instance_presenter.site_extended_description)
+ @rules = Rule.ordered
@contents = toc_generator.html
@table_of_contents = toc_generator.toc
@blocks = DomainBlock.with_user_facing_limitations.by_severity if display_blocks?
--- /dev/null
+# frozen_string_literal: true
+
+module Admin
+ class RulesController < BaseController
+ before_action :set_rule, except: [:index, :create]
+
+ def index
+ authorize :rule, :index?
+
+ @rules = Rule.ordered
+ @rule = Rule.new
+ end
+
+ def create
+ authorize :rule, :create?
+
+ @rule = Rule.new(resource_params)
+
+ if @rule.save
+ redirect_to admin_rules_path
+ else
+ @rules = Rule.ordered
+ render :index
+ end
+ end
+
+ def edit
+ authorize @rule, :update?
+ end
+
+ def update
+ authorize @rule, :update?
+
+ if @rule.update(resource_params)
+ redirect_to admin_rules_path
+ else
+ render :edit
+ end
+ end
+
+ def destroy
+ authorize @rule, :destroy?
+
+ @rule.discard
+
+ redirect_to admin_rules_path
+ end
+
+ private
+
+ def set_rule
+ @rule = Rule.find(params[:id])
+ end
+
+ def resource_params
+ params.require(:rule).permit(:text, :priority)
+ end
+ end
+end
--- /dev/null
+# frozen_string_literal: true
+
+class Api::V1::Instances::RulesController < Api::BaseController
+ skip_before_action :require_authenticated_user!, unless: :whitelist_mode?
+
+ before_action :set_rules
+
+ def index
+ render json: @rules, each_serializer: REST::RuleSerializer
+ end
+
+ private
+
+ def set_rules
+ @rules = Rule.ordered
+ end
+end
}
}
+.rules-list {
+ background: darken($ui-base-color, 2%);
+ border: 1px solid darken($ui-base-color, 8%);
+ border-radius: 4px;
+ padding: 0.5em 2.5em !important;
+ margin-top: 1.85em !important;
+
+ li {
+ border-bottom: 1px solid lighten($ui-base-color, 4%);
+ color: $dark-text-color;
+ padding: 1em;
+
+ &:last-child {
+ border-bottom: 0;
+ }
+ }
+
+ &__text {
+ color: $primary-text-color;
+ }
+}
--- /dev/null
+# frozen_string_literal: true
+
+# == Schema Information
+#
+# Table name: rules
+#
+# id :bigint(8) not null, primary key
+# priority :integer default(0), not null
+# deleted_at :datetime
+# text :text default(""), not null
+# created_at :datetime not null
+# updated_at :datetime not null
+#
+class Rule < ApplicationRecord
+ include Discard::Model
+
+ self.discard_column = :deleted_at
+
+ validates :text, presence: true, length: { maximum: 300 }
+
+ scope :ordered, -> { kept.order(priority: :asc) }
+end
--- /dev/null
+# frozen_string_literal: true
+
+class RulePolicy < ApplicationPolicy
+ def index?
+ staff?
+ end
+
+ def create?
+ admin?
+ end
+
+ def update?
+ admin?
+ end
+
+ def destroy?
+ admin?
+ end
+end
Account.find_local(Setting.site_contact_username.strip.gsub(/\A@/, ''))
end
+ def rules
+ Rule.ordered
+ end
+
def user_count
Rails.cache.fetch('user_count') { User.confirmed.joins(:account).merge(Account.without_suspended).count }
end
has_one :contact_account, serializer: REST::AccountSerializer
- delegate :contact_account, to: :instance_presenter
+ has_many :rules, serializer: REST::RuleSerializer
+
+ delegate :contact_account, :rules, to: :instance_presenter
def uri
Rails.configuration.x.local_domain
--- /dev/null
+# frozen_string_literal: true
+
+class REST::RuleSerializer < ActiveModel::Serializer
+ attributes :id, :text
+
+ def id
+ object.id.to_s
+ end
+end
- else
.box-widget
.rich-formatting
+ - unless @rules.empty?
+ %h2#rules= t('about.rules')
+
+ %p= t('about.rules_html')
+
+ %ol.rules-list
+ - @rules.each do |rule|
+ %li
+ .rules-list__text= rule.text
+
= @contents.html_safe
- if display_blocks? && !@blocks.empty?
.column-4
%ul.table-of-contents
+ - unless @rules.empty?
+ %li= link_to t('about.rules'), '#rules'
+
- @table_of_contents.each do |item|
%li
= link_to item.title, "##{item.anchor}"
--- /dev/null
+.announcements-list__item
+ = link_to edit_admin_rule_path(rule), class: 'announcements-list__item__title' do
+ = "#{rule_counter + 1}."
+ = truncate(rule.text)
+
+ .announcements-list__item__action-bar
+ .announcements-list__item__meta
+ = rule.text
+
+ %div
+ = table_link_to 'trash', t('admin.rules.delete'), admin_rule_path(rule), method: :delete, data: { confirm: t('admin.accounts.are_you_sure') } if can?(:destroy, rule)
--- /dev/null
+- content_for :page_title do
+ = t('admin.rules.edit')
+
+= simple_form_for @rule, url: admin_rule_path(@rule) do |f|
+ = render 'shared/error_messages', object: @rule
+
+ .fields-group
+ = f.input :text, wrapper: :with_block_label
+
+ .actions
+ = f.button :button, t('generic.save_changes'), type: :submit
--- /dev/null
+- content_for :page_title do
+ = t('admin.rules.title')
+
+.simple_form
+ %p.hint= t('admin.rules.description')
+
+- if can? :create, :rule
+ = simple_form_for @rule, url: admin_rules_path do |f|
+ = render 'shared/error_messages', object: @rule
+
+ .fields-group
+ = f.input :text, wrapper: :with_block_label
+
+ .actions
+ = f.button :button, t('admin.rules.add_new'), type: :submit
+
+ %hr.spacer/
+
+- if @rules.empty?
+ %div.muted-hint.center-text
+ = t 'admin.rules.empty'
+- else
+ .announcements-list
+ = render partial: 'rule', collection: @rules
It is used for federation purposes and should not be blocked unless you want to block the whole instance, in which case you should use a domain block.
learn_more: Learn more
privacy_policy: Privacy policy
+ rules: Server rules
+ rules_html: 'Below is a summary of rules you need to follow if you want to have an account on this server of Mastodon:'
see_whats_happening: See what's happening
server_stats: 'Server stats:'
source_code: Source code
unassign: Unassign
unresolved: Unresolved
updated_at: Updated
+ rules:
+ add_new: Add rule
+ description: While most claim to have read and agree to the terms of service, usually people do not read through until after a problem arises. Make it easier to see your server's rules at a glance by providing them in a flat bullet point list. Try to keep individual rules short and simple, but try not to split them up into many separate items either.
+ edit: Edit rule
+ title: Server rules
settings:
activity_api_enabled:
desc_html: Counts of locally posted statuses, active users, and new registrations in weekly buckets
no_access: Block access to all resources
sign_up_requires_approval: New sign-ups will require your approval
severity: Choose what will happen with requests from this IP
+ rule:
+ text: Describe a rule or requirement for users on this server. Try to keep it short and simple
sessions:
otp: 'Enter the two-factor code generated by your phone app or use one of your recovery codes:'
webauthn: If it's an USB key be sure to insert it and, if necessary, tap it.
reblog: Someone boosted your status
report: New report is submitted
trending_tag: An unreviewed hashtag is trending
+ rule:
+ text: Rule
tag:
listable: Allow this hashtag to appear in searches and on the profile directory
name: Hashtag
n.item :admin, safe_join([fa_icon('cogs fw'), t('admin.title')]), admin_dashboard_url, if: proc { current_user.staff? } do |s|
s.item :dashboard, safe_join([fa_icon('tachometer fw'), t('admin.dashboard.title')]), admin_dashboard_url
s.item :settings, safe_join([fa_icon('cogs fw'), t('admin.settings.title')]), edit_admin_settings_url, if: -> { current_user.admin? }, highlights_on: %r{/admin/settings}
+ s.item :rules, safe_join([fa_icon('gavel fw'), t('admin.rules.title')]), admin_rules_path, highlights_on: %r{/admin/rules}
s.item :announcements, safe_join([fa_icon('bullhorn fw'), t('admin.announcements.title')]), admin_announcements_path, highlights_on: %r{/admin/announcements}
s.item :custom_emojis, safe_join([fa_icon('smile-o fw'), t('admin.custom_emojis.title')]), admin_custom_emojis_url, highlights_on: %r{/admin/custom_emojis}
s.item :relays, safe_join([fa_icon('exchange fw'), t('admin.relays.title')]), admin_relays_url, if: -> { current_user.admin? && !whitelist_mode? }, highlights_on: %r{/admin/relays}
end
resources :instances, only: [:index, :show], constraints: { id: /[^\/]+/ }
+ resources :rules
resources :reports, only: [:index, :show] do
member do
resource :instance, only: [:show] do
resources :peers, only: [:index], controller: 'instances/peers'
resource :activity, only: [:show], controller: 'instances/activity'
+ resources :rules, only: [:index], controller: 'instances/rules'
end
resource :domain_blocks, only: [:show, :create, :destroy]
--- /dev/null
+class CreateRules < ActiveRecord::Migration[5.2]
+ def change
+ create_table :rules do |t|
+ t.integer :priority, null: false, default: 0
+ t.datetime :deleted_at
+ t.text :text, null: false, default: ''
+
+ t.timestamps
+ end
+ end
+end
#
# It's strongly recommended that you check this file into your version control system.
-ActiveRecord::Schema.define(version: 2020_12_18_054746) do
+ActiveRecord::Schema.define(version: 2021_02_21_045109) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
t.index ["target_account_id"], name: "index_reports_on_target_account_id"
end
+ create_table "rules", force: :cascade do |t|
+ t.integer "priority", default: 0, null: false
+ t.datetime "deleted_at"
+ t.text "text", default: "", null: false
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
+ end
+
create_table "scheduled_statuses", force: :cascade do |t|
t.bigint "account_id"
t.datetime "scheduled_at"
--- /dev/null
+Fabricator(:rule) do
+ priority ""
+ deleted_at "2021-02-21 05:51:09"
+ text "MyText"
+end
\ No newline at end of file
--- /dev/null
+require 'rails_helper'
+
+RSpec.describe Rule, type: :model do
+ pending "add some examples to (or delete) #{__FILE__}"
+end