mirror of
https://0xacab.org/sutty/sutty
synced 2024-11-17 02:46:22 +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'
|
||||||
gem 'devise-i18n'
|
gem 'devise-i18n'
|
||||||
gem 'devise_invitable'
|
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 'email_address', git: 'https://github.com/fauno/email_address', branch: 'i18n'
|
||||||
gem 'exception_notification'
|
gem 'exception_notification'
|
||||||
gem 'fast_blank'
|
gem 'fast_blank'
|
||||||
|
@ -65,6 +67,7 @@ gem 'redis', '~> 4.0', require: %w[redis redis/connection/hiredis]
|
||||||
gem 'redis-rails'
|
gem 'redis-rails'
|
||||||
gem 'rollups', git: 'https://github.com/fauno/rollup.git', branch: 'update'
|
gem 'rollups', git: 'https://github.com/fauno/rollup.git', branch: 'update'
|
||||||
gem 'rubyzip'
|
gem 'rubyzip'
|
||||||
|
gem 'ruby-brs'
|
||||||
gem 'rugged', '1.5.0.1'
|
gem 'rugged', '1.5.0.1'
|
||||||
gem 'git_clone_url'
|
gem 'git_clone_url'
|
||||||
gem 'concurrent-ruby-ext'
|
gem 'concurrent-ruby-ext'
|
||||||
|
@ -77,6 +80,9 @@ gem 'yaml_db', git: 'https://0xacab.org/sutty/yaml_db.git'
|
||||||
gem 'kaminari'
|
gem 'kaminari'
|
||||||
gem 'device_detector'
|
gem 'device_detector'
|
||||||
|
|
||||||
|
gem 'after_commit_everywhere', '~> 1.0'
|
||||||
|
gem 'aasm'
|
||||||
|
|
||||||
# database
|
# database
|
||||||
gem 'hairtrigger'
|
gem 'hairtrigger'
|
||||||
gem 'pg'
|
gem 'pg'
|
||||||
|
|
254
Gemfile.lock
254
Gemfile.lock
|
@ -27,73 +27,80 @@ GIT
|
||||||
GEM
|
GEM
|
||||||
remote: https://17.3.alpine.gems.sutty.nl/
|
remote: https://17.3.alpine.gems.sutty.nl/
|
||||||
specs:
|
specs:
|
||||||
actioncable (6.1.7.3)
|
aasm (5.5.0)
|
||||||
actionpack (= 6.1.7.3)
|
concurrent-ruby (~> 1.0)
|
||||||
activesupport (= 6.1.7.3)
|
actioncable (6.1.7.4)
|
||||||
|
actionpack (= 6.1.7.4)
|
||||||
|
activesupport (= 6.1.7.4)
|
||||||
nio4r (~> 2.0)
|
nio4r (~> 2.0)
|
||||||
websocket-driver (>= 0.6.1)
|
websocket-driver (>= 0.6.1)
|
||||||
actionmailbox (6.1.7.3)
|
actionmailbox (6.1.7.4)
|
||||||
actionpack (= 6.1.7.3)
|
actionpack (= 6.1.7.4)
|
||||||
activejob (= 6.1.7.3)
|
activejob (= 6.1.7.4)
|
||||||
activerecord (= 6.1.7.3)
|
activerecord (= 6.1.7.4)
|
||||||
activestorage (= 6.1.7.3)
|
activestorage (= 6.1.7.4)
|
||||||
activesupport (= 6.1.7.3)
|
activesupport (= 6.1.7.4)
|
||||||
mail (>= 2.7.1)
|
mail (>= 2.7.1)
|
||||||
actionmailer (6.1.7.3)
|
actionmailer (6.1.7.4)
|
||||||
actionpack (= 6.1.7.3)
|
actionpack (= 6.1.7.4)
|
||||||
actionview (= 6.1.7.3)
|
actionview (= 6.1.7.4)
|
||||||
activejob (= 6.1.7.3)
|
activejob (= 6.1.7.4)
|
||||||
activesupport (= 6.1.7.3)
|
activesupport (= 6.1.7.4)
|
||||||
mail (~> 2.5, >= 2.5.4)
|
mail (~> 2.5, >= 2.5.4)
|
||||||
rails-dom-testing (~> 2.0)
|
rails-dom-testing (~> 2.0)
|
||||||
actionpack (6.1.7.3)
|
actionpack (6.1.7.4)
|
||||||
actionview (= 6.1.7.3)
|
actionview (= 6.1.7.4)
|
||||||
activesupport (= 6.1.7.3)
|
activesupport (= 6.1.7.4)
|
||||||
rack (~> 2.0, >= 2.0.9)
|
rack (~> 2.0, >= 2.0.9)
|
||||||
rack-test (>= 0.6.3)
|
rack-test (>= 0.6.3)
|
||||||
rails-dom-testing (~> 2.0)
|
rails-dom-testing (~> 2.0)
|
||||||
rails-html-sanitizer (~> 1.0, >= 1.2.0)
|
rails-html-sanitizer (~> 1.0, >= 1.2.0)
|
||||||
actiontext (6.1.7.3)
|
actiontext (6.1.7.4)
|
||||||
actionpack (= 6.1.7.3)
|
actionpack (= 6.1.7.4)
|
||||||
activerecord (= 6.1.7.3)
|
activerecord (= 6.1.7.4)
|
||||||
activestorage (= 6.1.7.3)
|
activestorage (= 6.1.7.4)
|
||||||
activesupport (= 6.1.7.3)
|
activesupport (= 6.1.7.4)
|
||||||
nokogiri (>= 1.8.5)
|
nokogiri (>= 1.8.5)
|
||||||
actionview (6.1.7.3)
|
actionview (6.1.7.4)
|
||||||
activesupport (= 6.1.7.3)
|
activesupport (= 6.1.7.4)
|
||||||
builder (~> 3.1)
|
builder (~> 3.1)
|
||||||
erubi (~> 1.4)
|
erubi (~> 1.4)
|
||||||
rails-dom-testing (~> 2.0)
|
rails-dom-testing (~> 2.0)
|
||||||
rails-html-sanitizer (~> 1.1, >= 1.2.0)
|
rails-html-sanitizer (~> 1.1, >= 1.2.0)
|
||||||
activejob (6.1.7.3)
|
activejob (6.1.7.4)
|
||||||
activesupport (= 6.1.7.3)
|
activesupport (= 6.1.7.4)
|
||||||
globalid (>= 0.3.6)
|
globalid (>= 0.3.6)
|
||||||
activemodel (6.1.7.3)
|
activemodel (6.1.7.4)
|
||||||
activesupport (= 6.1.7.3)
|
activesupport (= 6.1.7.4)
|
||||||
activerecord (6.1.7.3)
|
activerecord (6.1.7.4)
|
||||||
activemodel (= 6.1.7.3)
|
activemodel (= 6.1.7.4)
|
||||||
activesupport (= 6.1.7.3)
|
activesupport (= 6.1.7.4)
|
||||||
activestorage (6.1.7.3)
|
activestorage (6.1.7.4)
|
||||||
actionpack (= 6.1.7.3)
|
actionpack (= 6.1.7.4)
|
||||||
activejob (= 6.1.7.3)
|
activejob (= 6.1.7.4)
|
||||||
activerecord (= 6.1.7.3)
|
activerecord (= 6.1.7.4)
|
||||||
activesupport (= 6.1.7.3)
|
activesupport (= 6.1.7.4)
|
||||||
marcel (~> 1.0)
|
marcel (~> 1.0)
|
||||||
mini_mime (>= 1.1.0)
|
mini_mime (>= 1.1.0)
|
||||||
activesupport (6.1.7.3)
|
activesupport (6.1.7.4)
|
||||||
concurrent-ruby (~> 1.0, >= 1.0.2)
|
concurrent-ruby (~> 1.0, >= 1.0.2)
|
||||||
i18n (>= 1.6, < 2)
|
i18n (>= 1.6, < 2)
|
||||||
minitest (>= 5.1)
|
minitest (>= 5.1)
|
||||||
tzinfo (~> 2.0)
|
tzinfo (~> 2.0)
|
||||||
zeitwerk (~> 2.3)
|
zeitwerk (~> 2.3)
|
||||||
addressable (2.8.4)
|
addressable (2.8.6)
|
||||||
public_suffix (>= 2.0.2, < 6.0)
|
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)
|
ast (2.4.2)
|
||||||
autoprefixer-rails (10.4.13.0)
|
autoprefixer-rails (10.4.13.0)
|
||||||
execjs (~> 2)
|
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)
|
bcrypt_pbkdf (1.1.0-x86_64-linux-musl)
|
||||||
benchmark-ips (2.12.0)
|
benchmark-ips (2.12.0)
|
||||||
|
bigdecimal (3.1.1)
|
||||||
bindex (0.8.1-x86_64-linux-musl)
|
bindex (0.8.1-x86_64-linux-musl)
|
||||||
blazer (2.6.5)
|
blazer (2.6.5)
|
||||||
activerecord (>= 5)
|
activerecord (>= 5)
|
||||||
|
@ -104,7 +111,8 @@ GEM
|
||||||
autoprefixer-rails (>= 9.1.0)
|
autoprefixer-rails (>= 9.1.0)
|
||||||
popper_js (>= 1.16.1, < 2)
|
popper_js (>= 1.16.1, < 2)
|
||||||
sassc-rails (>= 2.0.0)
|
sassc-rails (>= 2.0.0)
|
||||||
brakeman (5.4.1)
|
brakeman (6.1.1)
|
||||||
|
racc
|
||||||
builder (3.2.4)
|
builder (3.2.4)
|
||||||
bundler-audit (0.9.1)
|
bundler-audit (0.9.1)
|
||||||
bundler (>= 1.2.0, < 3)
|
bundler (>= 1.2.0, < 3)
|
||||||
|
@ -125,6 +133,7 @@ GEM
|
||||||
concurrent-ruby (1.2.2)
|
concurrent-ruby (1.2.2)
|
||||||
concurrent-ruby-ext (1.2.2-x86_64-linux-musl)
|
concurrent-ruby-ext (1.2.2-x86_64-linux-musl)
|
||||||
concurrent-ruby (= 1.2.2)
|
concurrent-ruby (= 1.2.2)
|
||||||
|
connection_pool (2.4.1)
|
||||||
crass (1.0.6)
|
crass (1.0.6)
|
||||||
database_cleaner (2.0.2)
|
database_cleaner (2.0.2)
|
||||||
database_cleaner-active_record (>= 2, < 3)
|
database_cleaner-active_record (>= 2, < 3)
|
||||||
|
@ -132,7 +141,7 @@ GEM
|
||||||
activerecord (>= 5.a)
|
activerecord (>= 5.a)
|
||||||
database_cleaner-core (~> 2.0.0)
|
database_cleaner-core (~> 2.0.0)
|
||||||
database_cleaner-core (2.0.1)
|
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)
|
dead_end (4.0.0)
|
||||||
derailed_benchmarks (2.1.2)
|
derailed_benchmarks (2.1.2)
|
||||||
benchmark-ips (~> 2)
|
benchmark-ips (~> 2)
|
||||||
|
@ -146,8 +155,8 @@ GEM
|
||||||
rake (> 10, < 14)
|
rake (> 10, < 14)
|
||||||
ruby-statistics (>= 2.1)
|
ruby-statistics (>= 2.1)
|
||||||
thor (>= 0.19, < 2)
|
thor (>= 0.19, < 2)
|
||||||
device_detector (1.1.1)
|
device_detector (1.1.2)
|
||||||
devise (4.9.2)
|
devise (4.9.3)
|
||||||
bcrypt (~> 3.0)
|
bcrypt (~> 3.0)
|
||||||
orm_adapter (~> 0.1)
|
orm_adapter (~> 0.1)
|
||||||
railties (>= 4.1.0)
|
railties (>= 4.1.0)
|
||||||
|
@ -155,14 +164,15 @@ GEM
|
||||||
warden (~> 1.2.3)
|
warden (~> 1.2.3)
|
||||||
devise-i18n (1.11.0)
|
devise-i18n (1.11.0)
|
||||||
devise (>= 4.9.0)
|
devise (>= 4.9.0)
|
||||||
devise_invitable (2.0.8)
|
devise_invitable (2.0.9)
|
||||||
actionmailer (>= 5.0)
|
actionmailer (>= 5.0)
|
||||||
devise (>= 4.6)
|
devise (>= 4.6)
|
||||||
distributed-press-api-client (0.3.0rc0)
|
distributed-press-api-client (0.4.0rc2)
|
||||||
addressable (~> 2.3, >= 2.3.0)
|
addressable (~> 2.3, >= 2.3.0)
|
||||||
climate_control
|
climate_control
|
||||||
dry-schema
|
dry-schema
|
||||||
httparty (~> 0.18)
|
httparty (~> 0.18)
|
||||||
|
httparty-cache (~> 0.0.4)
|
||||||
json (~> 2.1, >= 2.1.0)
|
json (~> 2.1, >= 2.1.0)
|
||||||
jwt (~> 2.6.0)
|
jwt (~> 2.6.0)
|
||||||
dotenv (2.8.1)
|
dotenv (2.8.1)
|
||||||
|
@ -171,10 +181,10 @@ GEM
|
||||||
railties (>= 3.2)
|
railties (>= 3.2)
|
||||||
down (5.4.1)
|
down (5.4.1)
|
||||||
addressable (~> 2.8)
|
addressable (~> 2.8)
|
||||||
dry-configurable (1.0.1)
|
dry-configurable (1.1.0)
|
||||||
dry-core (~> 1.0, < 2)
|
dry-core (~> 1.0, < 2)
|
||||||
zeitwerk (~> 2.6)
|
zeitwerk (~> 2.6)
|
||||||
dry-core (1.0.0)
|
dry-core (1.0.1)
|
||||||
concurrent-ruby (~> 1.0)
|
concurrent-ruby (~> 1.0)
|
||||||
zeitwerk (~> 2.6)
|
zeitwerk (~> 2.6)
|
||||||
dry-inflector (1.0.0)
|
dry-inflector (1.0.0)
|
||||||
|
@ -183,7 +193,7 @@ GEM
|
||||||
concurrent-ruby (~> 1.0)
|
concurrent-ruby (~> 1.0)
|
||||||
dry-core (~> 1.0, < 2)
|
dry-core (~> 1.0, < 2)
|
||||||
zeitwerk (~> 2.6)
|
zeitwerk (~> 2.6)
|
||||||
dry-schema (1.13.1)
|
dry-schema (1.13.3)
|
||||||
concurrent-ruby (~> 1.0)
|
concurrent-ruby (~> 1.0)
|
||||||
dry-configurable (~> 1.0, >= 1.0.1)
|
dry-configurable (~> 1.0, >= 1.0.1)
|
||||||
dry-core (~> 1.0, < 2)
|
dry-core (~> 1.0, < 2)
|
||||||
|
@ -191,7 +201,8 @@ GEM
|
||||||
dry-logic (>= 1.4, < 2)
|
dry-logic (>= 1.4, < 2)
|
||||||
dry-types (>= 1.7, < 2)
|
dry-types (>= 1.7, < 2)
|
||||||
zeitwerk (~> 2.6)
|
zeitwerk (~> 2.6)
|
||||||
dry-types (1.7.1)
|
dry-types (1.7.2)
|
||||||
|
bigdecimal (~> 3.0)
|
||||||
concurrent-ruby (~> 1.0)
|
concurrent-ruby (~> 1.0)
|
||||||
dry-core (~> 1.0)
|
dry-core (~> 1.0)
|
||||||
dry-inflector (~> 1.0)
|
dry-inflector (~> 1.0)
|
||||||
|
@ -224,25 +235,25 @@ GEM
|
||||||
ffi (~> 1.0)
|
ffi (~> 1.0)
|
||||||
git_clone_url (2.0.0)
|
git_clone_url (2.0.0)
|
||||||
uri-ssh_git (>= 2.0)
|
uri-ssh_git (>= 2.0)
|
||||||
globalid (1.1.0)
|
globalid (1.2.1)
|
||||||
activesupport (>= 5.0)
|
activesupport (>= 6.1)
|
||||||
groupdate (6.2.1)
|
groupdate (6.2.1)
|
||||||
activesupport (>= 5.2)
|
activesupport (>= 5.2)
|
||||||
hairtrigger (1.0.0)
|
hairtrigger (1.0.0)
|
||||||
activerecord (>= 6.0, < 8)
|
activerecord (>= 6.0, < 8)
|
||||||
ruby2ruby (~> 2.4)
|
ruby2ruby (~> 2.4)
|
||||||
ruby_parser (~> 3.10)
|
ruby_parser (~> 3.10)
|
||||||
haml (6.1.2-x86_64-linux-musl)
|
haml (6.3.0)
|
||||||
temple (>= 0.8.2)
|
temple (>= 0.8.2)
|
||||||
thor
|
thor
|
||||||
tilt
|
tilt
|
||||||
haml-lint (0.999.999)
|
haml-lint (0.999.999)
|
||||||
haml_lint
|
haml_lint
|
||||||
haml_lint (0.45.0)
|
haml_lint (0.53.0)
|
||||||
haml (>= 4.0, < 6.2)
|
haml (>= 5.0)
|
||||||
parallel (~> 1.10)
|
parallel (~> 1.10)
|
||||||
rainbow
|
rainbow
|
||||||
rubocop (>= 0.50.0)
|
rubocop (>= 1.0)
|
||||||
sysexits (~> 1.1)
|
sysexits (~> 1.1)
|
||||||
hamlit (3.0.3-x86_64-linux-musl)
|
hamlit (3.0.3-x86_64-linux-musl)
|
||||||
temple (>= 0.8.2)
|
temple (>= 0.8.2)
|
||||||
|
@ -256,10 +267,14 @@ GEM
|
||||||
heapy (0.2.0)
|
heapy (0.2.0)
|
||||||
thor
|
thor
|
||||||
hiredis (0.6.3-x86_64-linux-musl)
|
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)
|
http_parser.rb (0.8.0-x86_64-linux-musl)
|
||||||
httparty (0.21.0)
|
httparty (0.21.0)
|
||||||
mini_mime (>= 1.0.0)
|
mini_mime (>= 1.0.0)
|
||||||
multi_xml (>= 0.5.2)
|
multi_xml (>= 0.5.2)
|
||||||
|
httparty-cache (0.0.4)
|
||||||
|
httparty (~> 0.18)
|
||||||
i18n (1.14.1)
|
i18n (1.14.1)
|
||||||
concurrent-ruby (~> 1.0)
|
concurrent-ruby (~> 1.0)
|
||||||
icalendar (2.8.0)
|
icalendar (2.8.0)
|
||||||
|
@ -291,7 +306,7 @@ GEM
|
||||||
terminal-table (~> 2.0)
|
terminal-table (~> 2.0)
|
||||||
jekyll-commonmark (1.4.0)
|
jekyll-commonmark (1.4.0)
|
||||||
commonmarker (~> 0.22)
|
commonmarker (~> 0.22)
|
||||||
jekyll-images (0.4.1)
|
jekyll-images (0.4.4)
|
||||||
jekyll (~> 4)
|
jekyll (~> 4)
|
||||||
ruby-filemagic (~> 0.7)
|
ruby-filemagic (~> 0.7)
|
||||||
ruby-vips (~> 2)
|
ruby-vips (~> 2)
|
||||||
|
@ -301,7 +316,7 @@ GEM
|
||||||
sassc (> 2.0.1, < 3.0)
|
sassc (> 2.0.1, < 3.0)
|
||||||
jekyll-watch (2.2.1)
|
jekyll-watch (2.2.1)
|
||||||
listen (~> 3.0)
|
listen (~> 3.0)
|
||||||
json (2.6.3-x86_64-linux-musl)
|
json (2.7.1-x86_64-linux-musl)
|
||||||
jwt (2.6.0)
|
jwt (2.6.0)
|
||||||
kaminari (1.2.2)
|
kaminari (1.2.2)
|
||||||
activesupport (>= 4.1.0)
|
activesupport (>= 4.1.0)
|
||||||
|
@ -330,12 +345,12 @@ GEM
|
||||||
loaf (0.10.0)
|
loaf (0.10.0)
|
||||||
railties (>= 3.2)
|
railties (>= 3.2)
|
||||||
lockbox (1.2.0)
|
lockbox (1.2.0)
|
||||||
lograge (0.12.0)
|
lograge (0.14.0)
|
||||||
actionpack (>= 4)
|
actionpack (>= 4)
|
||||||
activesupport (>= 4)
|
activesupport (>= 4)
|
||||||
railties (>= 4)
|
railties (>= 4)
|
||||||
request_store (~> 1.0)
|
request_store (~> 1.0)
|
||||||
loofah (2.21.3)
|
loofah (2.22.0)
|
||||||
crass (~> 1.0.2)
|
crass (~> 1.0.2)
|
||||||
nokogiri (>= 1.12.0)
|
nokogiri (>= 1.12.0)
|
||||||
mail (2.8.1)
|
mail (2.8.1)
|
||||||
|
@ -349,36 +364,37 @@ GEM
|
||||||
method_source (1.0.0)
|
method_source (1.0.0)
|
||||||
mini_histogram (0.3.1)
|
mini_histogram (0.3.1)
|
||||||
mini_magick (4.12.0)
|
mini_magick (4.12.0)
|
||||||
mini_mime (1.1.2)
|
mini_mime (1.1.5)
|
||||||
mini_portile2 (2.8.2)
|
mini_portile2 (2.8.5)
|
||||||
minitest (5.18.0)
|
minitest (5.21.1)
|
||||||
mobility (1.2.9)
|
mobility (1.2.9)
|
||||||
i18n (>= 0.6.10, < 2)
|
i18n (>= 0.6.10, < 2)
|
||||||
request_store (~> 1.0)
|
request_store (~> 1.0)
|
||||||
multi_xml (0.6.0)
|
multi_xml (0.6.0)
|
||||||
net-imap (0.3.4)
|
net-imap (0.4.9)
|
||||||
date
|
date
|
||||||
net-protocol
|
net-protocol
|
||||||
net-pop (0.1.2)
|
net-pop (0.1.2)
|
||||||
net-protocol
|
net-protocol
|
||||||
net-protocol (0.2.1)
|
net-protocol (0.2.2)
|
||||||
timeout
|
timeout
|
||||||
net-smtp (0.3.3)
|
net-smtp (0.4.0)
|
||||||
net-protocol
|
net-protocol
|
||||||
net-ssh (7.1.0)
|
net-ssh (7.2.1)
|
||||||
netaddr (2.0.6)
|
netaddr (2.0.6)
|
||||||
nio4r (2.5.9-x86_64-linux-musl)
|
nio4r (2.7.0-x86_64-linux-musl)
|
||||||
nokogiri (1.15.4-x86_64-linux-musl)
|
nokogiri (1.16.0-x86_64-linux-musl)
|
||||||
mini_portile2 (~> 2.8.2)
|
mini_portile2 (~> 2.8.2)
|
||||||
racc (~> 1.4)
|
racc (~> 1.4)
|
||||||
orm_adapter (0.5.0)
|
orm_adapter (0.5.0)
|
||||||
pairing_heap (3.0.1)
|
pairing_heap (3.0.1)
|
||||||
parallel (1.23.0)
|
parallel (1.24.0)
|
||||||
parser (3.2.2.1)
|
parser (3.2.2.3)
|
||||||
ast (~> 2.4.1)
|
ast (~> 2.4.1)
|
||||||
|
racc
|
||||||
pathutil (0.16.2)
|
pathutil (0.16.2)
|
||||||
forwardable-extended (~> 2.6)
|
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)
|
pg_search (2.3.6)
|
||||||
activerecord (>= 5.2)
|
activerecord (>= 5.2)
|
||||||
activesupport (>= 5.2)
|
activesupport (>= 5.2)
|
||||||
|
@ -388,55 +404,57 @@ GEM
|
||||||
pry (0.14.2)
|
pry (0.14.2)
|
||||||
coderay (~> 1.1)
|
coderay (~> 1.1)
|
||||||
method_source (~> 1.0)
|
method_source (~> 1.0)
|
||||||
public_suffix (5.0.3)
|
public_suffix (5.0.4)
|
||||||
puma (6.3.1-x86_64-linux-musl)
|
puma (6.4.2-x86_64-linux-musl)
|
||||||
nio4r (~> 2.0)
|
nio4r (~> 2.0)
|
||||||
pundit (2.3.0)
|
pundit (2.3.1)
|
||||||
activesupport (>= 3.0.0)
|
activesupport (>= 3.0.0)
|
||||||
que (2.2.1)
|
que (2.2.1)
|
||||||
racc (1.7.1-x86_64-linux-musl)
|
racc (1.7.3-x86_64-linux-musl)
|
||||||
rack (2.2.7)
|
rack (2.2.8)
|
||||||
rack-cors (2.0.1)
|
rack-cors (2.0.1)
|
||||||
rack (>= 2.0.0)
|
rack (>= 2.0.0)
|
||||||
rack-mini-profiler (3.1.0)
|
rack-mini-profiler (3.1.0)
|
||||||
rack (>= 1.2.0)
|
rack (>= 1.2.0)
|
||||||
rack-proxy (0.7.6)
|
rack-proxy (0.7.7)
|
||||||
rack
|
rack
|
||||||
rack-test (2.1.0)
|
rack-test (2.1.0)
|
||||||
rack (>= 1.3)
|
rack (>= 1.3)
|
||||||
rails (6.1.7.3)
|
rails (6.1.7.4)
|
||||||
actioncable (= 6.1.7.3)
|
actioncable (= 6.1.7.4)
|
||||||
actionmailbox (= 6.1.7.3)
|
actionmailbox (= 6.1.7.4)
|
||||||
actionmailer (= 6.1.7.3)
|
actionmailer (= 6.1.7.4)
|
||||||
actionpack (= 6.1.7.3)
|
actionpack (= 6.1.7.4)
|
||||||
actiontext (= 6.1.7.3)
|
actiontext (= 6.1.7.4)
|
||||||
actionview (= 6.1.7.3)
|
actionview (= 6.1.7.4)
|
||||||
activejob (= 6.1.7.3)
|
activejob (= 6.1.7.4)
|
||||||
activemodel (= 6.1.7.3)
|
activemodel (= 6.1.7.4)
|
||||||
activerecord (= 6.1.7.3)
|
activerecord (= 6.1.7.4)
|
||||||
activestorage (= 6.1.7.3)
|
activestorage (= 6.1.7.4)
|
||||||
activesupport (= 6.1.7.3)
|
activesupport (= 6.1.7.4)
|
||||||
bundler (>= 1.15.0)
|
bundler (>= 1.15.0)
|
||||||
railties (= 6.1.7.3)
|
railties (= 6.1.7.4)
|
||||||
sprockets-rails (>= 2.0.0)
|
sprockets-rails (>= 2.0.0)
|
||||||
rails-dom-testing (2.0.3)
|
rails-dom-testing (2.2.0)
|
||||||
activesupport (>= 4.2.0)
|
activesupport (>= 5.0.0)
|
||||||
|
minitest
|
||||||
nokogiri (>= 1.6)
|
nokogiri (>= 1.6)
|
||||||
rails-html-sanitizer (1.5.0)
|
rails-html-sanitizer (1.6.0)
|
||||||
loofah (~> 2.19, >= 2.19.1)
|
loofah (~> 2.21)
|
||||||
rails-i18n (7.0.7)
|
nokogiri (~> 1.14)
|
||||||
|
rails-i18n (7.0.8)
|
||||||
i18n (>= 0.7, < 2)
|
i18n (>= 0.7, < 2)
|
||||||
railties (>= 6.0.0, < 8)
|
railties (>= 6.0.0, < 8)
|
||||||
rails_warden (0.6.0)
|
rails_warden (0.6.0)
|
||||||
warden (>= 1.2.0)
|
warden (>= 1.2.0)
|
||||||
railties (6.1.7.3)
|
railties (6.1.7.4)
|
||||||
actionpack (= 6.1.7.3)
|
actionpack (= 6.1.7.4)
|
||||||
activesupport (= 6.1.7.3)
|
activesupport (= 6.1.7.4)
|
||||||
method_source
|
method_source
|
||||||
rake (>= 12.2)
|
rake (>= 12.2)
|
||||||
thor (~> 1.0)
|
thor (~> 1.0)
|
||||||
rainbow (3.1.1)
|
rainbow (3.1.1)
|
||||||
rake (13.0.6)
|
rake (13.1.0)
|
||||||
rb-fsevent (0.11.2)
|
rb-fsevent (0.11.2)
|
||||||
rb-inotify (0.10.1)
|
rb-inotify (0.10.1)
|
||||||
ffi (~> 1.0)
|
ffi (~> 1.0)
|
||||||
|
@ -448,6 +466,8 @@ GEM
|
||||||
redis-activesupport (5.3.0)
|
redis-activesupport (5.3.0)
|
||||||
activesupport (>= 3, < 8)
|
activesupport (>= 3, < 8)
|
||||||
redis-store (>= 1.3, < 2)
|
redis-store (>= 1.3, < 2)
|
||||||
|
redis-client (0.14.1)
|
||||||
|
connection_pool
|
||||||
redis-rack (2.1.4)
|
redis-rack (2.1.4)
|
||||||
rack (>= 2.0.8, < 3)
|
rack (>= 2.0.8, < 3)
|
||||||
redis-store (>= 1.2, < 2)
|
redis-store (>= 1.2, < 2)
|
||||||
|
@ -457,13 +477,13 @@ GEM
|
||||||
redis-store (>= 1.2, < 2)
|
redis-store (>= 1.2, < 2)
|
||||||
redis-store (1.9.2)
|
redis-store (1.9.2)
|
||||||
redis (>= 4, < 6)
|
redis (>= 4, < 6)
|
||||||
regexp_parser (2.8.0)
|
regexp_parser (2.9.0)
|
||||||
request_store (1.5.1)
|
request_store (1.5.1)
|
||||||
rack (>= 1.4)
|
rack (>= 1.4)
|
||||||
responders (3.1.0)
|
responders (3.1.1)
|
||||||
actionpack (>= 5.2)
|
actionpack (>= 5.2)
|
||||||
railties (>= 5.2)
|
railties (>= 5.2)
|
||||||
rexml (3.2.5)
|
rexml (3.2.6)
|
||||||
rgl (0.6.3)
|
rgl (0.6.3)
|
||||||
pairing_heap (>= 0.3.0)
|
pairing_heap (>= 0.3.0)
|
||||||
rexml (~> 3.2, >= 3.2.4)
|
rexml (~> 3.2, >= 3.2.4)
|
||||||
|
@ -479,16 +499,19 @@ GEM
|
||||||
rubocop-ast (>= 1.24.1, < 2.0)
|
rubocop-ast (>= 1.24.1, < 2.0)
|
||||||
ruby-progressbar (~> 1.7)
|
ruby-progressbar (~> 1.7)
|
||||||
unicode-display_width (>= 1.4.0, < 3.0)
|
unicode-display_width (>= 1.4.0, < 3.0)
|
||||||
rubocop-ast (1.28.1)
|
rubocop-ast (1.30.0)
|
||||||
parser (>= 3.2.1.0)
|
parser (>= 3.2.1.0)
|
||||||
rubocop-rails (2.19.1)
|
rubocop-rails (2.23.1)
|
||||||
activesupport (>= 4.2.0)
|
activesupport (>= 4.2.0)
|
||||||
rack (>= 1.1)
|
rack (>= 1.1)
|
||||||
rubocop (>= 1.33.0, < 2.0)
|
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-filemagic (0.7.3-x86_64-linux-musl)
|
||||||
ruby-progressbar (1.13.0)
|
ruby-progressbar (1.13.0)
|
||||||
ruby-statistics (3.0.2)
|
ruby-statistics (3.0.2)
|
||||||
ruby-vips (2.1.4)
|
ruby-vips (2.2.0)
|
||||||
ffi (~> 1.12)
|
ffi (~> 1.12)
|
||||||
ruby2ruby (2.5.0)
|
ruby2ruby (2.5.0)
|
||||||
ruby_parser (~> 3.1)
|
ruby_parser (~> 3.1)
|
||||||
|
@ -521,14 +544,14 @@ GEM
|
||||||
spring-watcher-listen (2.1.0)
|
spring-watcher-listen (2.1.0)
|
||||||
listen (>= 2.7, < 4.0)
|
listen (>= 2.7, < 4.0)
|
||||||
spring (>= 4)
|
spring (>= 4)
|
||||||
sprockets (4.2.0)
|
sprockets (4.2.1)
|
||||||
concurrent-ruby (~> 1.0)
|
concurrent-ruby (~> 1.0)
|
||||||
rack (>= 2.2.4, < 4)
|
rack (>= 2.2.4, < 4)
|
||||||
sprockets-rails (3.4.2)
|
sprockets-rails (3.4.2)
|
||||||
actionpack (>= 5.2)
|
actionpack (>= 5.2)
|
||||||
activesupport (>= 5.2)
|
activesupport (>= 5.2)
|
||||||
sprockets (>= 3.0.0)
|
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)
|
mini_portile2 (~> 2.8.0)
|
||||||
stackprof (0.2.25-x86_64-linux-musl)
|
stackprof (0.2.25-x86_64-linux-musl)
|
||||||
stream (0.5.5)
|
stream (0.5.5)
|
||||||
|
@ -537,13 +560,13 @@ GEM
|
||||||
jekyll (~> 4)
|
jekyll (~> 4)
|
||||||
symbol-fstring (1.0.2-x86_64-linux-musl)
|
symbol-fstring (1.0.2-x86_64-linux-musl)
|
||||||
sysexits (1.2.0)
|
sysexits (1.2.0)
|
||||||
temple (0.10.1)
|
temple (0.10.3)
|
||||||
terminal-table (2.0.0)
|
terminal-table (2.0.0)
|
||||||
unicode-display_width (~> 1.1, >= 1.1.1)
|
unicode-display_width (~> 1.1, >= 1.1.1)
|
||||||
thor (1.3.0)
|
thor (1.3.0)
|
||||||
tilt (2.1.0)
|
tilt (2.3.0)
|
||||||
timecop (0.9.6)
|
timecop (0.9.6)
|
||||||
timeout (0.3.2)
|
timeout (0.4.1)
|
||||||
turbolinks (5.2.1)
|
turbolinks (5.2.1)
|
||||||
turbolinks-source (~> 5.2)
|
turbolinks-source (~> 5.2)
|
||||||
turbolinks-source (5.2.0)
|
turbolinks-source (5.2.0)
|
||||||
|
@ -553,7 +576,7 @@ GEM
|
||||||
execjs (>= 0.3.0, < 3)
|
execjs (>= 0.3.0, < 3)
|
||||||
unf (0.1.4)
|
unf (0.1.4)
|
||||||
unf_ext
|
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)
|
unicode-display_width (1.8.0)
|
||||||
uri-ssh_git (2.0.0)
|
uri-ssh_git (2.0.0)
|
||||||
validates_hostname (1.0.13)
|
validates_hostname (1.0.13)
|
||||||
|
@ -579,12 +602,14 @@ GEM
|
||||||
xpath (3.2.0)
|
xpath (3.2.0)
|
||||||
nokogiri (~> 1.8)
|
nokogiri (~> 1.8)
|
||||||
yard (0.9.34)
|
yard (0.9.34)
|
||||||
zeitwerk (2.6.8)
|
zeitwerk (2.6.12)
|
||||||
|
|
||||||
PLATFORMS
|
PLATFORMS
|
||||||
x86_64-linux-musl
|
x86_64-linux-musl
|
||||||
|
|
||||||
DEPENDENCIES
|
DEPENDENCIES
|
||||||
|
aasm
|
||||||
|
after_commit_everywhere (~> 1.0)
|
||||||
bcrypt (~> 3.1.7)
|
bcrypt (~> 3.1.7)
|
||||||
bcrypt_pbkdf
|
bcrypt_pbkdf
|
||||||
blazer
|
blazer
|
||||||
|
@ -601,7 +626,7 @@ DEPENDENCIES
|
||||||
devise
|
devise
|
||||||
devise-i18n
|
devise-i18n
|
||||||
devise_invitable
|
devise_invitable
|
||||||
distributed-press-api-client (~> 0.3.0rc0)
|
distributed-press-api-client (~> 0.4.0rc2)
|
||||||
dotenv-rails
|
dotenv-rails
|
||||||
down
|
down
|
||||||
ed25519
|
ed25519
|
||||||
|
@ -617,6 +642,7 @@ DEPENDENCIES
|
||||||
haml-lint
|
haml-lint
|
||||||
hamlit-rails
|
hamlit-rails
|
||||||
hiredis
|
hiredis
|
||||||
|
hiredis-client
|
||||||
httparty
|
httparty
|
||||||
icalendar
|
icalendar
|
||||||
image_processing
|
image_processing
|
||||||
|
@ -650,10 +676,12 @@ DEPENDENCIES
|
||||||
rails-i18n
|
rails-i18n
|
||||||
rails_warden
|
rails_warden
|
||||||
redis (~> 4.0)
|
redis (~> 4.0)
|
||||||
|
redis-client
|
||||||
redis-rails
|
redis-rails
|
||||||
rgl
|
rgl
|
||||||
rollups!
|
rollups!
|
||||||
rubocop-rails
|
rubocop-rails
|
||||||
|
ruby-brs
|
||||||
rubyzip
|
rubyzip
|
||||||
rugged (= 1.5.0.1)
|
rugged (= 1.5.0.1)
|
||||||
safe_yaml
|
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`.
|
# :attributes`.
|
||||||
class Deploy < ApplicationRecord
|
class Deploy < ApplicationRecord
|
||||||
belongs_to :site
|
belongs_to :site
|
||||||
|
belongs_to :rol
|
||||||
|
|
||||||
has_many :build_stats, dependent: :destroy
|
has_many :build_stats, dependent: :destroy
|
||||||
|
|
||||||
DEPENDENCIES = []
|
DEPENDENCIES = [].freeze
|
||||||
SOFT_DEPENDENCIES = []
|
SOFT_DEPENDENCIES = [].freeze
|
||||||
|
|
||||||
def deploy(**)
|
def deploy(**)
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
@ -72,7 +74,7 @@ class Deploy < ApplicationRecord
|
||||||
'HOME' => home_dir,
|
'HOME' => home_dir,
|
||||||
'PATH' => paths.join(':'),
|
'PATH' => paths.join(':'),
|
||||||
'JEKYLL_ENV' => Rails.env,
|
'JEKYLL_ENV' => Rails.env,
|
||||||
'LANG' => ENV['LANG'],
|
'LANG' => ENV.fetch('LANG', nil)
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -137,7 +139,7 @@ class Deploy < ApplicationRecord
|
||||||
# provisto con el archivo como parámetro
|
# provisto con el archivo como parámetro
|
||||||
#
|
#
|
||||||
# @param :content [String]
|
# @param :content [String]
|
||||||
def with_tempfile(content, &block)
|
def with_tempfile(content)
|
||||||
Tempfile.create(SecureRandom.hex) do |file|
|
Tempfile.create(SecureRandom.hex) do |file|
|
||||||
file.write content.to_s
|
file.write content.to_s
|
||||||
file.rewind
|
file.rewind
|
||||||
|
|
|
@ -5,7 +5,9 @@ require 'distributed_press/v1/social/client'
|
||||||
# Publicar novedades al Fediverso
|
# Publicar novedades al Fediverso
|
||||||
class DeploySocialDistributedPress < Deploy
|
class DeploySocialDistributedPress < Deploy
|
||||||
# Solo luego de publicar remotamente
|
# 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
|
# Envía las notificaciones
|
||||||
def deploy(output: false)
|
def deploy(output: false)
|
||||||
|
@ -52,4 +54,45 @@ class DeploySocialDistributedPress < Deploy
|
||||||
def flags_for_build(**args)
|
def flags_for_build(**args)
|
||||||
"--key #{Shellwords.escape args[:private_key].path}"
|
"--key #{Shellwords.escape args[:private_key].path}"
|
||||||
end
|
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
|
end
|
||||||
|
|
|
@ -11,6 +11,7 @@ class Rol < ApplicationRecord
|
||||||
|
|
||||||
belongs_to :usuarie
|
belongs_to :usuarie
|
||||||
belongs_to :site
|
belongs_to :site
|
||||||
|
has_many :deploys
|
||||||
|
|
||||||
validates_inclusion_of :rol, in: ROLES
|
validates_inclusion_of :rol, in: ROLES
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'distributed_press/v1/social/client'
|
||||||
|
|
||||||
class Site
|
class Site
|
||||||
# Agrega soporte para Social Distributed Press en los sitios
|
# Agrega soporte para Social Distributed Press en los sitios
|
||||||
module SocialDistributedPress
|
module SocialDistributedPress
|
||||||
|
@ -8,15 +10,25 @@ class Site
|
||||||
included do
|
included do
|
||||||
encrypts :private_key_pem
|
encrypts :private_key_pem
|
||||||
|
|
||||||
|
has_many :activity_pubs
|
||||||
|
|
||||||
before_save :generate_private_key_pem!, unless: :private_key_pem?
|
before_save :generate_private_key_pem!, unless: :private_key_pem?
|
||||||
|
|
||||||
|
# @return [SocialInbox]
|
||||||
|
def social_inbox
|
||||||
|
@social_inbox ||= SocialInbox.new(site: self)
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
# Genera la llave privada y la almacena
|
# Genera la llave privada y la almacena
|
||||||
#
|
#
|
||||||
# @return [nil]
|
# @return [nil]
|
||||||
def generate_private_key_pem!
|
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
|
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_relative 'boot'
|
||||||
|
|
||||||
|
require 'aasm'
|
||||||
|
require 'redis-client'
|
||||||
|
require 'hiredis-client'
|
||||||
|
require 'brs'
|
||||||
require 'rails'
|
require 'rails'
|
||||||
# Pick the frameworks you want:
|
# Pick the frameworks you want:
|
||||||
require 'active_model/railtie'
|
require 'active_model/railtie'
|
||||||
|
|
|
@ -18,7 +18,15 @@ Rails.application.routes.draw do
|
||||||
get :'contact/cookie', to: 'invitades#contact_cookie'
|
get :'contact/cookie', to: 'invitades#contact_cookie'
|
||||||
post :'contact/:form', to: 'contact#receive', as: :contact
|
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
|
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;
|
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: -
|
-- 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,
|
updated_at timestamp without time zone NOT NULL,
|
||||||
site_id integer,
|
site_id integer,
|
||||||
type character varying,
|
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);
|
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: -
|
-- 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);
|
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: -
|
-- Name: index_blazer_audits_on_query_id; Type: INDEX; Schema: public; Owner: -
|
||||||
--
|
--
|
||||||
|
@ -2346,6 +2493,13 @@ INSERT INTO "schema_migrations" (version) VALUES
|
||||||
('20230731195050'),
|
('20230731195050'),
|
||||||
('20230829204127'),
|
('20230829204127'),
|
||||||
('20230921155401'),
|
('20230921155401'),
|
||||||
('20230927153926');
|
('20230927153926'),
|
||||||
|
('20240216170202'),
|
||||||
|
('20240219153919'),
|
||||||
|
('20240219175839'),
|
||||||
|
('20240219204011'),
|
||||||
|
('20240219204224'),
|
||||||
|
('20240220161414'),
|
||||||
|
('20240221184007');
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue