require "loofah"
class HtmlSanitizer
ALLOWED_TAGS = %w[p br a strong em ul ol li blockquote code pre h2 h3].freeze
ALLOWED_ATTRS = %w[href title].freeze
SAFE_SCHEMES = %w[http https mailto].freeze
class CreateMaintenanceTasks < ActiveRecord::Migration[7.0]
def change
create_table :maintenance_tasks do |t|
t.string :name, null: false
t.string :state, null: false, default: "pending"
t.datetime :started_at
class CreateUsers < ActiveRecord::Migration[7.1]
def change
create_table :users do |t|
t.string :name, null: false
# Ciphertext is larger than plaintext, so use text columns.
class Contract
INVALID = Object.new.freeze
COERCERS = {
string: ->(v) { v.is_a?(String) ? v : v.to_s },
integer: ->(v) { Integer(v.to_s) rescue INVALID },
module DangerousAction
extend ActiveSupport::Concern
FRESH_WINDOW = 10.minutes
class ConfirmationMismatch < StandardError; end
class Reminder < ApplicationRecord
belongs_to :user
validates :time_zone, inclusion: { in: ActiveSupport::TimeZone::MAPPING.values }
validates :local_time, presence: true
module RequestStore
def self.store
Thread.current[:request_store] ||= {}
end
def self.fetch(key)
class NotifyFollowersJob
include Sidekiq::Job
sidekiq_options queue: :notifications, retry: 5
def perform(post_id, actor_id)
class CircuitBreaker
class CircuitOpenError < StandardError; end
INCREMENT = <<~LUA.freeze
local n = redis.call('INCR', KEYS[1])
if n == 1 then redis.call('EXPIRE', KEYS[1], ARGV[1]) end
class CreateCustomerRevenueSummaries < ActiveRecord::Migration[7.0]
def change
create_view :customer_revenue_summaries, materialized: true, version: 1
add_index :customer_revenue_summaries,
:customer_id,
class Order < ApplicationRecord
belongs_to :customer
scope :for_export, -> {
select(:id, :reference, :total_cents, :currency, :created_at, :customer_id)
.where.not(exported_at: nil)
class Comment < ApplicationRecord
belongs_to :post, touch: true
belongs_to :author, class_name: "User"
validates :body, presence: true, length: { maximum: 10_000 }