mirror of
https://0xacab.org/sutty/sutty
synced 2024-11-16 21:56:21 +00:00
Merge branch 'issue-15109' into production.panel.sutty.nl
This commit is contained in:
commit
3ee6ea2464
41 changed files with 1176 additions and 200 deletions
8
Gemfile
8
Gemfile
|
@ -37,7 +37,9 @@ gem 'commonmarker'
|
|||
gem 'devise'
|
||||
gem 'devise-i18n'
|
||||
gem 'devise_invitable'
|
||||
gem 'distributed-press-api-client', '~> 0.3.0rc0'
|
||||
gem 'redis-client'
|
||||
gem 'hiredis-client'
|
||||
gem 'distributed-press-api-client', '~> 0.4.0rc2'
|
||||
gem 'email_address', git: 'https://github.com/fauno/email_address', branch: 'i18n'
|
||||
gem 'exception_notification'
|
||||
gem 'fast_blank'
|
||||
|
@ -65,6 +67,7 @@ gem 'redis', '~> 4.0', require: %w[redis redis/connection/hiredis]
|
|||
gem 'redis-rails'
|
||||
gem 'rollups', git: 'https://github.com/fauno/rollup.git', branch: 'update'
|
||||
gem 'rubyzip'
|
||||
gem 'ruby-brs'
|
||||
gem 'rugged', '1.5.0.1'
|
||||
gem 'git_clone_url'
|
||||
gem 'concurrent-ruby-ext'
|
||||
|
@ -77,6 +80,9 @@ gem 'yaml_db', git: 'https://0xacab.org/sutty/yaml_db.git'
|
|||
gem 'kaminari'
|
||||
gem 'device_detector'
|
||||
|
||||
gem 'after_commit_everywhere', '~> 1.0'
|
||||
gem 'aasm'
|
||||
|
||||
# database
|
||||
gem 'hairtrigger'
|
||||
gem 'pg'
|
||||
|
|
254
Gemfile.lock
254
Gemfile.lock
|
@ -27,73 +27,80 @@ GIT
|
|||
GEM
|
||||
remote: https://17.3.alpine.gems.sutty.nl/
|
||||
specs:
|
||||
actioncable (6.1.7.3)
|
||||
actionpack (= 6.1.7.3)
|
||||
activesupport (= 6.1.7.3)
|
||||
aasm (5.5.0)
|
||||
concurrent-ruby (~> 1.0)
|
||||
actioncable (6.1.7.4)
|
||||
actionpack (= 6.1.7.4)
|
||||
activesupport (= 6.1.7.4)
|
||||
nio4r (~> 2.0)
|
||||
websocket-driver (>= 0.6.1)
|
||||
actionmailbox (6.1.7.3)
|
||||
actionpack (= 6.1.7.3)
|
||||
activejob (= 6.1.7.3)
|
||||
activerecord (= 6.1.7.3)
|
||||
activestorage (= 6.1.7.3)
|
||||
activesupport (= 6.1.7.3)
|
||||
actionmailbox (6.1.7.4)
|
||||
actionpack (= 6.1.7.4)
|
||||
activejob (= 6.1.7.4)
|
||||
activerecord (= 6.1.7.4)
|
||||
activestorage (= 6.1.7.4)
|
||||
activesupport (= 6.1.7.4)
|
||||
mail (>= 2.7.1)
|
||||
actionmailer (6.1.7.3)
|
||||
actionpack (= 6.1.7.3)
|
||||
actionview (= 6.1.7.3)
|
||||
activejob (= 6.1.7.3)
|
||||
activesupport (= 6.1.7.3)
|
||||
actionmailer (6.1.7.4)
|
||||
actionpack (= 6.1.7.4)
|
||||
actionview (= 6.1.7.4)
|
||||
activejob (= 6.1.7.4)
|
||||
activesupport (= 6.1.7.4)
|
||||
mail (~> 2.5, >= 2.5.4)
|
||||
rails-dom-testing (~> 2.0)
|
||||
actionpack (6.1.7.3)
|
||||
actionview (= 6.1.7.3)
|
||||
activesupport (= 6.1.7.3)
|
||||
actionpack (6.1.7.4)
|
||||
actionview (= 6.1.7.4)
|
||||
activesupport (= 6.1.7.4)
|
||||
rack (~> 2.0, >= 2.0.9)
|
||||
rack-test (>= 0.6.3)
|
||||
rails-dom-testing (~> 2.0)
|
||||
rails-html-sanitizer (~> 1.0, >= 1.2.0)
|
||||
actiontext (6.1.7.3)
|
||||
actionpack (= 6.1.7.3)
|
||||
activerecord (= 6.1.7.3)
|
||||
activestorage (= 6.1.7.3)
|
||||
activesupport (= 6.1.7.3)
|
||||
actiontext (6.1.7.4)
|
||||
actionpack (= 6.1.7.4)
|
||||
activerecord (= 6.1.7.4)
|
||||
activestorage (= 6.1.7.4)
|
||||
activesupport (= 6.1.7.4)
|
||||
nokogiri (>= 1.8.5)
|
||||
actionview (6.1.7.3)
|
||||
activesupport (= 6.1.7.3)
|
||||
actionview (6.1.7.4)
|
||||
activesupport (= 6.1.7.4)
|
||||
builder (~> 3.1)
|
||||
erubi (~> 1.4)
|
||||
rails-dom-testing (~> 2.0)
|
||||
rails-html-sanitizer (~> 1.1, >= 1.2.0)
|
||||
activejob (6.1.7.3)
|
||||
activesupport (= 6.1.7.3)
|
||||
activejob (6.1.7.4)
|
||||
activesupport (= 6.1.7.4)
|
||||
globalid (>= 0.3.6)
|
||||
activemodel (6.1.7.3)
|
||||
activesupport (= 6.1.7.3)
|
||||
activerecord (6.1.7.3)
|
||||
activemodel (= 6.1.7.3)
|
||||
activesupport (= 6.1.7.3)
|
||||
activestorage (6.1.7.3)
|
||||
actionpack (= 6.1.7.3)
|
||||
activejob (= 6.1.7.3)
|
||||
activerecord (= 6.1.7.3)
|
||||
activesupport (= 6.1.7.3)
|
||||
activemodel (6.1.7.4)
|
||||
activesupport (= 6.1.7.4)
|
||||
activerecord (6.1.7.4)
|
||||
activemodel (= 6.1.7.4)
|
||||
activesupport (= 6.1.7.4)
|
||||
activestorage (6.1.7.4)
|
||||
actionpack (= 6.1.7.4)
|
||||
activejob (= 6.1.7.4)
|
||||
activerecord (= 6.1.7.4)
|
||||
activesupport (= 6.1.7.4)
|
||||
marcel (~> 1.0)
|
||||
mini_mime (>= 1.1.0)
|
||||
activesupport (6.1.7.3)
|
||||
activesupport (6.1.7.4)
|
||||
concurrent-ruby (~> 1.0, >= 1.0.2)
|
||||
i18n (>= 1.6, < 2)
|
||||
minitest (>= 5.1)
|
||||
tzinfo (~> 2.0)
|
||||
zeitwerk (~> 2.3)
|
||||
addressable (2.8.4)
|
||||
addressable (2.8.6)
|
||||
public_suffix (>= 2.0.2, < 6.0)
|
||||
adsp (1.0.10)
|
||||
after_commit_everywhere (1.4.0)
|
||||
activerecord (>= 4.2)
|
||||
activesupport
|
||||
ast (2.4.2)
|
||||
autoprefixer-rails (10.4.13.0)
|
||||
execjs (~> 2)
|
||||
bcrypt (3.1.19-x86_64-linux-musl)
|
||||
bcrypt (3.1.20-x86_64-linux-musl)
|
||||
bcrypt_pbkdf (1.1.0-x86_64-linux-musl)
|
||||
benchmark-ips (2.12.0)
|
||||
bigdecimal (3.1.1)
|
||||
bindex (0.8.1-x86_64-linux-musl)
|
||||
blazer (2.6.5)
|
||||
activerecord (>= 5)
|
||||
|
@ -104,7 +111,8 @@ GEM
|
|||
autoprefixer-rails (>= 9.1.0)
|
||||
popper_js (>= 1.16.1, < 2)
|
||||
sassc-rails (>= 2.0.0)
|
||||
brakeman (5.4.1)
|
||||
brakeman (6.1.1)
|
||||
racc
|
||||
builder (3.2.4)
|
||||
bundler-audit (0.9.1)
|
||||
bundler (>= 1.2.0, < 3)
|
||||
|
@ -125,6 +133,7 @@ GEM
|
|||
concurrent-ruby (1.2.2)
|
||||
concurrent-ruby-ext (1.2.2-x86_64-linux-musl)
|
||||
concurrent-ruby (= 1.2.2)
|
||||
connection_pool (2.4.1)
|
||||
crass (1.0.6)
|
||||
database_cleaner (2.0.2)
|
||||
database_cleaner-active_record (>= 2, < 3)
|
||||
|
@ -132,7 +141,7 @@ GEM
|
|||
activerecord (>= 5.a)
|
||||
database_cleaner-core (~> 2.0.0)
|
||||
database_cleaner-core (2.0.1)
|
||||
date (3.3.3-x86_64-linux-musl)
|
||||
date (3.3.4-x86_64-linux-musl)
|
||||
dead_end (4.0.0)
|
||||
derailed_benchmarks (2.1.2)
|
||||
benchmark-ips (~> 2)
|
||||
|
@ -146,8 +155,8 @@ GEM
|
|||
rake (> 10, < 14)
|
||||
ruby-statistics (>= 2.1)
|
||||
thor (>= 0.19, < 2)
|
||||
device_detector (1.1.1)
|
||||
devise (4.9.2)
|
||||
device_detector (1.1.2)
|
||||
devise (4.9.3)
|
||||
bcrypt (~> 3.0)
|
||||
orm_adapter (~> 0.1)
|
||||
railties (>= 4.1.0)
|
||||
|
@ -155,14 +164,15 @@ GEM
|
|||
warden (~> 1.2.3)
|
||||
devise-i18n (1.11.0)
|
||||
devise (>= 4.9.0)
|
||||
devise_invitable (2.0.8)
|
||||
devise_invitable (2.0.9)
|
||||
actionmailer (>= 5.0)
|
||||
devise (>= 4.6)
|
||||
distributed-press-api-client (0.3.0rc0)
|
||||
distributed-press-api-client (0.4.0rc2)
|
||||
addressable (~> 2.3, >= 2.3.0)
|
||||
climate_control
|
||||
dry-schema
|
||||
httparty (~> 0.18)
|
||||
httparty-cache (~> 0.0.4)
|
||||
json (~> 2.1, >= 2.1.0)
|
||||
jwt (~> 2.6.0)
|
||||
dotenv (2.8.1)
|
||||
|
@ -171,10 +181,10 @@ GEM
|
|||
railties (>= 3.2)
|
||||
down (5.4.1)
|
||||
addressable (~> 2.8)
|
||||
dry-configurable (1.0.1)
|
||||
dry-configurable (1.1.0)
|
||||
dry-core (~> 1.0, < 2)
|
||||
zeitwerk (~> 2.6)
|
||||
dry-core (1.0.0)
|
||||
dry-core (1.0.1)
|
||||
concurrent-ruby (~> 1.0)
|
||||
zeitwerk (~> 2.6)
|
||||
dry-inflector (1.0.0)
|
||||
|
@ -183,7 +193,7 @@ GEM
|
|||
concurrent-ruby (~> 1.0)
|
||||
dry-core (~> 1.0, < 2)
|
||||
zeitwerk (~> 2.6)
|
||||
dry-schema (1.13.1)
|
||||
dry-schema (1.13.3)
|
||||
concurrent-ruby (~> 1.0)
|
||||
dry-configurable (~> 1.0, >= 1.0.1)
|
||||
dry-core (~> 1.0, < 2)
|
||||
|
@ -191,7 +201,8 @@ GEM
|
|||
dry-logic (>= 1.4, < 2)
|
||||
dry-types (>= 1.7, < 2)
|
||||
zeitwerk (~> 2.6)
|
||||
dry-types (1.7.1)
|
||||
dry-types (1.7.2)
|
||||
bigdecimal (~> 3.0)
|
||||
concurrent-ruby (~> 1.0)
|
||||
dry-core (~> 1.0)
|
||||
dry-inflector (~> 1.0)
|
||||
|
@ -224,25 +235,25 @@ GEM
|
|||
ffi (~> 1.0)
|
||||
git_clone_url (2.0.0)
|
||||
uri-ssh_git (>= 2.0)
|
||||
globalid (1.1.0)
|
||||
activesupport (>= 5.0)
|
||||
globalid (1.2.1)
|
||||
activesupport (>= 6.1)
|
||||
groupdate (6.2.1)
|
||||
activesupport (>= 5.2)
|
||||
hairtrigger (1.0.0)
|
||||
activerecord (>= 6.0, < 8)
|
||||
ruby2ruby (~> 2.4)
|
||||
ruby_parser (~> 3.10)
|
||||
haml (6.1.2-x86_64-linux-musl)
|
||||
haml (6.3.0)
|
||||
temple (>= 0.8.2)
|
||||
thor
|
||||
tilt
|
||||
haml-lint (0.999.999)
|
||||
haml_lint
|
||||
haml_lint (0.45.0)
|
||||
haml (>= 4.0, < 6.2)
|
||||
haml_lint (0.53.0)
|
||||
haml (>= 5.0)
|
||||
parallel (~> 1.10)
|
||||
rainbow
|
||||
rubocop (>= 0.50.0)
|
||||
rubocop (>= 1.0)
|
||||
sysexits (~> 1.1)
|
||||
hamlit (3.0.3-x86_64-linux-musl)
|
||||
temple (>= 0.8.2)
|
||||
|
@ -256,10 +267,14 @@ GEM
|
|||
heapy (0.2.0)
|
||||
thor
|
||||
hiredis (0.6.3-x86_64-linux-musl)
|
||||
hiredis-client (0.14.1-x86_64-linux-musl)
|
||||
redis-client (= 0.14.1)
|
||||
http_parser.rb (0.8.0-x86_64-linux-musl)
|
||||
httparty (0.21.0)
|
||||
mini_mime (>= 1.0.0)
|
||||
multi_xml (>= 0.5.2)
|
||||
httparty-cache (0.0.4)
|
||||
httparty (~> 0.18)
|
||||
i18n (1.14.1)
|
||||
concurrent-ruby (~> 1.0)
|
||||
icalendar (2.8.0)
|
||||
|
@ -291,7 +306,7 @@ GEM
|
|||
terminal-table (~> 2.0)
|
||||
jekyll-commonmark (1.4.0)
|
||||
commonmarker (~> 0.22)
|
||||
jekyll-images (0.4.1)
|
||||
jekyll-images (0.4.4)
|
||||
jekyll (~> 4)
|
||||
ruby-filemagic (~> 0.7)
|
||||
ruby-vips (~> 2)
|
||||
|
@ -301,7 +316,7 @@ GEM
|
|||
sassc (> 2.0.1, < 3.0)
|
||||
jekyll-watch (2.2.1)
|
||||
listen (~> 3.0)
|
||||
json (2.6.3-x86_64-linux-musl)
|
||||
json (2.7.1-x86_64-linux-musl)
|
||||
jwt (2.6.0)
|
||||
kaminari (1.2.2)
|
||||
activesupport (>= 4.1.0)
|
||||
|
@ -330,12 +345,12 @@ GEM
|
|||
loaf (0.10.0)
|
||||
railties (>= 3.2)
|
||||
lockbox (1.2.0)
|
||||
lograge (0.12.0)
|
||||
lograge (0.14.0)
|
||||
actionpack (>= 4)
|
||||
activesupport (>= 4)
|
||||
railties (>= 4)
|
||||
request_store (~> 1.0)
|
||||
loofah (2.21.3)
|
||||
loofah (2.22.0)
|
||||
crass (~> 1.0.2)
|
||||
nokogiri (>= 1.12.0)
|
||||
mail (2.8.1)
|
||||
|
@ -349,36 +364,37 @@ GEM
|
|||
method_source (1.0.0)
|
||||
mini_histogram (0.3.1)
|
||||
mini_magick (4.12.0)
|
||||
mini_mime (1.1.2)
|
||||
mini_portile2 (2.8.2)
|
||||
minitest (5.18.0)
|
||||
mini_mime (1.1.5)
|
||||
mini_portile2 (2.8.5)
|
||||
minitest (5.21.1)
|
||||
mobility (1.2.9)
|
||||
i18n (>= 0.6.10, < 2)
|
||||
request_store (~> 1.0)
|
||||
multi_xml (0.6.0)
|
||||
net-imap (0.3.4)
|
||||
net-imap (0.4.9)
|
||||
date
|
||||
net-protocol
|
||||
net-pop (0.1.2)
|
||||
net-protocol
|
||||
net-protocol (0.2.1)
|
||||
net-protocol (0.2.2)
|
||||
timeout
|
||||
net-smtp (0.3.3)
|
||||
net-smtp (0.4.0)
|
||||
net-protocol
|
||||
net-ssh (7.1.0)
|
||||
net-ssh (7.2.1)
|
||||
netaddr (2.0.6)
|
||||
nio4r (2.5.9-x86_64-linux-musl)
|
||||
nokogiri (1.15.4-x86_64-linux-musl)
|
||||
nio4r (2.7.0-x86_64-linux-musl)
|
||||
nokogiri (1.16.0-x86_64-linux-musl)
|
||||
mini_portile2 (~> 2.8.2)
|
||||
racc (~> 1.4)
|
||||
orm_adapter (0.5.0)
|
||||
pairing_heap (3.0.1)
|
||||
parallel (1.23.0)
|
||||
parser (3.2.2.1)
|
||||
parallel (1.24.0)
|
||||
parser (3.2.2.3)
|
||||
ast (~> 2.4.1)
|
||||
racc
|
||||
pathutil (0.16.2)
|
||||
forwardable-extended (~> 2.6)
|
||||
pg (1.5.3-x86_64-linux-musl)
|
||||
pg (1.5.4-x86_64-linux-musl)
|
||||
pg_search (2.3.6)
|
||||
activerecord (>= 5.2)
|
||||
activesupport (>= 5.2)
|
||||
|
@ -388,55 +404,57 @@ GEM
|
|||
pry (0.14.2)
|
||||
coderay (~> 1.1)
|
||||
method_source (~> 1.0)
|
||||
public_suffix (5.0.3)
|
||||
puma (6.3.1-x86_64-linux-musl)
|
||||
public_suffix (5.0.4)
|
||||
puma (6.4.2-x86_64-linux-musl)
|
||||
nio4r (~> 2.0)
|
||||
pundit (2.3.0)
|
||||
pundit (2.3.1)
|
||||
activesupport (>= 3.0.0)
|
||||
que (2.2.1)
|
||||
racc (1.7.1-x86_64-linux-musl)
|
||||
rack (2.2.7)
|
||||
racc (1.7.3-x86_64-linux-musl)
|
||||
rack (2.2.8)
|
||||
rack-cors (2.0.1)
|
||||
rack (>= 2.0.0)
|
||||
rack-mini-profiler (3.1.0)
|
||||
rack (>= 1.2.0)
|
||||
rack-proxy (0.7.6)
|
||||
rack-proxy (0.7.7)
|
||||
rack
|
||||
rack-test (2.1.0)
|
||||
rack (>= 1.3)
|
||||
rails (6.1.7.3)
|
||||
actioncable (= 6.1.7.3)
|
||||
actionmailbox (= 6.1.7.3)
|
||||
actionmailer (= 6.1.7.3)
|
||||
actionpack (= 6.1.7.3)
|
||||
actiontext (= 6.1.7.3)
|
||||
actionview (= 6.1.7.3)
|
||||
activejob (= 6.1.7.3)
|
||||
activemodel (= 6.1.7.3)
|
||||
activerecord (= 6.1.7.3)
|
||||
activestorage (= 6.1.7.3)
|
||||
activesupport (= 6.1.7.3)
|
||||
rails (6.1.7.4)
|
||||
actioncable (= 6.1.7.4)
|
||||
actionmailbox (= 6.1.7.4)
|
||||
actionmailer (= 6.1.7.4)
|
||||
actionpack (= 6.1.7.4)
|
||||
actiontext (= 6.1.7.4)
|
||||
actionview (= 6.1.7.4)
|
||||
activejob (= 6.1.7.4)
|
||||
activemodel (= 6.1.7.4)
|
||||
activerecord (= 6.1.7.4)
|
||||
activestorage (= 6.1.7.4)
|
||||
activesupport (= 6.1.7.4)
|
||||
bundler (>= 1.15.0)
|
||||
railties (= 6.1.7.3)
|
||||
railties (= 6.1.7.4)
|
||||
sprockets-rails (>= 2.0.0)
|
||||
rails-dom-testing (2.0.3)
|
||||
activesupport (>= 4.2.0)
|
||||
rails-dom-testing (2.2.0)
|
||||
activesupport (>= 5.0.0)
|
||||
minitest
|
||||
nokogiri (>= 1.6)
|
||||
rails-html-sanitizer (1.5.0)
|
||||
loofah (~> 2.19, >= 2.19.1)
|
||||
rails-i18n (7.0.7)
|
||||
rails-html-sanitizer (1.6.0)
|
||||
loofah (~> 2.21)
|
||||
nokogiri (~> 1.14)
|
||||
rails-i18n (7.0.8)
|
||||
i18n (>= 0.7, < 2)
|
||||
railties (>= 6.0.0, < 8)
|
||||
rails_warden (0.6.0)
|
||||
warden (>= 1.2.0)
|
||||
railties (6.1.7.3)
|
||||
actionpack (= 6.1.7.3)
|
||||
activesupport (= 6.1.7.3)
|
||||
railties (6.1.7.4)
|
||||
actionpack (= 6.1.7.4)
|
||||
activesupport (= 6.1.7.4)
|
||||
method_source
|
||||
rake (>= 12.2)
|
||||
thor (~> 1.0)
|
||||
rainbow (3.1.1)
|
||||
rake (13.0.6)
|
||||
rake (13.1.0)
|
||||
rb-fsevent (0.11.2)
|
||||
rb-inotify (0.10.1)
|
||||
ffi (~> 1.0)
|
||||
|
@ -448,6 +466,8 @@ GEM
|
|||
redis-activesupport (5.3.0)
|
||||
activesupport (>= 3, < 8)
|
||||
redis-store (>= 1.3, < 2)
|
||||
redis-client (0.14.1)
|
||||
connection_pool
|
||||
redis-rack (2.1.4)
|
||||
rack (>= 2.0.8, < 3)
|
||||
redis-store (>= 1.2, < 2)
|
||||
|
@ -457,13 +477,13 @@ GEM
|
|||
redis-store (>= 1.2, < 2)
|
||||
redis-store (1.9.2)
|
||||
redis (>= 4, < 6)
|
||||
regexp_parser (2.8.0)
|
||||
regexp_parser (2.9.0)
|
||||
request_store (1.5.1)
|
||||
rack (>= 1.4)
|
||||
responders (3.1.0)
|
||||
responders (3.1.1)
|
||||
actionpack (>= 5.2)
|
||||
railties (>= 5.2)
|
||||
rexml (3.2.5)
|
||||
rexml (3.2.6)
|
||||
rgl (0.6.3)
|
||||
pairing_heap (>= 0.3.0)
|
||||
rexml (~> 3.2, >= 3.2.4)
|
||||
|
@ -479,16 +499,19 @@ GEM
|
|||
rubocop-ast (>= 1.24.1, < 2.0)
|
||||
ruby-progressbar (~> 1.7)
|
||||
unicode-display_width (>= 1.4.0, < 3.0)
|
||||
rubocop-ast (1.28.1)
|
||||
rubocop-ast (1.30.0)
|
||||
parser (>= 3.2.1.0)
|
||||
rubocop-rails (2.19.1)
|
||||
rubocop-rails (2.23.1)
|
||||
activesupport (>= 4.2.0)
|
||||
rack (>= 1.1)
|
||||
rubocop (>= 1.33.0, < 2.0)
|
||||
rubocop-ast (>= 1.30.0, < 2.0)
|
||||
ruby-brs (1.3.3-x86_64-linux-musl)
|
||||
adsp (~> 1.0)
|
||||
ruby-filemagic (0.7.3-x86_64-linux-musl)
|
||||
ruby-progressbar (1.13.0)
|
||||
ruby-statistics (3.0.2)
|
||||
ruby-vips (2.1.4)
|
||||
ruby-vips (2.2.0)
|
||||
ffi (~> 1.12)
|
||||
ruby2ruby (2.5.0)
|
||||
ruby_parser (~> 3.1)
|
||||
|
@ -521,14 +544,14 @@ GEM
|
|||
spring-watcher-listen (2.1.0)
|
||||
listen (>= 2.7, < 4.0)
|
||||
spring (>= 4)
|
||||
sprockets (4.2.0)
|
||||
sprockets (4.2.1)
|
||||
concurrent-ruby (~> 1.0)
|
||||
rack (>= 2.2.4, < 4)
|
||||
sprockets-rails (3.4.2)
|
||||
actionpack (>= 5.2)
|
||||
activesupport (>= 5.2)
|
||||
sprockets (>= 3.0.0)
|
||||
sqlite3 (1.6.3-x86_64-linux-musl)
|
||||
sqlite3 (1.7.0-x86_64-linux-musl)
|
||||
mini_portile2 (~> 2.8.0)
|
||||
stackprof (0.2.25-x86_64-linux-musl)
|
||||
stream (0.5.5)
|
||||
|
@ -537,13 +560,13 @@ GEM
|
|||
jekyll (~> 4)
|
||||
symbol-fstring (1.0.2-x86_64-linux-musl)
|
||||
sysexits (1.2.0)
|
||||
temple (0.10.1)
|
||||
temple (0.10.3)
|
||||
terminal-table (2.0.0)
|
||||
unicode-display_width (~> 1.1, >= 1.1.1)
|
||||
thor (1.3.0)
|
||||
tilt (2.1.0)
|
||||
tilt (2.3.0)
|
||||
timecop (0.9.6)
|
||||
timeout (0.3.2)
|
||||
timeout (0.4.1)
|
||||
turbolinks (5.2.1)
|
||||
turbolinks-source (~> 5.2)
|
||||
turbolinks-source (5.2.0)
|
||||
|
@ -553,7 +576,7 @@ GEM
|
|||
execjs (>= 0.3.0, < 3)
|
||||
unf (0.1.4)
|
||||
unf_ext
|
||||
unf_ext (0.0.8.2-x86_64-linux-musl)
|
||||
unf_ext (0.0.9-x86_64-linux-musl)
|
||||
unicode-display_width (1.8.0)
|
||||
uri-ssh_git (2.0.0)
|
||||
validates_hostname (1.0.13)
|
||||
|
@ -579,12 +602,14 @@ GEM
|
|||
xpath (3.2.0)
|
||||
nokogiri (~> 1.8)
|
||||
yard (0.9.34)
|
||||
zeitwerk (2.6.8)
|
||||
zeitwerk (2.6.12)
|
||||
|
||||
PLATFORMS
|
||||
x86_64-linux-musl
|
||||
|
||||
DEPENDENCIES
|
||||
aasm
|
||||
after_commit_everywhere (~> 1.0)
|
||||
bcrypt (~> 3.1.7)
|
||||
bcrypt_pbkdf
|
||||
blazer
|
||||
|
@ -601,7 +626,7 @@ DEPENDENCIES
|
|||
devise
|
||||
devise-i18n
|
||||
devise_invitable
|
||||
distributed-press-api-client (~> 0.3.0rc0)
|
||||
distributed-press-api-client (~> 0.4.0rc2)
|
||||
dotenv-rails
|
||||
down
|
||||
ed25519
|
||||
|
@ -617,6 +642,7 @@ DEPENDENCIES
|
|||
haml-lint
|
||||
hamlit-rails
|
||||
hiredis
|
||||
hiredis-client
|
||||
httparty
|
||||
icalendar
|
||||
image_processing
|
||||
|
@ -650,10 +676,12 @@ DEPENDENCIES
|
|||
rails-i18n
|
||||
rails_warden
|
||||
redis (~> 4.0)
|
||||
redis-client
|
||||
redis-rails
|
||||
rgl
|
||||
rollups!
|
||||
rubocop-rails
|
||||
ruby-brs
|
||||
rubyzip
|
||||
rugged (= 1.5.0.1)
|
||||
safe_yaml
|
||||
|
|
79
app/controllers/api/v1/webhooks/concerns/webhook_concern.rb
Normal file
79
app/controllers/api/v1/webhooks/concerns/webhook_concern.rb
Normal file
|
@ -0,0 +1,79 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Api
|
||||
module V1
|
||||
module Webhooks
|
||||
module Concerns
|
||||
# Helpers para webhooks
|
||||
module WebhookConcern
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
included do
|
||||
skip_before_action :verify_authenticity_token
|
||||
|
||||
# Responde con forbidden si falla la validación del token
|
||||
rescue_from ActiveRecord::RecordNotFound, with: :platforms_answer
|
||||
rescue_from ActiveRecord::RecordInvalid, with: :platforms_answer
|
||||
|
||||
private
|
||||
|
||||
# Valida el token que envía la plataforma en el webhook
|
||||
#
|
||||
# @return [String]
|
||||
def token
|
||||
@token ||=
|
||||
begin
|
||||
header = request.headers
|
||||
token = header['X-Social-Inbox'].presence
|
||||
token ||= header['X-Gitlab-Token'].presence
|
||||
token ||= token_from_signature(header['X-Gitea-Signature'].presence)
|
||||
token ||= token_from_signature(header['X-Hub-Signature-256'].presence, 'sha256=')
|
||||
token
|
||||
ensure
|
||||
raise ActiveRecord::RecordNotFound, 'Proveedor no soportado' if token.blank?
|
||||
end
|
||||
end
|
||||
|
||||
# Valida token a partir de firma
|
||||
#
|
||||
# @param signature [String,nil]
|
||||
# @param prepend [String]
|
||||
# @return [String, nil]
|
||||
def token_from_signature(signature, prepend = '')
|
||||
return if signature.nil?
|
||||
|
||||
payload = request.raw_post
|
||||
|
||||
site.roles.where(temporal: false, rol: 'usuarie').pluck(:token).find do |token|
|
||||
new_signature = prepend + OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), token, payload)
|
||||
|
||||
ActiveSupport::SecurityUtils.secure_compare(new_signature, signature.to_s)
|
||||
end
|
||||
end
|
||||
|
||||
# Encuentra el sitio a partir de la URL
|
||||
#
|
||||
# @return [Site]
|
||||
def site
|
||||
@site ||= Site.find_by_name!(params[:site_id])
|
||||
end
|
||||
|
||||
# Encuentra le usuarie
|
||||
#
|
||||
# @return [Site]
|
||||
def usuarie
|
||||
@usuarie ||= site.roles.find_by!(temporal: false, rol: 'usuarie', token: token).usuarie
|
||||
end
|
||||
|
||||
# Respuesta de error a plataformas
|
||||
def platforms_answer(exception)
|
||||
ExceptionNotifier.notify_exception(exception, data: { headers: request.headers.to_h })
|
||||
|
||||
head :forbidden
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
25
app/controllers/api/v1/webhooks/pull_controller.rb
Normal file
25
app/controllers/api/v1/webhooks/pull_controller.rb
Normal file
|
@ -0,0 +1,25 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Api
|
||||
module V1
|
||||
module Webhooks
|
||||
# Recibe webhooks y lanza un PullJob
|
||||
class PullController < BaseController
|
||||
include WebhookConcern
|
||||
|
||||
# Trae los cambios a partir de un post de Webhooks:
|
||||
# (Gitlab, Github, Gitea, etc)
|
||||
#
|
||||
# @return [nil]
|
||||
def pull
|
||||
message = I18n.with_locale(site.default_locale) do
|
||||
I18n.t('webhooks.pull.message')
|
||||
end
|
||||
|
||||
GitPullJob.perform_later(site, usuarie, message)
|
||||
head :ok
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
165
app/controllers/api/v1/webhooks/social_inbox_controller.rb
Normal file
165
app/controllers/api/v1/webhooks/social_inbox_controller.rb
Normal file
|
@ -0,0 +1,165 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Api
|
||||
module V1
|
||||
module Webhooks
|
||||
# Recibe webhooks de la Social Inbox
|
||||
#
|
||||
# @see {https://www.w3.org/TR/activitypub/}
|
||||
class SocialInboxController < BaseController
|
||||
include Api::V1::Webhooks::Concerns::WebhookConcern
|
||||
|
||||
# Cuando una actividad ingresa en la cola de moderación, la
|
||||
# recibimos por acá
|
||||
#
|
||||
# Vamos a recibir Create, Update, Delete, Follow, Undo y obtener
|
||||
# el objeto dentro de cada una para guardar un estado asociado
|
||||
# al sitio.
|
||||
#
|
||||
# El objeto del estado puede ser un objeto o une actore,
|
||||
# dependiendo de la actividad.
|
||||
def moderationqueued
|
||||
# Devuelve un error si el token no es válido
|
||||
usuarie.present?
|
||||
|
||||
ActivityPub.transaction do
|
||||
# Crea todos los registros necesarios y actualiza el estado
|
||||
actor.present?
|
||||
instance.present?
|
||||
object.present?
|
||||
activity_pub.present?
|
||||
activity.update_activity_pub_state!
|
||||
end
|
||||
rescue ActiveRecord::RecordInvalid => e
|
||||
ExceptionNotifier.notify_exception(e,
|
||||
data: { site: site.name, usuarie: usuarie.email,
|
||||
activity: original_activity })
|
||||
ensure
|
||||
head :accepted
|
||||
end
|
||||
|
||||
# Cuando aprobamos una actividad, recibimos la confirmación y
|
||||
# cambiamos el estado.
|
||||
def onapproved
|
||||
ActivityPub.transaction do
|
||||
activity_pub.approve! if activity_pub.waiting?
|
||||
end
|
||||
|
||||
head :accepted
|
||||
end
|
||||
|
||||
# Cuando rechazamos una actividad, recibimos la confirmación y
|
||||
# cambiamos el estado
|
||||
def onrejected
|
||||
ActivityPub.transaction do
|
||||
activity_pub.reject! if activity_pub.waiting?
|
||||
end
|
||||
|
||||
head :accepted
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Si el objeto ya viene incorporado en la actividad o lo tenemos
|
||||
# que traer remotamente.
|
||||
#
|
||||
# @return [Bool]
|
||||
def object_embedded?
|
||||
@object_embedded ||= original_activity[:object].is_a?(Hash)
|
||||
end
|
||||
|
||||
# Encuentra la URI del objeto o falla si no la encuentra.
|
||||
#
|
||||
# @return [String]
|
||||
def object_uri
|
||||
@object_uri ||=
|
||||
case original_activity[:object]
|
||||
when String then original_activity[:object]
|
||||
when Hash then original_activity.dig(:object, :id)
|
||||
end
|
||||
ensure
|
||||
raise ActiveRecord::RecordNotFound, 'object id missing' unless @object_uri
|
||||
end
|
||||
|
||||
# Atajo a la instancia
|
||||
#
|
||||
# @return [ActivityPub::Instance]
|
||||
def instance
|
||||
actor.instance
|
||||
end
|
||||
|
||||
# Genera un objeto a partir de la actividad. Si el objeto ya
|
||||
# existe, actualiza su contenido. Si el objeto no viene
|
||||
# incorporado, obtenemos el contenido más tarde.
|
||||
#
|
||||
# @return [ActivityPub::Object]
|
||||
def object
|
||||
@object ||= ActivityPub::Object.find_or_initialize_by(uri: object_uri).tap do |o|
|
||||
# XXX: Si el objeto es una actividad, esto siempre va a ser
|
||||
# Generic
|
||||
o.type ||= 'ActivityPub::Object::Generic'
|
||||
o.content = original_object if object_embedded?
|
||||
|
||||
o.save!
|
||||
|
||||
# XXX: el objeto necesita ser guardado antes de poder
|
||||
# procesarlo
|
||||
ActivityPub::FetchJob.perform_later(site: site, object: o) unless object_embedded?
|
||||
end
|
||||
end
|
||||
|
||||
# Genera el seguimiento del estado del objeto con respecto al
|
||||
# sitio.
|
||||
#
|
||||
# @return [ActivityPub]
|
||||
def activity_pub
|
||||
@activity_pub ||= site.activity_pubs.find_or_create_by!(site: site, object: object)
|
||||
end
|
||||
|
||||
# Crea la actividad y la vincula con el estado
|
||||
#
|
||||
# @return [ActivityPub::Activity]
|
||||
def activity
|
||||
@activity ||= ActivityPub::Activity.type_from(original_activity).new(uri: original_activity[:id],
|
||||
activity_pub: activity_pub).tap do |a|
|
||||
a.content = original_activity.dup
|
||||
a.content[:object] = object.uri
|
||||
a.save!
|
||||
end
|
||||
end
|
||||
|
||||
# Actor, si no hay instancia, la crea en el momento
|
||||
#
|
||||
# @return [Actor]
|
||||
def actor
|
||||
@actor ||= ActivityPub::Actor.find_or_initialize_by(uri: original_activity[:actor]).tap do |a|
|
||||
next if a.instance
|
||||
|
||||
a.instance = ActivityPub::Instance.find_or_create_by(hostname: URI.parse(a.uri).hostname)
|
||||
a.save!
|
||||
end
|
||||
end
|
||||
|
||||
# Descubre la actividad recibida, generando un error si la
|
||||
# actividad no está dirigida a nosotres.
|
||||
#
|
||||
# @todo Validar formato
|
||||
# @return [Hash]
|
||||
def original_activity
|
||||
@original_activity ||= FastJsonparser.parse(request.raw_post).tap do |activity|
|
||||
raise '@context missing' unless activity[:@context].presence
|
||||
raise 'id missing' unless activity[:id].presence
|
||||
raise 'object missing' unless activity[:object].presence
|
||||
rescue RuntimeError => e
|
||||
raise ActiveRecord::RecordNotFound, e.message
|
||||
end
|
||||
end
|
||||
|
||||
# @return [Hash,String]
|
||||
def original_object
|
||||
@original_object ||= original_activity[:object].dup
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,77 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Api
|
||||
module V1
|
||||
# Recibe webhooks y lanza un PullJob
|
||||
class WebhooksController < BaseController
|
||||
# responde con forbidden si falla la validación del token
|
||||
rescue_from ActiveRecord::RecordNotFound, with: :platforms_answer
|
||||
|
||||
# Trae los cambios a partir de un post de Webhooks:
|
||||
# (Gitlab, Github, Gitea, etc)
|
||||
#
|
||||
# @return [nil]
|
||||
def pull
|
||||
message = I18n.with_locale(site.default_locale) do
|
||||
I18n.t('webhooks.pull.message')
|
||||
end
|
||||
|
||||
GitPullJob.perform_later(site, usuarie, message)
|
||||
head :ok
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# encuentra el sitio a partir de la url
|
||||
def site
|
||||
@site ||= Site.find_by_name!(params[:site_id])
|
||||
end
|
||||
|
||||
# valida el token que envía la plataforma del webhook
|
||||
#
|
||||
# @return [String]
|
||||
def token
|
||||
@token ||=
|
||||
begin
|
||||
# Gitlab
|
||||
if request.headers['X-Gitlab-Token'].present?
|
||||
request.headers['X-Gitlab-Token']
|
||||
# Github
|
||||
elsif request.headers['X-Hub-Signature-256'].present?
|
||||
token_from_signature(request.headers['X-Hub-Signature-256'], 'sha256=')
|
||||
# Gitea
|
||||
elsif request.headers['X-Gitea-Signature'].present?
|
||||
token_from_signature(request.headers['X-Gitea-Signature'])
|
||||
else
|
||||
raise ActiveRecord::RecordNotFound, 'proveedor no soportado'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# valida token a partir de firma de webhook
|
||||
#
|
||||
# @return [String, Boolean]
|
||||
def token_from_signature(signature, prepend = '')
|
||||
payload = request.body.read
|
||||
site.roles.where(temporal: false, rol: 'usuarie').pluck(:token).find do |token|
|
||||
new_signature = prepend + OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), token, payload)
|
||||
ActiveSupport::SecurityUtils.secure_compare(new_signature, signature.to_s)
|
||||
end.tap do |t|
|
||||
raise ActiveRecord::RecordNotFound, 'token no encontrado' if t.nil?
|
||||
end
|
||||
end
|
||||
|
||||
# encuentra le usuarie
|
||||
def usuarie
|
||||
@usuarie ||= site.roles.find_by!(temporal: false, rol: 'usuarie', token: token).usuarie
|
||||
end
|
||||
|
||||
# respuesta de error a plataformas
|
||||
def platforms_answer(exception)
|
||||
ExceptionNotifier.notify_exception(exception, data: { headers: request.headers.to_h })
|
||||
|
||||
head :forbidden
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
28
app/jobs/activity_pub/fetch_job.rb
Normal file
28
app/jobs/activity_pub/fetch_job.rb
Normal file
|
@ -0,0 +1,28 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
# Obtiene o actualiza el contenido de un objeto, usando las credenciales
|
||||
# del sitio.
|
||||
#
|
||||
# XXX: Esto usa las credenciales del sitio para volver el objeto
|
||||
# disponible para todo el CMS. Asumimos que el objeto devuelto es el
|
||||
# mismo para todo el mundo y las credenciales solo son para
|
||||
# autenticación.
|
||||
class ActivityPub
|
||||
class FetchJob < ApplicationJob
|
||||
def perform(site:, object:)
|
||||
ActivityPub::Object.transaction do
|
||||
return if object.activity_pubs.where(aasm_state: 'removed').count.positive?
|
||||
|
||||
response = site.social_inbox.dereferencer.get(uri: object.uri)
|
||||
|
||||
# @todo Fallar cuando la respuesta no funcione?
|
||||
return unless response.ok?
|
||||
return if response.miss? && object.content.present?
|
||||
|
||||
content = FastJsonparser.parse(response.body)
|
||||
|
||||
object.update(content: content, type: ActivityPub::Object.type_from(content).name)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
62
app/models/activity_pub.rb
Normal file
62
app/models/activity_pub.rb
Normal file
|
@ -0,0 +1,62 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
# = ActivityPub =
|
||||
#
|
||||
# El registro de actividades recibidas y su estado. Cuando recibimos
|
||||
# una actividad, puede estar destinada a varies actores dentro de Sutty,
|
||||
# con lo que generamos una cola para cada une.
|
||||
#
|
||||
# @see {https://www.w3.org/TR/activitypub/#client-to-server-interactions}
|
||||
class ActivityPub < ApplicationRecord
|
||||
include AASM
|
||||
|
||||
belongs_to :site
|
||||
belongs_to :object, polymorphic: true
|
||||
has_many :activities
|
||||
|
||||
validates :site_id, presence: true
|
||||
validates :object_id, presence: true
|
||||
validates :aasm_state, presence: true, inclusion: { in: %w[paused approved rejected reported removed] }
|
||||
|
||||
aasm do
|
||||
# Todavía no hay una decisión sobre el objeto
|
||||
state :paused, initial: true
|
||||
# Estamos esperando respuesta desde la Social Inbox
|
||||
state :waiting
|
||||
# Le usuarie aprobó el objeto
|
||||
state :approved
|
||||
# Le usuarie rechazó el objeto
|
||||
state :rejected
|
||||
# Le usuarie reportó el objeto
|
||||
state :reported
|
||||
# Le actore eliminó el objeto
|
||||
state :removed
|
||||
|
||||
# Recibir una acción de eliminación, eliminar el contenido de la
|
||||
# base de datos. Esto elimina el contenido para todos los sitios
|
||||
# porque estamos respetando lo que pidió le actore.
|
||||
event :remove do
|
||||
transitions to: :removed
|
||||
|
||||
before do
|
||||
object.update(content: {}) unless object.content.empty?
|
||||
end
|
||||
end
|
||||
|
||||
# Si un objeto previamente aprobado fue actualizado, volvemos a
|
||||
# pausarlo.
|
||||
event :pause do
|
||||
transitions from: %i[waiting approved rejected], to: :paused
|
||||
end
|
||||
|
||||
# La actividad se aprueba
|
||||
event :approve do
|
||||
transitions from: :waiting, to: :approved
|
||||
end
|
||||
|
||||
# La actividad fue rechazada
|
||||
event :reject do
|
||||
transitions from: :waiting, to: :rejected
|
||||
end
|
||||
end
|
||||
end
|
31
app/models/activity_pub/activity.rb
Normal file
31
app/models/activity_pub/activity.rb
Normal file
|
@ -0,0 +1,31 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
# = Activity =
|
||||
#
|
||||
# Lleva un registro de las actividades que nos piden hacer remotamente.
|
||||
#
|
||||
# Las actividades pueden tener distintos destinataries (sitios/actores).
|
||||
#
|
||||
# @todo Obtener el contenido del objeto dinámicamente si no existe
|
||||
# localmente, por ejemplo cuando la actividad crea un objeto pero lo
|
||||
# envía como referencia en lugar de anidarlo.
|
||||
#
|
||||
# @see {https://www.w3.org/TR/activitypub/#client-to-server-interactions}
|
||||
class ActivityPub
|
||||
class Activity < ApplicationRecord
|
||||
include ActivityPub::Concerns::JsonLdConcern
|
||||
|
||||
belongs_to :activity_pub
|
||||
has_one :object, through: :activity_pub
|
||||
|
||||
validates :activity_pub_id, presence: true
|
||||
|
||||
# Siempre en orden descendiente para saber el último estado
|
||||
default_scope -> { order(created_at: :desc) }
|
||||
|
||||
# Cambia la máquina de estados según el tipo de actividad
|
||||
def update_activity_pub_state!
|
||||
nil
|
||||
end
|
||||
end
|
||||
end
|
7
app/models/activity_pub/activity/create.rb
Normal file
7
app/models/activity_pub/activity/create.rb
Normal file
|
@ -0,0 +1,7 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class ActivityPub
|
||||
class Activity
|
||||
class Create < ActivityPub::Activity; end
|
||||
end
|
||||
end
|
13
app/models/activity_pub/activity/delete.rb
Normal file
13
app/models/activity_pub/activity/delete.rb
Normal file
|
@ -0,0 +1,13 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class ActivityPub
|
||||
class Activity
|
||||
class Delete < ActivityPub::Activity
|
||||
# Si estamos eliminando el objeto, tenemos que vaciar su contenido y
|
||||
# cambiar el estado a borrado.
|
||||
def update_activity_pub_state!
|
||||
activity_pub.remove!
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
7
app/models/activity_pub/activity/flag.rb
Normal file
7
app/models/activity_pub/activity/flag.rb
Normal file
|
@ -0,0 +1,7 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class ActivityPub
|
||||
class Activity
|
||||
class Flag < ActivityPub::Activity; end
|
||||
end
|
||||
end
|
11
app/models/activity_pub/activity/follow.rb
Normal file
11
app/models/activity_pub/activity/follow.rb
Normal file
|
@ -0,0 +1,11 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
# = Follow =
|
||||
#
|
||||
# Una actividad de seguimiento se refiere siempre a une actore (el
|
||||
# sitio) y proviene de otre actore.
|
||||
class ActivityPub
|
||||
class Activity
|
||||
class Follow < ActivityPub::Activity; end
|
||||
end
|
||||
end
|
7
app/models/activity_pub/activity/generic.rb
Normal file
7
app/models/activity_pub/activity/generic.rb
Normal file
|
@ -0,0 +1,7 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class ActivityPub
|
||||
class Activity
|
||||
class Generic < ActivityPub::Activity; end
|
||||
end
|
||||
end
|
27
app/models/activity_pub/activity/undo.rb
Normal file
27
app/models/activity_pub/activity/undo.rb
Normal file
|
@ -0,0 +1,27 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
# = Undo =
|
||||
#
|
||||
# Deshace una actividad, dependiendo de la actividad a la que se
|
||||
# refiere.
|
||||
class ActivityPub
|
||||
class Activity
|
||||
class Undo < ActivityPub::Activity
|
||||
# Una actividad de deshacer tiene anidada como objeto la actividad
|
||||
# a deshacer. Para respetar la voluntad de le actore remote,
|
||||
# tendríamos que eliminar cualquier actividad pendiente sobre el
|
||||
# objeto.
|
||||
#
|
||||
# Sin embargo, estas acciones nunca deberían llegar a nuestra
|
||||
# Inbox.
|
||||
#
|
||||
# @see {https://github.com/hyphacoop/social.distributed.press/issues/43}
|
||||
def update_activity_pub_state!
|
||||
ActivityPub.transaction do
|
||||
ActivityPub::Activity.find_by(uri: content['object'])&.activity_pub&.remove!
|
||||
activity_pub.remove!
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
13
app/models/activity_pub/activity/update.rb
Normal file
13
app/models/activity_pub/activity/update.rb
Normal file
|
@ -0,0 +1,13 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class ActivityPub
|
||||
class Activity
|
||||
class Update < ActivityPub::Activity
|
||||
# Si estamos actualizando el objeto, tenemos que devolverlo a estado
|
||||
# de moderación
|
||||
def update_activity_pub_state!
|
||||
activity_pub.pause! if activity_pub.approved?
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
15
app/models/activity_pub/actor.rb
Normal file
15
app/models/activity_pub/actor.rb
Normal file
|
@ -0,0 +1,15 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
# = Actor =
|
||||
#
|
||||
# Actor es la entidad que realiza acciones en ActivityPub
|
||||
#
|
||||
# @todo Obtener el perfil dinámicamente
|
||||
class ActivityPub
|
||||
class Actor < ApplicationRecord
|
||||
include ActivityPub::Concerns::JsonLdConcern
|
||||
|
||||
belongs_to :instance
|
||||
has_many :activity_pubs, as: :object
|
||||
end
|
||||
end
|
34
app/models/activity_pub/concerns/json_ld_concern.rb
Normal file
34
app/models/activity_pub/concerns/json_ld_concern.rb
Normal file
|
@ -0,0 +1,34 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class ActivityPub
|
||||
module Concerns
|
||||
module JsonLdConcern
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
included do
|
||||
validates :uri, presence: true, uniqueness: true
|
||||
|
||||
# Cuando asignamos contenido, obtener la URI si no lo hicimos ya
|
||||
before_save :uri_from_content!, unless: :uri?
|
||||
|
||||
# Obtiene un tipo de actividad a partir del tipo informado
|
||||
#
|
||||
# @param object [Hash]
|
||||
# @return [Activity]
|
||||
def self.type_from(object)
|
||||
raise NameError unless object.is_a?(Hash)
|
||||
|
||||
"#{model_name.name}::#{object[:type].presence || 'Generic'}".constantize
|
||||
rescue NameError
|
||||
model_name.name.constantize::Generic
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def uri_from_content!
|
||||
self.uri = content[:id]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
23
app/models/activity_pub/instance.rb
Normal file
23
app/models/activity_pub/instance.rb
Normal file
|
@ -0,0 +1,23 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
# = Instance =
|
||||
#
|
||||
# Representa cada instancia del fediverso que interactúa con la Social
|
||||
# Inbox.
|
||||
class ActivityPub
|
||||
class Instance < ApplicationRecord
|
||||
include AASM
|
||||
|
||||
validates :aasm_state, presence: true, inclusion: { in: %w[paused allowed blocked] }
|
||||
validates :hostname, uniqueness: true, hostname: true
|
||||
|
||||
has_many :activity_pubs
|
||||
has_many :actors
|
||||
|
||||
aasm do
|
||||
state :paused, initial: true
|
||||
state :allowed
|
||||
state :blocked
|
||||
end
|
||||
end
|
||||
end
|
10
app/models/activity_pub/object.rb
Normal file
10
app/models/activity_pub/object.rb
Normal file
|
@ -0,0 +1,10 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
# Almacena objetos de ActivityPub, como Note, Article, etc.
|
||||
class ActivityPub
|
||||
class Object < ApplicationRecord
|
||||
include ActivityPub::Concerns::JsonLdConcern
|
||||
|
||||
has_many :activity_pubs, as: :object
|
||||
end
|
||||
end
|
10
app/models/activity_pub/object/application.rb
Normal file
10
app/models/activity_pub/object/application.rb
Normal file
|
@ -0,0 +1,10 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
# = Application =
|
||||
#
|
||||
# Una aplicación o instancia
|
||||
class ActivityPub
|
||||
class Object
|
||||
class Application < ActivityPub::Object; end
|
||||
end
|
||||
end
|
10
app/models/activity_pub/object/article.rb
Normal file
10
app/models/activity_pub/object/article.rb
Normal file
|
@ -0,0 +1,10 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
# = Article =
|
||||
#
|
||||
# Representa artículos
|
||||
class ActivityPub
|
||||
class Object
|
||||
class Article < ActivityPub::Object; end
|
||||
end
|
||||
end
|
8
app/models/activity_pub/object/generic.rb
Normal file
8
app/models/activity_pub/object/generic.rb
Normal file
|
@ -0,0 +1,8 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
# = Generic =
|
||||
class ActivityPub
|
||||
class Object
|
||||
class Generic < ActivityPub::Object; end
|
||||
end
|
||||
end
|
10
app/models/activity_pub/object/note.rb
Normal file
10
app/models/activity_pub/object/note.rb
Normal file
|
@ -0,0 +1,10 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
# = Note =
|
||||
#
|
||||
# Representa notas, el tipo más común de objeto del Fediverso.
|
||||
class ActivityPub
|
||||
class Object
|
||||
class Note < ActivityPub::Object; end
|
||||
end
|
||||
end
|
10
app/models/activity_pub/object/organization.rb
Normal file
10
app/models/activity_pub/object/organization.rb
Normal file
|
@ -0,0 +1,10 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
# = Organization =
|
||||
#
|
||||
# Una organización
|
||||
class ActivityPub
|
||||
class Object
|
||||
class Organization < ActivityPub::Object; end
|
||||
end
|
||||
end
|
10
app/models/activity_pub/object/person.rb
Normal file
10
app/models/activity_pub/object/person.rb
Normal file
|
@ -0,0 +1,10 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
# = Person =
|
||||
#
|
||||
# Una persona, el perfil de une actore
|
||||
class ActivityPub
|
||||
class Object
|
||||
class Person < ActivityPub::Object; end
|
||||
end
|
||||
end
|
|
@ -10,10 +10,12 @@ require 'open3'
|
|||
# :attributes`.
|
||||
class Deploy < ApplicationRecord
|
||||
belongs_to :site
|
||||
belongs_to :rol
|
||||
|
||||
has_many :build_stats, dependent: :destroy
|
||||
|
||||
DEPENDENCIES = []
|
||||
SOFT_DEPENDENCIES = []
|
||||
DEPENDENCIES = [].freeze
|
||||
SOFT_DEPENDENCIES = [].freeze
|
||||
|
||||
def deploy(**)
|
||||
raise NotImplementedError
|
||||
|
@ -72,7 +74,7 @@ class Deploy < ApplicationRecord
|
|||
'HOME' => home_dir,
|
||||
'PATH' => paths.join(':'),
|
||||
'JEKYLL_ENV' => Rails.env,
|
||||
'LANG' => ENV['LANG'],
|
||||
'LANG' => ENV.fetch('LANG', nil)
|
||||
})
|
||||
end
|
||||
|
||||
|
@ -137,7 +139,7 @@ class Deploy < ApplicationRecord
|
|||
# provisto con el archivo como parámetro
|
||||
#
|
||||
# @param :content [String]
|
||||
def with_tempfile(content, &block)
|
||||
def with_tempfile(content)
|
||||
Tempfile.create(SecureRandom.hex) do |file|
|
||||
file.write content.to_s
|
||||
file.rewind
|
||||
|
|
|
@ -5,7 +5,9 @@ require 'distributed_press/v1/social/client'
|
|||
# Publicar novedades al Fediverso
|
||||
class DeploySocialDistributedPress < Deploy
|
||||
# Solo luego de publicar remotamente
|
||||
DEPENDENCIES = %i[deploy_distributed_press deploy_rsync deploy_full_rsync]
|
||||
DEPENDENCIES = %i[deploy_distributed_press deploy_rsync deploy_full_rsync].freeze
|
||||
|
||||
after_save :create_hooks!
|
||||
|
||||
# Envía las notificaciones
|
||||
def deploy(output: false)
|
||||
|
@ -52,4 +54,45 @@ class DeploySocialDistributedPress < Deploy
|
|||
def flags_for_build(**args)
|
||||
"--key #{Shellwords.escape args[:private_key].path}"
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Obtiene el hostname de la API de Sutty
|
||||
#
|
||||
# @return [String]
|
||||
def api_hostname
|
||||
Rails.application.routes.default_url_options[:host].sub('panel', 'api')
|
||||
end
|
||||
|
||||
# Crea los hooks en la Social Inbox para que nos avise de actividades
|
||||
# nuevas
|
||||
#
|
||||
# @return [nil]
|
||||
def create_hooks!
|
||||
hook_client = site.social_inbox.hook
|
||||
webhook_class = DistributedPress::V1::Social::Schemas::Webhook
|
||||
|
||||
hook_client.class::EVENTS.each do |event|
|
||||
event_url = :"v1_site_webhooks_social_inbox_#{event}_url"
|
||||
|
||||
webhook =
|
||||
webhook_class.new.call({
|
||||
method: 'POST',
|
||||
url: Rails.application.routes.url_helpers.public_send(
|
||||
event_url, site_id: site.name, host: api_hostname
|
||||
),
|
||||
headers: {
|
||||
'X-Social-Inbox': rol.token
|
||||
}
|
||||
})
|
||||
|
||||
raise ArgumentError, webhook.errors.messages if webhook.failure?
|
||||
|
||||
response = hook_client.put(event: event, hook: webhook)
|
||||
|
||||
raise ArgumentError, response.parsed_body unless response.ok?
|
||||
rescue ArgumentError => e
|
||||
ExceptionNotifier.notify_exception(e, data: { site_id: site.name, usuarie_id: rol.usuarie_id })
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -11,6 +11,7 @@ class Rol < ApplicationRecord
|
|||
|
||||
belongs_to :usuarie
|
||||
belongs_to :site
|
||||
has_many :deploys
|
||||
|
||||
validates_inclusion_of :rol, in: ROLES
|
||||
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'distributed_press/v1/social/client'
|
||||
|
||||
class Site
|
||||
# Agrega soporte para Social Distributed Press en los sitios
|
||||
module SocialDistributedPress
|
||||
|
@ -8,15 +10,25 @@ class Site
|
|||
included do
|
||||
encrypts :private_key_pem
|
||||
|
||||
has_many :activity_pubs
|
||||
|
||||
before_save :generate_private_key_pem!, unless: :private_key_pem?
|
||||
|
||||
# @return [SocialInbox]
|
||||
def social_inbox
|
||||
@social_inbox ||= SocialInbox.new(site: self)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Genera la llave privada y la almacena
|
||||
#
|
||||
# @return [nil]
|
||||
def generate_private_key_pem!
|
||||
self.private_key_pem ||= ::DistributedPress::V1::Social::Client.new(public_key_url: nil, key_size: 2048).private_key.export
|
||||
self.private_key_pem ||= DistributedPress::V1::Social::Client.new(
|
||||
public_key_url: nil,
|
||||
key_size: 2048
|
||||
).private_key.export
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
74
app/models/social_inbox.rb
Normal file
74
app/models/social_inbox.rb
Normal file
|
@ -0,0 +1,74 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'distributed_press/v1/social/client'
|
||||
require 'distributed_press/v1/social/hook'
|
||||
require 'distributed_press/v1/social/dereferencer'
|
||||
|
||||
# Gestiona la Social Inbox de un sitio
|
||||
class SocialInbox
|
||||
# @return [Site]
|
||||
attr_reader :site
|
||||
|
||||
# @param :site [Site]
|
||||
def initialize(site:)
|
||||
@site = site
|
||||
end
|
||||
|
||||
# @return [String]
|
||||
def actor
|
||||
@actor ||=
|
||||
begin
|
||||
user = site.config.dig('activity_pub', 'username')
|
||||
user ||= hostname.split('.', 2).first
|
||||
|
||||
"@#{user}@#{hostname}"
|
||||
end
|
||||
end
|
||||
|
||||
def actor_id
|
||||
@actor_id ||= generate_uri do |uri|
|
||||
uri.path = '/about.jsonld'
|
||||
end
|
||||
end
|
||||
|
||||
# @return [DistributedPress::V1::Social::Client]
|
||||
def client
|
||||
@client ||= DistributedPress::V1::Social::Client.new(
|
||||
url: site.config.dig('activity_pub', 'url'),
|
||||
public_key_url: public_key_url,
|
||||
private_key_pem: site.private_key_pem,
|
||||
logger: Rails.logger,
|
||||
cache_store: :redis
|
||||
)
|
||||
end
|
||||
|
||||
# @return [DistributedPress::V1::Social::Dereferencer]
|
||||
def dereferencer
|
||||
@dereferencer ||= DistributedPress::V1::Social::Dereferencer.new(client: client)
|
||||
end
|
||||
|
||||
# @return [DistributedPress::V1::Social::Hook]
|
||||
def hook
|
||||
@hook ||= DistributedPress::V1::Social::Hook.new(client: client, actor: actor)
|
||||
end
|
||||
|
||||
# @return [String]
|
||||
def public_key_url
|
||||
@public_key_url ||= generate_uri do |uri|
|
||||
uri.path = '/about.jsonld'
|
||||
uri.fragment = 'main-key'
|
||||
end
|
||||
end
|
||||
|
||||
def hostname
|
||||
@hostname ||=
|
||||
site.config.dig('activity_pub', 'hostname') || site.hostname
|
||||
end
|
||||
|
||||
# Genera una URI dentro de este sitio
|
||||
#
|
||||
# @return [String]
|
||||
def generate_uri(&block)
|
||||
@public_key_url ||= URI("https://#{hostname}").tap(&block).to_s
|
||||
end
|
||||
end
|
|
@ -2,6 +2,10 @@
|
|||
|
||||
require_relative 'boot'
|
||||
|
||||
require 'aasm'
|
||||
require 'redis-client'
|
||||
require 'hiredis-client'
|
||||
require 'brs'
|
||||
require 'rails'
|
||||
# Pick the frameworks you want:
|
||||
require 'active_model/railtie'
|
||||
|
|
|
@ -18,7 +18,15 @@ Rails.application.routes.draw do
|
|||
get :'contact/cookie', to: 'invitades#contact_cookie'
|
||||
post :'contact/:form', to: 'contact#receive', as: :contact
|
||||
|
||||
post :'webhooks/pull', to: 'webhooks#pull'
|
||||
namespace :webhooks do
|
||||
post :pull, to: 'pull#pull'
|
||||
|
||||
scope :social_inbox do
|
||||
post :moderationqueued, to: 'social_inbox#moderationqueued'
|
||||
post :onapproved, to: 'social_inbox#onapproved'
|
||||
post :onrejected, to: 'social_inbox#onrejected'
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
18
db/migrate/20240216170202_add_rol_to_deploys.rb
Normal file
18
db/migrate/20240216170202_add_rol_to_deploys.rb
Normal file
|
@ -0,0 +1,18 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
# Establece una relación entre roles y deploys
|
||||
class AddRolToDeploys < ActiveRecord::Migration[6.1]
|
||||
def up
|
||||
add_column :deploys, :rol_id, :integer, index: true
|
||||
|
||||
Deploy.find_each do |deploy|
|
||||
rol_id = deploy.site.roles.find_by(rol: 'usuarie', temporal: false).id
|
||||
|
||||
deploy.update_column(:rol_id, rol_id) if rol_id
|
||||
end
|
||||
end
|
||||
|
||||
def down
|
||||
remove_column :deploys, :rol_id
|
||||
end
|
||||
end
|
16
db/migrate/20240219153919_create_activity_pub_activities.rb
Normal file
16
db/migrate/20240219153919_create_activity_pub_activities.rb
Normal file
|
@ -0,0 +1,16 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
# Actividades. Se asocian a un objeto y a una cola de moderación
|
||||
class CreateActivityPubActivities < ActiveRecord::Migration[6.1]
|
||||
def change
|
||||
create_table :activity_pub_activities, id: :uuid do |t|
|
||||
t.timestamps
|
||||
|
||||
t.uuid :activity_pub_id, index: true, null: false
|
||||
|
||||
t.string :type, null: false
|
||||
t.string :uri, null: false
|
||||
t.jsonb :content, default: {}
|
||||
end
|
||||
end
|
||||
end
|
12
db/migrate/20240219175839_create_activity_pub_actors.rb
Normal file
12
db/migrate/20240219175839_create_activity_pub_actors.rb
Normal file
|
@ -0,0 +1,12 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
# Almacena actores de ActivityPub y los relaciona con actividades
|
||||
class CreateActivityPubActors < ActiveRecord::Migration[6.1]
|
||||
def change
|
||||
create_table :activity_pub_actors, id: :uuid do |t|
|
||||
t.timestamps
|
||||
t.uuid :instance_id, index: true, null: false
|
||||
t.string :uri, index: true, unique: true, null: false
|
||||
end
|
||||
end
|
||||
end
|
18
db/migrate/20240219204011_create_activity_pubs.rb
Normal file
18
db/migrate/20240219204011_create_activity_pubs.rb
Normal file
|
@ -0,0 +1,18 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
# Registro de actividades.
|
||||
class CreateActivityPubs < ActiveRecord::Migration[6.1]
|
||||
def change
|
||||
create_table :activity_pubs, id: :uuid do |t|
|
||||
t.timestamps
|
||||
|
||||
t.bigint :site_id, null: false
|
||||
t.uuid :object_id, null: false
|
||||
t.string :object_type, null: false
|
||||
|
||||
t.string :aasm_state, null: false
|
||||
|
||||
t.index %i[site_id object_id object_type], unique: true
|
||||
end
|
||||
end
|
||||
end
|
17
db/migrate/20240219204224_create_activity_pub_objects.rb
Normal file
17
db/migrate/20240219204224_create_activity_pub_objects.rb
Normal file
|
@ -0,0 +1,17 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
# Almacena objetos de ActivityPub. Los objetos pueden estar compartidos
|
||||
# por toda la instancia.
|
||||
class CreateActivityPubObjects < ActiveRecord::Migration[6.1]
|
||||
def change
|
||||
create_table :activity_pub_objects, id: :uuid do |t|
|
||||
t.timestamps
|
||||
|
||||
t.uuid :actor_id, index: true, null: false
|
||||
|
||||
t.string :type, null: false
|
||||
t.string :uri, null: false, unique: true
|
||||
t.jsonb :content, default: {}
|
||||
end
|
||||
end
|
||||
end
|
13
db/migrate/20240220161414_create_activity_pub_instances.rb
Normal file
13
db/migrate/20240220161414_create_activity_pub_instances.rb
Normal file
|
@ -0,0 +1,13 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
# Almacena las instancias
|
||||
class CreateActivityPubInstances < ActiveRecord::Migration[6.1]
|
||||
def change
|
||||
create_table :activity_pub_instances, id: :uuid do |t|
|
||||
t.timestamps
|
||||
t.string :hostname, index: true, unique: true, null: false
|
||||
t.string :aasm_state, null: false
|
||||
t.jsonb :content, default: {}
|
||||
end
|
||||
end
|
||||
end
|
12
db/migrate/20240221184007_remove_actor_from_objects.rb
Normal file
12
db/migrate/20240221184007_remove_actor_from_objects.rb
Normal file
|
@ -0,0 +1,12 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
# No es necesario vincular actores con objetos, porque la forma en que
|
||||
# lo estábamos haciendo no se refiere a le actore del objeto, sino de
|
||||
# acciones distintas sobre el mismo objeto, generado por une actore.
|
||||
#
|
||||
# Y ese valor ya lo podemos obtener desde attributedTo
|
||||
class RemoveActorFromObjects < ActiveRecord::Migration[6.1]
|
||||
def change
|
||||
remove_column :activity_pub_objects, :actor_id, :uuid, index: true
|
||||
end
|
||||
end
|
158
db/structure.sql
158
db/structure.sql
|
@ -494,6 +494,77 @@ CREATE SEQUENCE public.active_storage_variant_records_id_seq
|
|||
ALTER SEQUENCE public.active_storage_variant_records_id_seq OWNED BY public.active_storage_variant_records.id;
|
||||
|
||||
|
||||
--
|
||||
-- Name: activity_pub_activities; Type: TABLE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE TABLE public.activity_pub_activities (
|
||||
id uuid DEFAULT gen_random_uuid() NOT NULL,
|
||||
created_at timestamp(6) without time zone NOT NULL,
|
||||
updated_at timestamp(6) without time zone NOT NULL,
|
||||
activity_pub_id uuid NOT NULL,
|
||||
type character varying NOT NULL,
|
||||
uri character varying NOT NULL,
|
||||
content jsonb DEFAULT '{}'::jsonb
|
||||
);
|
||||
|
||||
|
||||
--
|
||||
-- Name: activity_pub_actors; Type: TABLE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE TABLE public.activity_pub_actors (
|
||||
id uuid DEFAULT gen_random_uuid() NOT NULL,
|
||||
created_at timestamp(6) without time zone NOT NULL,
|
||||
updated_at timestamp(6) without time zone NOT NULL,
|
||||
instance_id uuid NOT NULL,
|
||||
uri character varying NOT NULL
|
||||
);
|
||||
|
||||
|
||||
--
|
||||
-- Name: activity_pub_instances; Type: TABLE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE TABLE public.activity_pub_instances (
|
||||
id uuid DEFAULT gen_random_uuid() NOT NULL,
|
||||
created_at timestamp(6) without time zone NOT NULL,
|
||||
updated_at timestamp(6) without time zone NOT NULL,
|
||||
hostname character varying NOT NULL,
|
||||
aasm_state character varying NOT NULL,
|
||||
content jsonb DEFAULT '{}'::jsonb
|
||||
);
|
||||
|
||||
|
||||
--
|
||||
-- Name: activity_pub_objects; Type: TABLE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE TABLE public.activity_pub_objects (
|
||||
id uuid DEFAULT gen_random_uuid() NOT NULL,
|
||||
created_at timestamp(6) without time zone NOT NULL,
|
||||
updated_at timestamp(6) without time zone NOT NULL,
|
||||
type character varying NOT NULL,
|
||||
uri character varying NOT NULL,
|
||||
content jsonb DEFAULT '{}'::jsonb
|
||||
);
|
||||
|
||||
|
||||
--
|
||||
-- Name: activity_pubs; Type: TABLE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE TABLE public.activity_pubs (
|
||||
id uuid DEFAULT gen_random_uuid() NOT NULL,
|
||||
created_at timestamp(6) without time zone NOT NULL,
|
||||
updated_at timestamp(6) without time zone NOT NULL,
|
||||
site_id bigint NOT NULL,
|
||||
object_id uuid NOT NULL,
|
||||
object_type character varying NOT NULL,
|
||||
aasm_state character varying NOT NULL
|
||||
);
|
||||
|
||||
|
||||
--
|
||||
-- Name: ar_internal_metadata; Type: TABLE; Schema: public; Owner: -
|
||||
--
|
||||
|
@ -780,7 +851,8 @@ CREATE TABLE public.deploys (
|
|||
updated_at timestamp without time zone NOT NULL,
|
||||
site_id integer,
|
||||
type character varying,
|
||||
"values" text
|
||||
"values" text,
|
||||
rol_id integer
|
||||
);
|
||||
|
||||
|
||||
|
@ -1585,6 +1657,46 @@ ALTER TABLE ONLY public.active_storage_variant_records
|
|||
ADD CONSTRAINT active_storage_variant_records_pkey PRIMARY KEY (id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: activity_pub_activities activity_pub_activities_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.activity_pub_activities
|
||||
ADD CONSTRAINT activity_pub_activities_pkey PRIMARY KEY (id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: activity_pub_actors activity_pub_actors_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.activity_pub_actors
|
||||
ADD CONSTRAINT activity_pub_actors_pkey PRIMARY KEY (id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: activity_pub_instances activity_pub_instances_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.activity_pub_instances
|
||||
ADD CONSTRAINT activity_pub_instances_pkey PRIMARY KEY (id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: activity_pub_objects activity_pub_objects_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.activity_pub_objects
|
||||
ADD CONSTRAINT activity_pub_objects_pkey PRIMARY KEY (id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: activity_pubs activity_pubs_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.activity_pubs
|
||||
ADD CONSTRAINT activity_pubs_pkey PRIMARY KEY (id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: blazer_audits blazer_audits_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
@ -1885,6 +1997,41 @@ CREATE UNIQUE INDEX index_active_storage_blobs_on_key_and_service_name ON public
|
|||
CREATE UNIQUE INDEX index_active_storage_variant_records_uniqueness ON public.active_storage_variant_records USING btree (blob_id, variation_digest);
|
||||
|
||||
|
||||
--
|
||||
-- Name: index_activity_pub_activities_on_activity_pub_id; Type: INDEX; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE INDEX index_activity_pub_activities_on_activity_pub_id ON public.activity_pub_activities USING btree (activity_pub_id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: index_activity_pub_actors_on_instance_id; Type: INDEX; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE INDEX index_activity_pub_actors_on_instance_id ON public.activity_pub_actors USING btree (instance_id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: index_activity_pub_actors_on_uri; Type: INDEX; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE INDEX index_activity_pub_actors_on_uri ON public.activity_pub_actors USING btree (uri);
|
||||
|
||||
|
||||
--
|
||||
-- Name: index_activity_pub_instances_on_hostname; Type: INDEX; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE INDEX index_activity_pub_instances_on_hostname ON public.activity_pub_instances USING btree (hostname);
|
||||
|
||||
|
||||
--
|
||||
-- Name: index_activity_pubs_on_site_id_and_object_id_and_object_type; Type: INDEX; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE UNIQUE INDEX index_activity_pubs_on_site_id_and_object_id_and_object_type ON public.activity_pubs USING btree (site_id, object_id, object_type);
|
||||
|
||||
|
||||
--
|
||||
-- Name: index_blazer_audits_on_query_id; Type: INDEX; Schema: public; Owner: -
|
||||
--
|
||||
|
@ -2346,6 +2493,13 @@ INSERT INTO "schema_migrations" (version) VALUES
|
|||
('20230731195050'),
|
||||
('20230829204127'),
|
||||
('20230921155401'),
|
||||
('20230927153926');
|
||||
('20230927153926'),
|
||||
('20240216170202'),
|
||||
('20240219153919'),
|
||||
('20240219175839'),
|
||||
('20240219204011'),
|
||||
('20240219204224'),
|
||||
('20240220161414'),
|
||||
('20240221184007');
|
||||
|
||||
|
||||
|
|
Loading…
Reference in a new issue