Merge remote-tracking branch 'origin/main'
This commit is contained in:
commit
8b3d53b263
|
@ -0,0 +1,54 @@
|
||||||
|
name: Bug Report
|
||||||
|
description: If something isn't working as expected
|
||||||
|
labels: [bug]
|
||||||
|
body:
|
||||||
|
- type: markdown
|
||||||
|
attributes:
|
||||||
|
value: |
|
||||||
|
Before opening an issue, please make sure to check if the [issue tracker](https://github.com/Retrospring/retrospring/issues?q=is%3Aissue+label%3Abug) in case it has been previously reported or fixed.
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: Steps to reproduce the problem
|
||||||
|
description: What were you trying to do?
|
||||||
|
value: |
|
||||||
|
1.
|
||||||
|
2.
|
||||||
|
3.
|
||||||
|
...
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: Expected behaviour
|
||||||
|
description: What should have happened?
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: Actual behaviour
|
||||||
|
description: What happened?
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: Detailed description
|
||||||
|
validations:
|
||||||
|
required: false
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: Specifications
|
||||||
|
description: |
|
||||||
|
If you host Retrospring, what version/commit hash of Retrospring did this issue occur in?
|
||||||
|
|
||||||
|
If a front-end issue, what browser and operating systems were you using?
|
||||||
|
placeholder: |
|
||||||
|
Retrospring 1970.0101.0
|
||||||
|
Ruby 3.1.3
|
||||||
|
Node.js 18.13.0
|
||||||
|
|
||||||
|
Google Chrome 112
|
||||||
|
Firefox 109.0
|
||||||
|
|
||||||
|
etc...
|
||||||
|
validations:
|
||||||
|
required: true
|
|
@ -0,0 +1,20 @@
|
||||||
|
name: Feature Request
|
||||||
|
description: If you have a suggestion
|
||||||
|
labels: [suggestion]
|
||||||
|
body:
|
||||||
|
- type: markdown
|
||||||
|
attributes:
|
||||||
|
value: |
|
||||||
|
Please use a concise and distinct title for the issue.
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: Pitch
|
||||||
|
description: Describe your idea for a feature. Please check our [issue tracker](https://github.com/Retrospring/retrospring/issues?q=is%3Aissue+label%3Asuggestion) to make sure it has not already been suggested/implemented/turned down before.
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: Motivation
|
||||||
|
description: Why do you think this feature is needed? Who would benefit from it?
|
||||||
|
validations:
|
||||||
|
required: true
|
|
@ -0,0 +1,5 @@
|
||||||
|
blank_issues_enabled: false
|
||||||
|
contact_links:
|
||||||
|
- name: GitHub Discussions
|
||||||
|
url: https://github.com/retrospring/retrospring/discussions
|
||||||
|
about: Please ask and answer questions here.
|
6
Gemfile
6
Gemfile
|
@ -50,9 +50,9 @@ gem "sentry-rails"
|
||||||
gem "sentry-ruby"
|
gem "sentry-ruby"
|
||||||
gem "sentry-sidekiq"
|
gem "sentry-sidekiq"
|
||||||
|
|
||||||
gem "sidekiq", "< 6" # remove version constraint once we have redis 5
|
gem "sidekiq", "< 7" # remove version constraint once are ready to upgrade https://github.com/mperham/sidekiq/blob/main/docs/7.0-Upgrade.md
|
||||||
|
|
||||||
gem "questiongenerator", "~> 1.0"
|
gem "questiongenerator", "~> 1.1"
|
||||||
|
|
||||||
gem "httparty"
|
gem "httparty"
|
||||||
gem "redcarpet"
|
gem "redcarpet"
|
||||||
|
@ -97,7 +97,7 @@ group :development, :test do
|
||||||
gem "rspec-mocks"
|
gem "rspec-mocks"
|
||||||
gem "rspec-rails", "~> 6.0"
|
gem "rspec-rails", "~> 6.0"
|
||||||
gem "rspec-sidekiq", "~> 3.0", require: false
|
gem "rspec-sidekiq", "~> 3.0", require: false
|
||||||
gem "rubocop", "~> 1.43"
|
gem "rubocop", "~> 1.44"
|
||||||
gem "rubocop-rails", "~> 2.17"
|
gem "rubocop-rails", "~> 2.17"
|
||||||
gem "shoulda-matchers", "~> 5.3"
|
gem "shoulda-matchers", "~> 5.3"
|
||||||
gem "simplecov", require: false
|
gem "simplecov", require: false
|
||||||
|
|
151
Gemfile.lock
151
Gemfile.lock
|
@ -9,40 +9,40 @@ GIT
|
||||||
GEM
|
GEM
|
||||||
remote: https://rubygems.org/
|
remote: https://rubygems.org/
|
||||||
specs:
|
specs:
|
||||||
actioncable (6.1.7.1)
|
actioncable (6.1.7.2)
|
||||||
actionpack (= 6.1.7.1)
|
actionpack (= 6.1.7.2)
|
||||||
activesupport (= 6.1.7.1)
|
activesupport (= 6.1.7.2)
|
||||||
nio4r (~> 2.0)
|
nio4r (~> 2.0)
|
||||||
websocket-driver (>= 0.6.1)
|
websocket-driver (>= 0.6.1)
|
||||||
actionmailbox (6.1.7.1)
|
actionmailbox (6.1.7.2)
|
||||||
actionpack (= 6.1.7.1)
|
actionpack (= 6.1.7.2)
|
||||||
activejob (= 6.1.7.1)
|
activejob (= 6.1.7.2)
|
||||||
activerecord (= 6.1.7.1)
|
activerecord (= 6.1.7.2)
|
||||||
activestorage (= 6.1.7.1)
|
activestorage (= 6.1.7.2)
|
||||||
activesupport (= 6.1.7.1)
|
activesupport (= 6.1.7.2)
|
||||||
mail (>= 2.7.1)
|
mail (>= 2.7.1)
|
||||||
actionmailer (6.1.7.1)
|
actionmailer (6.1.7.2)
|
||||||
actionpack (= 6.1.7.1)
|
actionpack (= 6.1.7.2)
|
||||||
actionview (= 6.1.7.1)
|
actionview (= 6.1.7.2)
|
||||||
activejob (= 6.1.7.1)
|
activejob (= 6.1.7.2)
|
||||||
activesupport (= 6.1.7.1)
|
activesupport (= 6.1.7.2)
|
||||||
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.1)
|
actionpack (6.1.7.2)
|
||||||
actionview (= 6.1.7.1)
|
actionview (= 6.1.7.2)
|
||||||
activesupport (= 6.1.7.1)
|
activesupport (= 6.1.7.2)
|
||||||
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.1)
|
actiontext (6.1.7.2)
|
||||||
actionpack (= 6.1.7.1)
|
actionpack (= 6.1.7.2)
|
||||||
activerecord (= 6.1.7.1)
|
activerecord (= 6.1.7.2)
|
||||||
activestorage (= 6.1.7.1)
|
activestorage (= 6.1.7.2)
|
||||||
activesupport (= 6.1.7.1)
|
activesupport (= 6.1.7.2)
|
||||||
nokogiri (>= 1.8.5)
|
nokogiri (>= 1.8.5)
|
||||||
actionview (6.1.7.1)
|
actionview (6.1.7.2)
|
||||||
activesupport (= 6.1.7.1)
|
activesupport (= 6.1.7.2)
|
||||||
builder (~> 3.1)
|
builder (~> 3.1)
|
||||||
erubi (~> 1.4)
|
erubi (~> 1.4)
|
||||||
rails-dom-testing (~> 2.0)
|
rails-dom-testing (~> 2.0)
|
||||||
|
@ -50,26 +50,26 @@ GEM
|
||||||
active_model_otp (2.3.1)
|
active_model_otp (2.3.1)
|
||||||
activemodel
|
activemodel
|
||||||
rotp (~> 6.2.0)
|
rotp (~> 6.2.0)
|
||||||
activejob (6.1.7.1)
|
activejob (6.1.7.2)
|
||||||
activesupport (= 6.1.7.1)
|
activesupport (= 6.1.7.2)
|
||||||
globalid (>= 0.3.6)
|
globalid (>= 0.3.6)
|
||||||
activemodel (6.1.7.1)
|
activemodel (6.1.7.2)
|
||||||
activesupport (= 6.1.7.1)
|
activesupport (= 6.1.7.2)
|
||||||
activemodel-serializers-xml (1.0.2)
|
activemodel-serializers-xml (1.0.2)
|
||||||
activemodel (> 5.x)
|
activemodel (> 5.x)
|
||||||
activesupport (> 5.x)
|
activesupport (> 5.x)
|
||||||
builder (~> 3.1)
|
builder (~> 3.1)
|
||||||
activerecord (6.1.7.1)
|
activerecord (6.1.7.2)
|
||||||
activemodel (= 6.1.7.1)
|
activemodel (= 6.1.7.2)
|
||||||
activesupport (= 6.1.7.1)
|
activesupport (= 6.1.7.2)
|
||||||
activestorage (6.1.7.1)
|
activestorage (6.1.7.2)
|
||||||
actionpack (= 6.1.7.1)
|
actionpack (= 6.1.7.2)
|
||||||
activejob (= 6.1.7.1)
|
activejob (= 6.1.7.2)
|
||||||
activerecord (= 6.1.7.1)
|
activerecord (= 6.1.7.2)
|
||||||
activesupport (= 6.1.7.1)
|
activesupport (= 6.1.7.2)
|
||||||
marcel (~> 1.0)
|
marcel (~> 1.0)
|
||||||
mini_mime (>= 1.1.0)
|
mini_mime (>= 1.1.0)
|
||||||
activesupport (6.1.7.1)
|
activesupport (6.1.7.2)
|
||||||
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)
|
||||||
|
@ -85,7 +85,7 @@ GEM
|
||||||
rack (>= 0.9.0)
|
rack (>= 0.9.0)
|
||||||
binding_of_caller (1.0.0)
|
binding_of_caller (1.0.0)
|
||||||
debug_inspector (>= 0.0.1)
|
debug_inspector (>= 0.0.1)
|
||||||
bootsnap (1.15.0)
|
bootsnap (1.16.0)
|
||||||
msgpack (~> 1.2)
|
msgpack (~> 1.2)
|
||||||
bootstrap_form (5.1.0)
|
bootstrap_form (5.1.0)
|
||||||
actionpack (>= 5.2)
|
actionpack (>= 5.2)
|
||||||
|
@ -105,8 +105,8 @@ GEM
|
||||||
chunky_png (1.4.0)
|
chunky_png (1.4.0)
|
||||||
coderay (1.1.3)
|
coderay (1.1.3)
|
||||||
colorize (0.8.1)
|
colorize (0.8.1)
|
||||||
concurrent-ruby (1.1.10)
|
concurrent-ruby (1.2.0)
|
||||||
connection_pool (2.2.5)
|
connection_pool (2.3.0)
|
||||||
crass (1.0.6)
|
crass (1.0.6)
|
||||||
cssbundling-rails (1.1.2)
|
cssbundling-rails (1.1.2)
|
||||||
railties (>= 6.0.0)
|
railties (>= 6.0.0)
|
||||||
|
@ -150,7 +150,7 @@ GEM
|
||||||
zeitwerk (~> 2.6)
|
zeitwerk (~> 2.6)
|
||||||
equalizer (0.0.11)
|
equalizer (0.0.11)
|
||||||
erubi (1.12.0)
|
erubi (1.12.0)
|
||||||
excon (0.93.1)
|
excon (0.98.0)
|
||||||
factory_bot (6.2.0)
|
factory_bot (6.2.0)
|
||||||
activesupport (>= 5.0.0)
|
activesupport (>= 5.0.0)
|
||||||
factory_bot_rails (6.2.0)
|
factory_bot_rails (6.2.0)
|
||||||
|
@ -165,7 +165,7 @@ GEM
|
||||||
ffi-compiler (1.0.1)
|
ffi-compiler (1.0.1)
|
||||||
ffi (>= 1.0.0)
|
ffi (>= 1.0.0)
|
||||||
rake
|
rake
|
||||||
fog-aws (3.15.0)
|
fog-aws (3.16.0)
|
||||||
fog-core (~> 2.1)
|
fog-core (~> 2.1)
|
||||||
fog-json (~> 1.1)
|
fog-json (~> 1.1)
|
||||||
fog-xml (~> 0.1)
|
fog-xml (~> 0.1)
|
||||||
|
@ -184,13 +184,13 @@ GEM
|
||||||
nokogiri (>= 1.5.11, < 2.0.0)
|
nokogiri (>= 1.5.11, < 2.0.0)
|
||||||
formatador (1.1.0)
|
formatador (1.1.0)
|
||||||
glob (0.3.1)
|
glob (0.3.1)
|
||||||
globalid (1.0.1)
|
globalid (1.1.0)
|
||||||
activesupport (>= 5.0)
|
activesupport (>= 5.0)
|
||||||
haml (6.1.1)
|
haml (6.1.1)
|
||||||
temple (>= 0.8.2)
|
temple (>= 0.8.2)
|
||||||
thor
|
thor
|
||||||
tilt
|
tilt
|
||||||
haml_lint (0.43.0)
|
haml_lint (0.45.0)
|
||||||
haml (>= 4.0, < 6.2)
|
haml (>= 4.0, < 6.2)
|
||||||
parallel (~> 1.10)
|
parallel (~> 1.10)
|
||||||
rainbow
|
rainbow
|
||||||
|
@ -321,27 +321,27 @@ GEM
|
||||||
nio4r (~> 2.0)
|
nio4r (~> 2.0)
|
||||||
pundit (2.3.0)
|
pundit (2.3.0)
|
||||||
activesupport (>= 3.0.0)
|
activesupport (>= 3.0.0)
|
||||||
questiongenerator (1.0.0)
|
questiongenerator (1.1.0)
|
||||||
racc (1.6.2)
|
racc (1.6.2)
|
||||||
rack (2.2.6.2)
|
rack (2.2.6.2)
|
||||||
rack-protection (2.2.2)
|
rack-protection (3.0.5)
|
||||||
rack
|
rack
|
||||||
rack-test (2.0.2)
|
rack-test (2.0.2)
|
||||||
rack (>= 1.3)
|
rack (>= 1.3)
|
||||||
rails (6.1.7.1)
|
rails (6.1.7.2)
|
||||||
actioncable (= 6.1.7.1)
|
actioncable (= 6.1.7.2)
|
||||||
actionmailbox (= 6.1.7.1)
|
actionmailbox (= 6.1.7.2)
|
||||||
actionmailer (= 6.1.7.1)
|
actionmailer (= 6.1.7.2)
|
||||||
actionpack (= 6.1.7.1)
|
actionpack (= 6.1.7.2)
|
||||||
actiontext (= 6.1.7.1)
|
actiontext (= 6.1.7.2)
|
||||||
actionview (= 6.1.7.1)
|
actionview (= 6.1.7.2)
|
||||||
activejob (= 6.1.7.1)
|
activejob (= 6.1.7.2)
|
||||||
activemodel (= 6.1.7.1)
|
activemodel (= 6.1.7.2)
|
||||||
activerecord (= 6.1.7.1)
|
activerecord (= 6.1.7.2)
|
||||||
activestorage (= 6.1.7.1)
|
activestorage (= 6.1.7.2)
|
||||||
activesupport (= 6.1.7.1)
|
activesupport (= 6.1.7.2)
|
||||||
bundler (>= 1.15.0)
|
bundler (>= 1.15.0)
|
||||||
railties (= 6.1.7.1)
|
railties (= 6.1.7.2)
|
||||||
sprockets-rails (>= 2.0.0)
|
sprockets-rails (>= 2.0.0)
|
||||||
rails-controller-testing (1.0.5)
|
rails-controller-testing (1.0.5)
|
||||||
actionpack (>= 5.0.1.rc1)
|
actionpack (>= 5.0.1.rc1)
|
||||||
|
@ -361,17 +361,17 @@ GEM
|
||||||
nested_form (~> 0.3)
|
nested_form (~> 0.3)
|
||||||
rails (>= 6.0, < 8)
|
rails (>= 6.0, < 8)
|
||||||
turbo-rails (~> 1.0)
|
turbo-rails (~> 1.0)
|
||||||
railties (6.1.7.1)
|
railties (6.1.7.2)
|
||||||
actionpack (= 6.1.7.1)
|
actionpack (= 6.1.7.2)
|
||||||
activesupport (= 6.1.7.1)
|
activesupport (= 6.1.7.2)
|
||||||
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.0.6)
|
||||||
redcarpet (3.5.1)
|
redcarpet (3.6.0)
|
||||||
redis (4.5.1)
|
redis (4.8.0)
|
||||||
regexp_parser (2.6.1)
|
regexp_parser (2.6.2)
|
||||||
request_store (1.5.1)
|
request_store (1.5.1)
|
||||||
rack (>= 1.4)
|
rack (>= 1.4)
|
||||||
responders (3.0.1)
|
responders (3.0.1)
|
||||||
|
@ -417,7 +417,7 @@ GEM
|
||||||
rspec-core (~> 3.0, >= 3.0.0)
|
rspec-core (~> 3.0, >= 3.0.0)
|
||||||
sidekiq (>= 2.4.0)
|
sidekiq (>= 2.4.0)
|
||||||
rspec-support (3.12.0)
|
rspec-support (3.12.0)
|
||||||
rubocop (1.43.0)
|
rubocop (1.44.1)
|
||||||
json (~> 2.3)
|
json (~> 2.3)
|
||||||
parallel (~> 1.10)
|
parallel (~> 1.10)
|
||||||
parser (>= 3.2.0.0)
|
parser (>= 3.2.0.0)
|
||||||
|
@ -437,7 +437,7 @@ GEM
|
||||||
ruby-vips (2.1.4)
|
ruby-vips (2.1.4)
|
||||||
ffi (~> 1.12)
|
ffi (~> 1.12)
|
||||||
rubyzip (2.3.2)
|
rubyzip (2.3.2)
|
||||||
sanitize (6.0.0)
|
sanitize (6.0.1)
|
||||||
crass (~> 1.0.2)
|
crass (~> 1.0.2)
|
||||||
nokogiri (>= 1.12.0)
|
nokogiri (>= 1.12.0)
|
||||||
sassc (2.4.0)
|
sassc (2.4.0)
|
||||||
|
@ -458,11 +458,10 @@ GEM
|
||||||
sidekiq (>= 3.0)
|
sidekiq (>= 3.0)
|
||||||
shoulda-matchers (5.3.0)
|
shoulda-matchers (5.3.0)
|
||||||
activesupport (>= 5.2.0)
|
activesupport (>= 5.2.0)
|
||||||
sidekiq (5.2.10)
|
sidekiq (6.5.8)
|
||||||
connection_pool (~> 2.2, >= 2.2.2)
|
connection_pool (>= 2.2.5, < 3)
|
||||||
rack (~> 2.0)
|
rack (~> 2.0)
|
||||||
rack-protection (>= 1.5.0)
|
redis (>= 4.5.0, < 5)
|
||||||
redis (~> 4.5, < 4.6.0)
|
|
||||||
simple_oauth (0.3.1)
|
simple_oauth (0.3.1)
|
||||||
simplecov (0.22.0)
|
simplecov (0.22.0)
|
||||||
docile (~> 1.1)
|
docile (~> 1.1)
|
||||||
|
@ -485,7 +484,7 @@ GEM
|
||||||
activesupport (>= 5.2)
|
activesupport (>= 5.2)
|
||||||
sprockets (>= 3.0.0)
|
sprockets (>= 3.0.0)
|
||||||
sysexits (1.2.0)
|
sysexits (1.2.0)
|
||||||
temple (0.9.1)
|
temple (0.10.0)
|
||||||
thor (1.2.1)
|
thor (1.2.1)
|
||||||
thread_safe (0.3.6)
|
thread_safe (0.3.6)
|
||||||
tilt (2.0.11)
|
tilt (2.0.11)
|
||||||
|
@ -511,7 +510,7 @@ GEM
|
||||||
twitter-text (3.1.0)
|
twitter-text (3.1.0)
|
||||||
idn-ruby
|
idn-ruby
|
||||||
unf (~> 0.1.0)
|
unf (~> 0.1.0)
|
||||||
tzinfo (2.0.5)
|
tzinfo (2.0.6)
|
||||||
concurrent-ruby (~> 1.0)
|
concurrent-ruby (~> 1.0)
|
||||||
unf (0.1.4)
|
unf (0.1.4)
|
||||||
unf_ext
|
unf_ext
|
||||||
|
@ -579,7 +578,7 @@ DEPENDENCIES
|
||||||
pghero
|
pghero
|
||||||
puma
|
puma
|
||||||
pundit (~> 2.3)
|
pundit (~> 2.3)
|
||||||
questiongenerator (~> 1.0)
|
questiongenerator (~> 1.1)
|
||||||
rails (~> 6.1)
|
rails (~> 6.1)
|
||||||
rails-controller-testing
|
rails-controller-testing
|
||||||
rails-i18n (~> 7.0)
|
rails-i18n (~> 7.0)
|
||||||
|
@ -594,7 +593,7 @@ DEPENDENCIES
|
||||||
rspec-mocks
|
rspec-mocks
|
||||||
rspec-rails (~> 6.0)
|
rspec-rails (~> 6.0)
|
||||||
rspec-sidekiq (~> 3.0)
|
rspec-sidekiq (~> 3.0)
|
||||||
rubocop (~> 1.43)
|
rubocop (~> 1.44)
|
||||||
rubocop-rails (~> 2.17)
|
rubocop-rails (~> 2.17)
|
||||||
ruby-progressbar
|
ruby-progressbar
|
||||||
rubyzip (~> 2.3)
|
rubyzip (~> 2.3)
|
||||||
|
@ -604,7 +603,7 @@ DEPENDENCIES
|
||||||
sentry-ruby
|
sentry-ruby
|
||||||
sentry-sidekiq
|
sentry-sidekiq
|
||||||
shoulda-matchers (~> 5.3)
|
shoulda-matchers (~> 5.3)
|
||||||
sidekiq (< 6)
|
sidekiq (< 7)
|
||||||
simplecov
|
simplecov
|
||||||
simplecov-cobertura
|
simplecov-cobertura
|
||||||
simplecov-json
|
simplecov-json
|
||||||
|
|
9
Rakefile
9
Rakefile
|
@ -51,6 +51,15 @@ namespace :justask do # rubocop:disable Metrics/BlockLength
|
||||||
user.remove_role :moderator
|
user.remove_role :moderator
|
||||||
puts "#{user.screen_name} is no longer a moderator."
|
puts "#{user.screen_name} is no longer a moderator."
|
||||||
end
|
end
|
||||||
|
|
||||||
|
desc "Removes users whose accounts haven't been verified for over 3 months."
|
||||||
|
task remove_stale: :environment do
|
||||||
|
puts "Removing stale users…"
|
||||||
|
removed = User.where(confirmed_at: nil)
|
||||||
|
.where("confirmation_sent_at < ?", DateTime.now.utc - 3.months)
|
||||||
|
.destroy_all.count
|
||||||
|
puts "Removed #{removed} users"
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
namespace :db do
|
namespace :db do
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
# Security Policy
|
||||||
|
|
||||||
|
If you believe you've found a security vulnerability in Retrospring (a bug that allows something to happen that shouldn't be possible), you can reach us at <security@retrospring.net>.
|
||||||
|
|
||||||
|
You should *not* report such issues on GitHub or in other public spaces to give us time to publish a fix for the issue without exposing Retrospring's users to increased risk.
|
||||||
|
|
||||||
|
## Scope
|
||||||
|
|
||||||
|
A "vulnerability in Retrospring" is a vulnerability in the code distributed through our main source code repository on GitHub. Vulnerabilities that are specific to a given installation (e.g. misconfiguration) should be reported to the owner of that installation and not us.
|
||||||
|
|
||||||
|
## Supported Versions
|
||||||
|
|
||||||
|
As long as Retrospring is in rapid development pace the currently supported version for security issues is always the [latest tagged release](https://github.com/Retrospring/retrospring/releases/latest).
|
|
@ -125,6 +125,8 @@ $spacers: map-merge($rs-spacers, $spacers);
|
||||||
--muted-text: 108, 117, 125;
|
--muted-text: 108, 117, 125;
|
||||||
--input-text: 0, 0, 0;
|
--input-text: 0, 0, 0;
|
||||||
--input-placeholder: 108, 117, 125;
|
--input-placeholder: 108, 117, 125;
|
||||||
|
--raised-text: 0, 0, 0;
|
||||||
|
--raised-accent-text: 0, 0, 0;
|
||||||
|
|
||||||
--turbolinks-progress-color: #a58adc; // --primary lightened by 25%
|
--turbolinks-progress-color: #a58adc; // --primary lightened by 25%
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,7 +42,7 @@
|
||||||
& .dropdown-item:hover,
|
& .dropdown-item:hover,
|
||||||
& .dropdown-item:active {
|
& .dropdown-item:active {
|
||||||
background: transparent;
|
background: transparent;
|
||||||
color: RGB(var(--body-text));
|
color: RGB(var(--raised-text));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
margin-bottom: map.get($spacers, 3);
|
margin-bottom: map.get($spacers, 3);
|
||||||
box-shadow: $box-shadow-sm;
|
box-shadow: $box-shadow-sm;
|
||||||
background-color: var(--raised-bg);
|
background-color: var(--raised-bg);
|
||||||
|
color: RGB(var(--raised-text));
|
||||||
|
|
||||||
p:last-child {
|
p:last-child {
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
|
@ -17,4 +18,5 @@
|
||||||
.card-header,
|
.card-header,
|
||||||
.card-footer {
|
.card-footer {
|
||||||
background-color: var(--raised-accent);
|
background-color: var(--raised-accent);
|
||||||
|
color: RGB(var(--raised-accent-text));
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
.dropdown-menu {
|
.dropdown-menu {
|
||||||
color: RGB(var(--body-text));
|
color: RGB(var(--raised-text));
|
||||||
background-color: var(--raised-bg);
|
background-color: var(--raised-bg);
|
||||||
box-shadow: $box-shadow-lg;
|
box-shadow: $box-shadow-lg;
|
||||||
border: none;
|
border: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dropdown-item {
|
.dropdown-item {
|
||||||
color: RGB(var(--body-text));
|
color: RGB(var(--raised-text));
|
||||||
|
|
||||||
&.active,
|
&.active,
|
||||||
&:active,
|
&:active,
|
||||||
|
@ -16,6 +16,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
|
color: RGB(var(--raised-accent-text));
|
||||||
background-color: var(--raised-accent);
|
background-color: var(--raised-accent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,9 +13,10 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.list-group-item-action {
|
.list-group-item-action {
|
||||||
color: RGB(var(--body-text));
|
color: RGB(var(--raised-text));
|
||||||
|
|
||||||
&:hover, &:focus {
|
&:hover, &:focus {
|
||||||
|
color: RGB(var(--raised-accent-text));
|
||||||
background-color: var(--raised-accent);
|
background-color: var(--raised-accent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class AjaxController < ApplicationController
|
class AjaxController < ApplicationController
|
||||||
|
skip_before_action :find_active_announcements
|
||||||
before_action :build_response
|
before_action :build_response
|
||||||
after_action :return_response
|
after_action :return_response
|
||||||
|
|
||||||
|
@ -92,10 +93,6 @@ class AjaxController < ApplicationController
|
||||||
return_response
|
return_response
|
||||||
end
|
end
|
||||||
|
|
||||||
def find_active_announcements
|
|
||||||
# We do not need announcements here
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def build_response
|
def build_response
|
||||||
|
|
|
@ -3,7 +3,9 @@
|
||||||
class InboxController < ApplicationController
|
class InboxController < ApplicationController
|
||||||
before_action :authenticate_user!
|
before_action :authenticate_user!
|
||||||
|
|
||||||
def show
|
after_action :mark_inbox_entries_as_read, only: %i[show]
|
||||||
|
|
||||||
|
def show # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
|
||||||
find_author
|
find_author
|
||||||
find_inbox_entries
|
find_inbox_entries
|
||||||
|
|
||||||
|
@ -11,15 +13,17 @@ class InboxController < ApplicationController
|
||||||
# rubocop disabled because of a false positive
|
# rubocop disabled because of a false positive
|
||||||
flash[:info] = t(".author.info", author: @author) # rubocop:disable Rails/ActionControllerFlashBeforeRender
|
flash[:info] = t(".author.info", author: @author) # rubocop:disable Rails/ActionControllerFlashBeforeRender
|
||||||
redirect_to inbox_path(last_id: params[:last_id])
|
redirect_to inbox_path(last_id: params[:last_id])
|
||||||
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
@delete_id = find_delete_id
|
@delete_id = find_delete_id
|
||||||
|
|
||||||
@disabled = true if @inbox.empty?
|
@disabled = true if @inbox.empty?
|
||||||
|
services = current_user.services.to_a
|
||||||
|
|
||||||
respond_to do |format|
|
respond_to do |format|
|
||||||
format.html
|
format.html { render "show", locals: { services: } }
|
||||||
format.turbo_stream do
|
format.turbo_stream do
|
||||||
render "show", layout: false, status: :see_other
|
render "show", locals: { services: }, layout: false, status: :see_other
|
||||||
|
|
||||||
# rubocop disabled as just flipping a flag doesn't need to have validations to be run
|
# rubocop disabled as just flipping a flag doesn't need to have validations to be run
|
||||||
@inbox.update_all(new: false) # rubocop:disable Rails/SkipsModelValidations
|
@inbox.update_all(new: false) # rubocop:disable Rails/SkipsModelValidations
|
||||||
|
@ -34,10 +38,11 @@ class InboxController < ApplicationController
|
||||||
user: current_user)
|
user: current_user)
|
||||||
|
|
||||||
inbox = Inbox.create!(user: current_user, question_id: question.id, new: true)
|
inbox = Inbox.create!(user: current_user, question_id: question.id, new: true)
|
||||||
|
services = current_user.services
|
||||||
|
|
||||||
respond_to do |format|
|
respond_to do |format|
|
||||||
format.turbo_stream do
|
format.turbo_stream do
|
||||||
render turbo_stream: turbo_stream.prepend("entries", partial: "inbox/entry", locals: { i: inbox })
|
render turbo_stream: turbo_stream.prepend("entries", partial: "inbox/entry", locals: { i: inbox, services: })
|
||||||
|
|
||||||
inbox.update(new: false)
|
inbox.update(new: false)
|
||||||
end
|
end
|
||||||
|
@ -77,4 +82,9 @@ class InboxController < ApplicationController
|
||||||
.joins(:question)
|
.joins(:question)
|
||||||
.where(questions: { user: @author_user, author_is_anonymous: false })
|
.where(questions: { user: @author_user, author_is_anonymous: false })
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def mark_inbox_entries_as_read
|
||||||
|
# using .dup to not modify @inbox -- useful in tests
|
||||||
|
@inbox&.dup&.update_all(new: false) # rubocop:disable Rails/SkipsModelValidations
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -3,7 +3,13 @@
|
||||||
class ManifestsController < ApplicationController
|
class ManifestsController < ApplicationController
|
||||||
include ThemeHelper
|
include ThemeHelper
|
||||||
|
|
||||||
|
skip_before_action :banned?
|
||||||
|
skip_before_action :find_active_announcements
|
||||||
|
|
||||||
def show
|
def show
|
||||||
|
expires_in 1.day
|
||||||
|
return if fresh_when current_user&.theme
|
||||||
|
|
||||||
render json: {
|
render json: {
|
||||||
name: APP_CONFIG["site_name"],
|
name: APP_CONFIG["site_name"],
|
||||||
description: t("about.index.subtitle"),
|
description: t("about.index.subtitle"),
|
||||||
|
@ -12,17 +18,19 @@ class ManifestsController < ApplicationController
|
||||||
display: "standalone",
|
display: "standalone",
|
||||||
categories: %w[social],
|
categories: %w[social],
|
||||||
lang: I18n.locale,
|
lang: I18n.locale,
|
||||||
shortcuts: [
|
shortcuts:,
|
||||||
webapp_shortcut(inbox_url, t("navigation.inbox"), "inbox")
|
|
||||||
],
|
|
||||||
icons: webapp_icons,
|
icons: webapp_icons,
|
||||||
theme_color: theme_color,
|
theme_color:,
|
||||||
background_color: mobile_theme_color
|
background_color: mobile_theme_color
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
|
def shortcuts = [
|
||||||
|
webapp_shortcut(inbox_url, t("navigation.inbox"), "inbox")
|
||||||
|
]
|
||||||
|
|
||||||
def webapp_shortcut(url, name, icon_name)
|
def webapp_shortcut(url, name, icon_name)
|
||||||
{
|
{
|
||||||
name: name,
|
name: name,
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
class NotificationsController < ApplicationController
|
class NotificationsController < ApplicationController
|
||||||
before_action :authenticate_user!
|
before_action :authenticate_user!
|
||||||
|
|
||||||
|
after_action :mark_notifications_as_read, only: %i[index]
|
||||||
|
|
||||||
TYPE_MAPPINGS = {
|
TYPE_MAPPINGS = {
|
||||||
"answer" => Notification::QuestionAnswered.name,
|
"answer" => Notification::QuestionAnswered.name,
|
||||||
"comment" => Notification::Commented.name,
|
"comment" => Notification::Commented.name,
|
||||||
|
@ -14,8 +16,8 @@ class NotificationsController < ApplicationController
|
||||||
def index
|
def index
|
||||||
@type = TYPE_MAPPINGS[params[:type]] || params[:type]
|
@type = TYPE_MAPPINGS[params[:type]] || params[:type]
|
||||||
@notifications = cursored_notifications_for(type: @type, last_id: params[:last_id])
|
@notifications = cursored_notifications_for(type: @type, last_id: params[:last_id])
|
||||||
@notifications_last_id = @notifications.map(&:id).min
|
paginate_notifications
|
||||||
@more_data_available = !cursored_notifications_for(type: @type, last_id: @notifications_last_id, size: 1).count.zero?
|
@counters = count_unread_by_type
|
||||||
|
|
||||||
respond_to do |format|
|
respond_to do |format|
|
||||||
format.html
|
format.html
|
||||||
|
@ -25,6 +27,22 @@ class NotificationsController < ApplicationController
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
|
def paginate_notifications
|
||||||
|
@notifications_last_id = @notifications.map(&:id).min
|
||||||
|
@more_data_available = !cursored_notifications_for(type: @type, last_id: @notifications_last_id, size: 1).count.zero?
|
||||||
|
end
|
||||||
|
|
||||||
|
def count_unread_by_type
|
||||||
|
Notification.where(recipient: current_user, new: true)
|
||||||
|
.group(:target_type)
|
||||||
|
.count(:target_type)
|
||||||
|
end
|
||||||
|
|
||||||
|
def mark_notifications_as_read
|
||||||
|
# using .dup to not modify @notifications -- useful in tests
|
||||||
|
@notifications&.dup&.update_all(new: false) # rubocop:disable Rails/SkipsModelValidations
|
||||||
|
end
|
||||||
|
|
||||||
def cursored_notifications_for(type:, last_id:, size: nil)
|
def cursored_notifications_for(type:, last_id:, size: nil)
|
||||||
cursor_params = { last_id: last_id, size: size }.compact
|
cursor_params = { last_id: last_id, size: size }.compact
|
||||||
|
|
||||||
|
|
|
@ -8,22 +8,8 @@ class Settings::ThemeController < ApplicationController
|
||||||
def edit; end
|
def edit; end
|
||||||
|
|
||||||
def update
|
def update
|
||||||
update_attributes = params.require(:theme).permit(%i[
|
|
||||||
primary_color primary_text
|
|
||||||
danger_color danger_text
|
|
||||||
success_color success_text
|
|
||||||
warning_color warning_text
|
|
||||||
info_color info_text
|
|
||||||
dark_color dark_text
|
|
||||||
light_color light_text
|
|
||||||
raised_background raised_accent
|
|
||||||
background_color body_text
|
|
||||||
muted_text input_color
|
|
||||||
input_text input_placeholder
|
|
||||||
])
|
|
||||||
|
|
||||||
if current_user.theme.nil?
|
if current_user.theme.nil?
|
||||||
current_user.theme = Theme.new update_attributes
|
current_user.theme = Theme.new theme_attributes
|
||||||
current_user.theme.user_id = current_user.id
|
current_user.theme.user_id = current_user.id
|
||||||
|
|
||||||
if current_user.theme.save
|
if current_user.theme.save
|
||||||
|
@ -31,7 +17,7 @@ class Settings::ThemeController < ApplicationController
|
||||||
else
|
else
|
||||||
flash[:error] = t(".error", errors: current_user.theme.errors.messages.flatten.join(" "))
|
flash[:error] = t(".error", errors: current_user.theme.errors.messages.flatten.join(" "))
|
||||||
end
|
end
|
||||||
elsif current_user.theme.update(update_attributes)
|
elsif current_user.theme.update(theme_attributes)
|
||||||
flash[:success] = t(".success")
|
flash[:success] = t(".success")
|
||||||
else
|
else
|
||||||
flash[:error] = t(".error", errors: current_user.theme.errors.messages.flatten.join(" "))
|
flash[:error] = t(".error", errors: current_user.theme.errors.messages.flatten.join(" "))
|
||||||
|
@ -43,4 +29,23 @@ class Settings::ThemeController < ApplicationController
|
||||||
current_user.theme.destroy!
|
current_user.theme.destroy!
|
||||||
redirect_to edit_settings_theme_path
|
redirect_to edit_settings_theme_path
|
||||||
end
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def theme_attributes
|
||||||
|
params.require(:theme).permit(%i[
|
||||||
|
primary_color primary_text
|
||||||
|
danger_color danger_text
|
||||||
|
success_color success_text
|
||||||
|
warning_color warning_text
|
||||||
|
info_color info_text
|
||||||
|
dark_color dark_text
|
||||||
|
light_color light_text
|
||||||
|
raised_background raised_accent
|
||||||
|
raised_text raised_accent_text
|
||||||
|
background_color body_text
|
||||||
|
muted_text input_color
|
||||||
|
input_text input_placeholder
|
||||||
|
])
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -3,20 +3,13 @@
|
||||||
class UserController < ApplicationController
|
class UserController < ApplicationController
|
||||||
before_action :set_user
|
before_action :set_user
|
||||||
before_action :hidden_social_graph_redirect, only: %i[followers followings]
|
before_action :hidden_social_graph_redirect, only: %i[followers followings]
|
||||||
|
after_action :mark_notification_as_read, only: %i[show]
|
||||||
|
|
||||||
def show
|
def show
|
||||||
@answers = @user.cursored_answers(last_id: params[:last_id])
|
@answers = @user.cursored_answers(last_id: params[:last_id])
|
||||||
@answers_last_id = @answers.map(&:id).min
|
@answers_last_id = @answers.map(&:id).min
|
||||||
@more_data_available = !@user.cursored_answers(last_id: @answers_last_id, size: 1).count.zero?
|
@more_data_available = !@user.cursored_answers(last_id: @answers_last_id, size: 1).count.zero?
|
||||||
|
|
||||||
if user_signed_in?
|
|
||||||
notif = Notification.where(target_type: "Relationship", target_id: @user.active_follow_relationships.where(target_id: current_user.id).pluck(:id), recipient_id: current_user.id, new: true).first
|
|
||||||
unless notif.nil?
|
|
||||||
notif.new = false
|
|
||||||
notif.save
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
respond_to do |format|
|
respond_to do |format|
|
||||||
format.html
|
format.html
|
||||||
format.turbo_stream
|
format.turbo_stream
|
||||||
|
@ -24,36 +17,40 @@ class UserController < ApplicationController
|
||||||
end
|
end
|
||||||
|
|
||||||
def followers
|
def followers
|
||||||
@title = "Followers"
|
paginate_relationships(:cursored_follower_relationships)
|
||||||
@relationships = @user.cursored_follower_relationships(last_id: params[:last_id])
|
|
||||||
@relationships_last_id = @relationships.map(&:id).min
|
|
||||||
@more_data_available = !@user.cursored_follower_relationships(last_id: @relationships_last_id, size: 1).count.zero?
|
|
||||||
@users = @relationships.map(&:source)
|
@users = @relationships.map(&:source)
|
||||||
@type = :follower
|
own_relationships = find_own_relationships
|
||||||
|
locals = {
|
||||||
|
type: :follower,
|
||||||
|
own_followings: own_relationships[Relationships::Follow],
|
||||||
|
own_blocks: own_relationships[Relationships::Block],
|
||||||
|
own_mutes: own_relationships[Relationships::Mute]
|
||||||
|
}
|
||||||
|
|
||||||
respond_to do |format|
|
respond_to do |format|
|
||||||
format.html { render "show_follow" }
|
format.html { render "show_follow", locals: }
|
||||||
format.turbo_stream { render "show_follow" }
|
format.turbo_stream { render "show_follow", locals: }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def followings
|
def followings
|
||||||
@title = "Following"
|
paginate_relationships(:cursored_following_relationships)
|
||||||
@relationships = @user.cursored_following_relationships(last_id: params[:last_id])
|
|
||||||
@relationships_last_id = @relationships.map(&:id).min
|
|
||||||
@more_data_available = !@user.cursored_following_relationships(last_id: @relationships_last_id, size: 1).count.zero?
|
|
||||||
@users = @relationships.map(&:target)
|
@users = @relationships.map(&:target)
|
||||||
@type = :friend
|
own_relationships = find_own_relationships
|
||||||
|
locals = {
|
||||||
|
type: :friend,
|
||||||
|
own_followings: own_relationships[Relationships::Follow],
|
||||||
|
own_blocks: own_relationships[Relationships::Block],
|
||||||
|
own_mutes: own_relationships[Relationships::Mute]
|
||||||
|
}
|
||||||
|
|
||||||
respond_to do |format|
|
respond_to do |format|
|
||||||
format.html { render "show_follow" }
|
format.html { render "show_follow", locals: }
|
||||||
format.turbo_stream { render "show_follow" }
|
format.turbo_stream { render "show_follow", locals: }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def questions
|
def questions
|
||||||
@title = "Questions"
|
|
||||||
|
|
||||||
@questions = @user.cursored_questions(author_is_anonymous: false, direct: direct_param, last_id: params[:last_id])
|
@questions = @user.cursored_questions(author_is_anonymous: false, direct: direct_param, last_id: params[:last_id])
|
||||||
@questions_last_id = @questions.map(&:id).min
|
@questions_last_id = @questions.map(&:id).min
|
||||||
@more_data_available = !@user.cursored_questions(author_is_anonymous: false, direct: direct_param, last_id: @questions_last_id, size: 1).count.zero?
|
@more_data_available = !@user.cursored_questions(author_is_anonymous: false, direct: direct_param, last_id: @questions_last_id, size: 1).count.zero?
|
||||||
|
@ -66,10 +63,36 @@ class UserController < ApplicationController
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
|
def mark_notification_as_read
|
||||||
|
return unless user_signed_in?
|
||||||
|
|
||||||
|
Notification
|
||||||
|
.where(
|
||||||
|
target_type: "Relationship",
|
||||||
|
target_id: @user.active_follow_relationships.where(target_id: current_user.id).pluck(:id),
|
||||||
|
recipient_id: current_user.id,
|
||||||
|
new: true
|
||||||
|
).update(new: false)
|
||||||
|
end
|
||||||
|
|
||||||
def set_user
|
def set_user
|
||||||
@user = User.where("LOWER(screen_name) = ?", params[:username].downcase).includes(:profile).first!
|
@user = User.where("LOWER(screen_name) = ?", params[:username].downcase).includes(:profile).first!
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def find_own_relationships
|
||||||
|
return {} unless user_signed_in?
|
||||||
|
|
||||||
|
Relationship.where(source: current_user, target_id: @users.map(&:id))
|
||||||
|
&.select(:target_id, :type)
|
||||||
|
&.group_by(&:type)
|
||||||
|
end
|
||||||
|
|
||||||
|
def paginate_relationships(method)
|
||||||
|
@relationships = @user.public_send(method, last_id: params[:last_id])
|
||||||
|
@relationships_last_id = @relationships.map(&:id).min
|
||||||
|
@more_data_available = !@user.public_send(method, last_id: @relationships_last_id, size: 1).count.zero?
|
||||||
|
end
|
||||||
|
|
||||||
def hidden_social_graph_redirect
|
def hidden_social_graph_redirect
|
||||||
return if belongs_to_current_user? || !@user.privacy_hide_social_graph
|
return if belongs_to_current_user? || !@user.privacy_hide_social_graph
|
||||||
|
|
||||||
|
|
|
@ -2,28 +2,30 @@
|
||||||
|
|
||||||
module ThemeHelper
|
module ThemeHelper
|
||||||
ATTRIBUTE_MAP = {
|
ATTRIBUTE_MAP = {
|
||||||
"primary_color" => %w[primary primary-rgb],
|
"primary_color" => %w[primary primary-rgb],
|
||||||
"primary_text" => "primary-text",
|
"primary_text" => "primary-text",
|
||||||
"danger_color" => "danger",
|
"danger_color" => "danger",
|
||||||
"danger_text" => "danger-text",
|
"danger_text" => "danger-text",
|
||||||
"warning_color" => "warning",
|
"warning_color" => "warning",
|
||||||
"warning_text" => "warning-text",
|
"warning_text" => "warning-text",
|
||||||
"info_color" => "info",
|
"info_color" => "info",
|
||||||
"info_text" => "info-text",
|
"info_text" => "info-text",
|
||||||
"success_color" => "success",
|
"success_color" => "success",
|
||||||
"success_text" => "success-text",
|
"success_text" => "success-text",
|
||||||
"dark_color" => "dark",
|
"dark_color" => "dark",
|
||||||
"dark_text" => "dark-text",
|
"dark_text" => "dark-text",
|
||||||
"light_color" => "light",
|
"light_color" => "light",
|
||||||
"light_text" => "light-text",
|
"light_text" => "light-text",
|
||||||
"raised_background" => %w[raised-bg raised-bg-rgb],
|
"raised_background" => %w[raised-bg raised-bg-rgb],
|
||||||
"raised_accent" => %w[raised-accent raised-accent-rgb],
|
"raised_text" => "raised-text",
|
||||||
"background_color" => "background",
|
"raised_accent" => %w[raised-accent raised-accent-rgb],
|
||||||
"body_text" => "body-text",
|
"raised_accent_text" => "raised-accent-text",
|
||||||
"input_color" => "input-bg",
|
"background_color" => "background",
|
||||||
"input_text" => "input-text",
|
"body_text" => "body-text",
|
||||||
"input_placeholder" => "input-placeholder",
|
"input_color" => "input-bg",
|
||||||
"muted_text" => "muted-text"
|
"input_text" => "input-text",
|
||||||
|
"input_placeholder" => "input-placeholder",
|
||||||
|
"muted_text" => "muted-text"
|
||||||
}.freeze
|
}.freeze
|
||||||
|
|
||||||
def render_theme
|
def render_theme
|
||||||
|
|
|
@ -0,0 +1,49 @@
|
||||||
|
import { Controller } from '@hotwired/stimulus';
|
||||||
|
import Croppr from 'croppr';
|
||||||
|
|
||||||
|
export default class extends Controller {
|
||||||
|
static targets = ['input', 'controls', 'cropper', 'x', 'y', 'w', 'h'];
|
||||||
|
|
||||||
|
declare readonly inputTarget: HTMLInputElement;
|
||||||
|
declare readonly controlsTarget: HTMLElement;
|
||||||
|
declare readonly cropperTarget: HTMLImageElement;
|
||||||
|
declare readonly xTarget: HTMLInputElement;
|
||||||
|
declare readonly yTarget: HTMLInputElement;
|
||||||
|
declare readonly wTarget: HTMLInputElement;
|
||||||
|
declare readonly hTarget: HTMLInputElement;
|
||||||
|
|
||||||
|
static values = {
|
||||||
|
aspectRatio: String
|
||||||
|
};
|
||||||
|
|
||||||
|
declare readonly aspectRatioValue: string;
|
||||||
|
|
||||||
|
readImage(file: File, callback: (string) => void): void {
|
||||||
|
callback((window.URL || window.webkitURL).createObjectURL(file));
|
||||||
|
}
|
||||||
|
|
||||||
|
updateValues(data: Record<string, string>): void {
|
||||||
|
this.xTarget.value = data.x;
|
||||||
|
this.yTarget.value = data.y;
|
||||||
|
this.wTarget.value = data.width;
|
||||||
|
this.hTarget.value = data.height;
|
||||||
|
}
|
||||||
|
|
||||||
|
change(): void {
|
||||||
|
this.controlsTarget.classList.toggle('d-none');
|
||||||
|
|
||||||
|
if (this.inputTarget.files && this.inputTarget.files[0]) {
|
||||||
|
this.readImage(this.inputTarget.files[0], (src) => {
|
||||||
|
this.cropperTarget.src = src;
|
||||||
|
|
||||||
|
new Croppr(this.cropperTarget, {
|
||||||
|
aspectRatio: parseFloat(this.aspectRatioValue),
|
||||||
|
startSize: [100, 100, '%'],
|
||||||
|
onCropStart: this.updateValues.bind(this),
|
||||||
|
onCropMove: this.updateValues.bind(this),
|
||||||
|
onCropEnd: this.updateValues.bind(this)
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,6 +0,0 @@
|
||||||
export function authorSearchHandler(event: Event): void {
|
|
||||||
event.preventDefault();
|
|
||||||
|
|
||||||
const author = document.querySelector<HTMLInputElement>('#author')?.value;
|
|
||||||
window.location.href = `/inbox/${encodeURIComponent(author)}`;
|
|
||||||
}
|
|
|
@ -62,6 +62,7 @@ export function deleteAllQuestionsHandler(event: Event): void {
|
||||||
export function deleteAllAuthorQuestionsHandler(event: Event): void {
|
export function deleteAllAuthorQuestionsHandler(event: Event): void {
|
||||||
const button = event.target as Element;
|
const button = event.target as Element;
|
||||||
const count = button.getAttribute('data-ib-count');
|
const count = button.getAttribute('data-ib-count');
|
||||||
|
const urlSearchParams = new URLSearchParams(window.location.search);
|
||||||
|
|
||||||
swal({
|
swal({
|
||||||
title: I18n.translate('frontend.inbox.confirm_all.title', { count: count }),
|
title: I18n.translate('frontend.inbox.confirm_all.title', { count: count }),
|
||||||
|
@ -75,7 +76,7 @@ export function deleteAllAuthorQuestionsHandler(event: Event): void {
|
||||||
}, (returnValue) => {
|
}, (returnValue) => {
|
||||||
if (returnValue === null) return false;
|
if (returnValue === null) return false;
|
||||||
|
|
||||||
post(`/ajax/delete_all_inbox/${location.pathname.split('/')[2]}`)
|
post(`/ajax/delete_all_inbox/${urlSearchParams.get('author')}`)
|
||||||
.then(async response => {
|
.then(async response => {
|
||||||
const data = await response.json;
|
const data = await response.json;
|
||||||
|
|
||||||
|
|
|
@ -6,8 +6,7 @@ import { deleteAllAuthorQuestionsHandler, deleteAllQuestionsHandler } from './de
|
||||||
export default (): void => {
|
export default (): void => {
|
||||||
registerEvents([
|
registerEvents([
|
||||||
{ type: 'click', target: '#ib-delete-all', handler: deleteAllQuestionsHandler, global: true },
|
{ type: 'click', target: '#ib-delete-all', handler: deleteAllQuestionsHandler, global: true },
|
||||||
{ type: 'click', target: '#ib-delete-all-author', handler: deleteAllAuthorQuestionsHandler, global: true },
|
{ type: 'click', target: '#ib-delete-all-author', handler: deleteAllAuthorQuestionsHandler, global: true }
|
||||||
{ type: 'submit', target: '#author-form', handler: authorSearchHandler, global: true }
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
registerInboxEntryEvents();
|
registerInboxEntryEvents();
|
||||||
|
|
|
@ -1,61 +0,0 @@
|
||||||
import Croppr from 'croppr';
|
|
||||||
|
|
||||||
const readImage = (file, callback) => callback((window.URL || window.webkitURL).createObjectURL(file));
|
|
||||||
|
|
||||||
export function profilePictureChangeHandler(event: Event): void {
|
|
||||||
const input = event.target as HTMLInputElement;
|
|
||||||
|
|
||||||
const cropControls = document.querySelector('#profile-picture-crop-controls');
|
|
||||||
cropControls.classList.toggle('d-none');
|
|
||||||
|
|
||||||
if (input.files && input.files[0]) {
|
|
||||||
readImage(input.files[0], (src) => {
|
|
||||||
const updateValues = (data) => {
|
|
||||||
document.querySelector<HTMLInputElement>('#profile_picture_x').value = data.x;
|
|
||||||
document.querySelector<HTMLInputElement>('#profile_picture_y').value = data.y;
|
|
||||||
document.querySelector<HTMLInputElement>('#profile_picture_w').value = data.width;
|
|
||||||
document.querySelector<HTMLInputElement>('#profile_picture_h').value = data.height;
|
|
||||||
}
|
|
||||||
|
|
||||||
const cropper = document.querySelector<HTMLImageElement>('#profile-picture-cropper');
|
|
||||||
cropper.src = src;
|
|
||||||
|
|
||||||
new Croppr(cropper, {
|
|
||||||
aspectRatio: 1,
|
|
||||||
startSize: [100, 100, '%'],
|
|
||||||
onCropStart: updateValues,
|
|
||||||
onCropMove: updateValues,
|
|
||||||
onCropEnd: updateValues
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function profileHeaderChangeHandler(event: Event): void {
|
|
||||||
const input = event.target as HTMLInputElement;
|
|
||||||
|
|
||||||
const cropControls = document.querySelector('#profile-header-crop-controls');
|
|
||||||
cropControls.classList.toggle('d-none');
|
|
||||||
|
|
||||||
if (input.files && input.files[0]) {
|
|
||||||
readImage(input.files[0], (src) => {
|
|
||||||
const updateValues = (data) => {
|
|
||||||
document.querySelector<HTMLInputElement>('#profile_header_x').value = data.x;
|
|
||||||
document.querySelector<HTMLInputElement>('#profile_header_y').value = data.y;
|
|
||||||
document.querySelector<HTMLInputElement>('#profile_header_w').value = data.width;
|
|
||||||
document.querySelector<HTMLInputElement>('#profile_header_h').value = data.height;
|
|
||||||
}
|
|
||||||
|
|
||||||
const cropper = document.querySelector<HTMLImageElement>('#profile-header-cropper');
|
|
||||||
cropper.src = src;
|
|
||||||
|
|
||||||
new Croppr(cropper, {
|
|
||||||
aspectRatio: 7/30,
|
|
||||||
startSize: [100, 100, '%'],
|
|
||||||
onCropStart: updateValues,
|
|
||||||
onCropMove: updateValues,
|
|
||||||
onCropEnd: updateValues
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,11 +1,8 @@
|
||||||
import registerEvents from "utilities/registerEvents";
|
import registerEvents from "utilities/registerEvents";
|
||||||
import { profileHeaderChangeHandler, profilePictureChangeHandler } from "./crop";
|
|
||||||
import { userSubmitHandler } from "./password";
|
import { userSubmitHandler } from "./password";
|
||||||
|
|
||||||
export default (): void => {
|
export default (): void => {
|
||||||
registerEvents([
|
registerEvents([
|
||||||
{ type: 'submit', target: document.querySelector('#edit_user'), handler: userSubmitHandler },
|
{ type: 'submit', target: document.querySelector('#edit_user'), handler: userSubmitHandler }
|
||||||
{ type: 'change', target: document.querySelector('#user_profile_picture[type=file]'), handler: profilePictureChangeHandler },
|
|
||||||
{ type: 'change', target: document.querySelector('#user_profile_header[type=file]'), handler: profileHeaderChangeHandler }
|
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ import FormatPopupController from "retrospring/controllers/format_popup_controll
|
||||||
import CollapseController from "retrospring/controllers/collapse_controller";
|
import CollapseController from "retrospring/controllers/collapse_controller";
|
||||||
import ThemeController from "retrospring/controllers/theme_controller";
|
import ThemeController from "retrospring/controllers/theme_controller";
|
||||||
import CapabilitiesController from "retrospring/controllers/capabilities_controller";
|
import CapabilitiesController from "retrospring/controllers/capabilities_controller";
|
||||||
|
import CropperController from "retrospring/controllers/cropper_controller";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This module sets up Stimulus and our controllers
|
* This module sets up Stimulus and our controllers
|
||||||
|
@ -23,6 +24,7 @@ export default function (): void {
|
||||||
window['Stimulus'].register('character-count', CharacterCountController);
|
window['Stimulus'].register('character-count', CharacterCountController);
|
||||||
window['Stimulus'].register('character-count-warning', CharacterCountWarningController);
|
window['Stimulus'].register('character-count-warning', CharacterCountWarningController);
|
||||||
window['Stimulus'].register('collapse', CollapseController);
|
window['Stimulus'].register('collapse', CollapseController);
|
||||||
|
window['Stimulus'].register('cropper', CropperController);
|
||||||
window['Stimulus'].register('format-popup', FormatPopupController);
|
window['Stimulus'].register('format-popup', FormatPopupController);
|
||||||
window['Stimulus'].register('theme', ThemeController);
|
window['Stimulus'].register('theme', ThemeController);
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,9 @@ export const THEME_MAPPING = {
|
||||||
'light_color': 'light',
|
'light_color': 'light',
|
||||||
'light_text': 'light-text',
|
'light_text': 'light-text',
|
||||||
'raised_background': 'raised-bg',
|
'raised_background': 'raised-bg',
|
||||||
|
'raised_text': 'raised-text',
|
||||||
'raised_accent': 'raised-accent',
|
'raised_accent': 'raised-accent',
|
||||||
|
'raised_accent_text': 'raised-accent-text',
|
||||||
'background_color': 'background',
|
'background_color': 'background',
|
||||||
'body_text': 'body-text',
|
'body_text': 'body-text',
|
||||||
'input_color': 'input-bg',
|
'input_color': 'input-bg',
|
||||||
|
|
|
@ -11,11 +11,11 @@ class Notification < ApplicationRecord
|
||||||
define_cursor_paginator :cursored_for_type, :for_type
|
define_cursor_paginator :cursored_for_type, :for_type
|
||||||
|
|
||||||
def for(recipient, **kwargs)
|
def for(recipient, **kwargs)
|
||||||
where(kwargs.merge!(recipient:)).order(:created_at).reverse_order
|
where(kwargs.merge!(recipient:)).includes(:target).order(:created_at).reverse_order
|
||||||
end
|
end
|
||||||
|
|
||||||
def for_type(recipient, type, **kwargs)
|
def for_type(recipient, type, **kwargs)
|
||||||
where(kwargs.merge!(recipient:)).where(type:).order(:created_at).reverse_order
|
where(kwargs.merge!(recipient:)).includes(:target).where(type:).order(:created_at).reverse_order
|
||||||
end
|
end
|
||||||
|
|
||||||
def notify(recipient, target)
|
def notify(recipient, target)
|
||||||
|
|
|
@ -5,10 +5,11 @@ module User::AnswerMethods
|
||||||
|
|
||||||
define_cursor_paginator :cursored_answers, :ordered_answers
|
define_cursor_paginator :cursored_answers, :ordered_answers
|
||||||
|
|
||||||
|
# @return [ActiveRecord::Relation<Answer>] List of a user's answers
|
||||||
def ordered_answers
|
def ordered_answers
|
||||||
answers
|
answers
|
||||||
.order(:created_at)
|
.order(:created_at)
|
||||||
.reverse_order
|
.reverse_order
|
||||||
.includes(comments: [:user, :smiles], question: [:user], smiles: [:user])
|
.includes(comments: %i[user smiles], question: { user: :profile }, smiles: [:user])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -5,9 +5,10 @@ module User::InboxMethods
|
||||||
|
|
||||||
define_cursor_paginator :cursored_inbox, :ordered_inbox
|
define_cursor_paginator :cursored_inbox, :ordered_inbox
|
||||||
|
|
||||||
|
# @return [ActiveRecord::Relation<Inbox>] the user's inbox entries
|
||||||
def ordered_inbox
|
def ordered_inbox
|
||||||
inboxes
|
inboxes
|
||||||
.includes(:question, :user)
|
.includes(:question, user: :profile)
|
||||||
.order(:created_at)
|
.order(:created_at)
|
||||||
.reverse_order
|
.reverse_order
|
||||||
end
|
end
|
||||||
|
|
|
@ -5,6 +5,7 @@ module User::QuestionMethods
|
||||||
|
|
||||||
define_cursor_paginator :cursored_questions, :ordered_questions
|
define_cursor_paginator :cursored_questions, :ordered_questions
|
||||||
|
|
||||||
|
# @return [ActiveRecord::Relation<Question>] List of questions sent by the user
|
||||||
def ordered_questions(author_is_anonymous: nil, direct: nil)
|
def ordered_questions(author_is_anonymous: nil, direct: nil)
|
||||||
questions
|
questions
|
||||||
.where({ author_is_anonymous:, direct: }.compact)
|
.where({ author_is_anonymous:, direct: }.compact)
|
||||||
|
|
|
@ -6,10 +6,12 @@ module User::RelationshipMethods
|
||||||
define_cursor_paginator :cursored_following_relationships, :ordered_following_relationships
|
define_cursor_paginator :cursored_following_relationships, :ordered_following_relationships
|
||||||
define_cursor_paginator :cursored_follower_relationships, :ordered_follower_relationships
|
define_cursor_paginator :cursored_follower_relationships, :ordered_follower_relationships
|
||||||
|
|
||||||
|
# @return [ActiveRecord::Relation<Relationships::Follow>] List of the user's following relationships
|
||||||
def ordered_following_relationships
|
def ordered_following_relationships
|
||||||
active_follow_relationships.reverse_order.includes(target: [:profile])
|
active_follow_relationships.reverse_order.includes(target: [:profile])
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# @return [ActiveRecord::Relation<Relationships::Follow>] List of the user's follower relationships
|
||||||
def ordered_follower_relationships
|
def ordered_follower_relationships
|
||||||
passive_follow_relationships.reverse_order.includes(source: [:profile])
|
passive_follow_relationships.reverse_order.includes(source: [:profile])
|
||||||
end
|
end
|
||||||
|
|
|
@ -5,8 +5,12 @@ module User::TimelineMethods
|
||||||
|
|
||||||
define_cursor_paginator :cursored_timeline, :timeline
|
define_cursor_paginator :cursored_timeline, :timeline
|
||||||
|
|
||||||
# @return [Array] the users' timeline
|
# @return [ActiveRecord::Relation<Answer>] the user's timeline
|
||||||
def timeline
|
def timeline
|
||||||
Answer.where("user_id in (?) OR user_id = ?", following_ids, id).order(:created_at).reverse_order.includes(comments: %i[user smiles], question: [:user], user: [:profile], smiles: [:user])
|
Answer
|
||||||
|
.where("user_id in (?) OR user_id = ?", following_ids, id)
|
||||||
|
.order(:created_at)
|
||||||
|
.reverse_order
|
||||||
|
.includes(comments: %i[user smiles], question: { user: :profile }, user: [:profile], smiles: [:user])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -7,6 +7,7 @@ class TypoedEmailValidator < ActiveModel::EachValidator
|
||||||
INVALID_ENDINGS = [
|
INVALID_ENDINGS = [
|
||||||
# with @:
|
# with @:
|
||||||
*%w[
|
*%w[
|
||||||
|
aoo.com
|
||||||
fmail.com
|
fmail.com
|
||||||
gail.com
|
gail.com
|
||||||
gamil.com
|
gamil.com
|
||||||
|
@ -19,6 +20,7 @@ class TypoedEmailValidator < ActiveModel::EachValidator
|
||||||
gmaile.com
|
gmaile.com
|
||||||
gmaill.com
|
gmaill.com
|
||||||
gmali.com
|
gmali.com
|
||||||
|
gmaul.com
|
||||||
gnail.com
|
gnail.com
|
||||||
hotamil.com
|
hotamil.com
|
||||||
hotmai.com
|
hotmai.com
|
||||||
|
|
|
@ -40,9 +40,9 @@
|
||||||
= render "shared/format_link"
|
= render "shared/format_link"
|
||||||
.card-footer.d-none{ id: "ib-options-#{i.id}" }
|
.card-footer.d-none{ id: "ib-options-#{i.id}" }
|
||||||
%h4= t(".sharing.heading")
|
%h4= t(".sharing.heading")
|
||||||
- if current_user.services.count.positive?
|
- if services.count.positive?
|
||||||
.row
|
.row
|
||||||
- current_user.services.each do |service|
|
- services.each do |service|
|
||||||
.col-md-3.col-sm-4.col-xs-6
|
.col-md-3.col-sm-4.col-xs-6
|
||||||
%label
|
%label
|
||||||
%input{ type: "checkbox", name: "ib-share", checked: :checked, data: { ib_id: i.id, service: service.provider } }
|
%input{ type: "checkbox", name: "ib-share", checked: :checked, data: { ib_id: i.id, service: service.provider } }
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#entries
|
#entries
|
||||||
- @inbox.each do |i|
|
- @inbox.each do |i|
|
||||||
= render "inbox/entry", i:
|
= render "inbox/entry", services:, i:
|
||||||
|
|
||||||
- if @inbox.empty?
|
- if @inbox.empty?
|
||||||
%p.empty= t(".empty")
|
%p.empty= t(".empty")
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
= turbo_stream.append "entries" do
|
= turbo_stream.append "entries" do
|
||||||
- @inbox.each do |i|
|
- @inbox.each do |i|
|
||||||
= render "inbox/entry", i:
|
= render "inbox/entry", services:, i:
|
||||||
|
|
||||||
= turbo_stream.update "paginator" do
|
= turbo_stream.update "paginator" do
|
||||||
- if @more_data_available
|
- if @more_data_available
|
||||||
|
|
|
@ -9,6 +9,5 @@
|
||||||
= render 'shared/links'
|
= render 'shared/links'
|
||||||
|
|
||||||
:ruby
|
:ruby
|
||||||
@inbox.update_all(new: false)
|
|
||||||
provide(:title, generate_title('Inbox'))
|
provide(:title, generate_title('Inbox'))
|
||||||
parent_layout 'base'
|
parent_layout 'base'
|
||||||
|
|
|
@ -8,5 +8,4 @@
|
||||||
.d-block.d-sm-none= render "shared/links"
|
.d-block.d-sm-none= render "shared/links"
|
||||||
|
|
||||||
:ruby
|
:ruby
|
||||||
Notification.for(current_user).update_all(new: false)
|
|
||||||
parent_layout 'base'
|
parent_layout 'base'
|
||||||
|
|
|
@ -2,36 +2,38 @@
|
||||||
.card-body
|
.card-body
|
||||||
= bootstrap_form_for(current_user, url: settings_profile_picture_path, html: { multipart: true }, method: :patch, data: { turbo: false }) do |f|
|
= bootstrap_form_for(current_user, url: settings_profile_picture_path, html: { multipart: true }, method: :patch, data: { turbo: false }) do |f|
|
||||||
|
|
||||||
.d-flex#profile-picture-media
|
%div{ data: { controller: "cropper", cropper_aspect_ratio_value: "1" } }
|
||||||
.flex-shrink-0
|
.d-flex
|
||||||
%img.avatar-lg.me-3{ src: current_user.profile_picture.url(:medium) }
|
.flex-shrink-0
|
||||||
.flex-grow-1
|
%img.avatar-lg.me-3{ src: current_user.profile_picture.url(:medium) }
|
||||||
= f.file_field :profile_picture, accept: APP_CONFIG[:accepted_image_formats].join(",")
|
.flex-grow-1
|
||||||
|
= f.file_field :profile_picture, accept: APP_CONFIG[:accepted_image_formats].join(","), data: { cropper_target: "input", action: "cropper#change" }
|
||||||
|
|
||||||
.row.d-none#profile-picture-crop-controls
|
.row.d-none{ data: { cropper_target: "controls" } }
|
||||||
.col-sm-10.col-md-8
|
.col-sm-10.col-md-8
|
||||||
%strong= t(".adjust.profile_picture")
|
%strong= t(".adjust.profile_picture")
|
||||||
%img#profile-picture-cropper{ src: current_user.profile_picture.url(:medium) }
|
%img{ src: current_user.profile_picture.url(:medium), data: { cropper_target: "cropper" } }
|
||||||
|
|
||||||
.row.mb-2#profile-header-media
|
- %i[profile_picture_x profile_picture_y profile_picture_w profile_picture_h].each do |attrib|
|
||||||
.col-xs-12.col-md-6
|
= f.hidden_field attrib, id: attrib, data: { cropper_target: attrib.to_s.split("_").last }
|
||||||
%img.mw-100.me-3{ src: current_user.profile_header.url(:mobile) }
|
|
||||||
.col-xs-12.col-md-6.mt-3.mt-sm-0.ps-3.pe-3
|
|
||||||
= f.file_field :profile_header, accept: APP_CONFIG[:accepted_image_formats].join(",")
|
|
||||||
|
|
||||||
.row.d-none#profile-header-crop-controls
|
%div{ data: { controller: "cropper", cropper_aspect_ratio_value: "0.23" } }
|
||||||
.col-sm-10.col-md-8
|
.row.mb-2
|
||||||
%strong= t(".adjust.profile_header")
|
.col-xs-12.col-md-6
|
||||||
%img#profile-header-cropper{ src: current_user.profile_header.url(:web) }
|
%img.mw-100.me-3{ src: current_user.profile_header.url(:mobile) }
|
||||||
|
.col-xs-12.col-md-6.mt-3.mt-sm-0.ps-3.pe-3
|
||||||
|
= f.file_field :profile_header, accept: APP_CONFIG[:accepted_image_formats].join(","), data: { cropper_target: "input", action: "cropper#change" }
|
||||||
|
|
||||||
|
.row.d-none{ data: { cropper_target: "controls" } }
|
||||||
|
.col-sm-10.col-md-8
|
||||||
|
%strong= t(".adjust.profile_header")
|
||||||
|
%img{ src: current_user.profile_header.url(:web), data: { cropper_target: "cropper" } }
|
||||||
|
|
||||||
|
- %i[profile_header_x profile_header_y profile_header_w profile_header_h].each do |attrib|
|
||||||
|
= f.hidden_field attrib, id: attrib, data: { cropper_target: attrib.to_s.split("_").last }
|
||||||
|
|
||||||
= f.check_box :show_foreign_themes
|
= f.check_box :show_foreign_themes
|
||||||
|
|
||||||
- %i[profile_picture_x profile_picture_y profile_picture_w profile_picture_h].each do |attrib|
|
|
||||||
= f.hidden_field attrib, id: attrib
|
|
||||||
|
|
||||||
- %i[profile_header_x profile_header_y profile_header_w profile_header_h].each do |attrib|
|
|
||||||
= f.hidden_field attrib, id: attrib
|
|
||||||
|
|
||||||
= f.primary t(".submit_picture")
|
= f.primary t(".submit_picture")
|
||||||
.card
|
.card
|
||||||
.card-body
|
.card-body
|
||||||
|
|
|
@ -21,6 +21,23 @@
|
||||||
= f.text_field :background_color, class: "color", data: { default: 0xF0EDF4, theme_target: "color", action: "theme#updatePreview" }
|
= f.text_field :background_color, class: "color", data: { default: 0xF0EDF4, theme_target: "color", action: "theme#updatePreview" }
|
||||||
.col-sm-6
|
.col-sm-6
|
||||||
= f.text_field :body_text, class: "color", data: { default: 0x000000, theme_target: "color", action: "theme#updatePreview" }
|
= f.text_field :body_text, class: "color", data: { default: 0x000000, theme_target: "color", action: "theme#updatePreview" }
|
||||||
|
.card
|
||||||
|
.card-body
|
||||||
|
%h2= t(".raised.heading")
|
||||||
|
%p= t(".raised.body")
|
||||||
|
|
||||||
|
.row
|
||||||
|
.col-sm-6
|
||||||
|
= f.text_field :raised_background, class: "color", data: { default: 0xFFFFFF, theme_target: "color", action: "theme#updatePreview" }
|
||||||
|
.col-sm-6
|
||||||
|
= f.text_field :raised_text, class: "color", data: { default: 0x000000, theme_target: "color", action: "theme#updatePreview" }
|
||||||
|
.row
|
||||||
|
.col-sm-6
|
||||||
|
= f.text_field :raised_accent, class: "color", data: { default: 0xF7F7F7, theme_target: "color", action: "theme#updatePreview" }
|
||||||
|
.col-sm-6
|
||||||
|
= f.text_field :raised_accent_text, class: "color", data: { default: 0x000000, theme_target: "color", action: "theme#updatePreview" }
|
||||||
|
.card-footer
|
||||||
|
%p= t(".raised.accent.example")
|
||||||
.card
|
.card
|
||||||
.card-body
|
.card-body
|
||||||
%h2= t(".colors.heading")
|
%h2= t(".colors.heading")
|
||||||
|
@ -93,23 +110,11 @@
|
||||||
|
|
||||||
.row
|
.row
|
||||||
.col-sm-6
|
.col-sm-6
|
||||||
= f.text_field :input_placeholder, class: "color", data: { default: 0x6C757D, theme_target: "color" }
|
= f.text_field :input_placeholder, class: "color", data: { default: 0x6C757D, theme_target: "color", action: "theme#updatePreview" }
|
||||||
.col-sm-6
|
.col-sm-6
|
||||||
.form-group
|
.form-group
|
||||||
%label.form-label Example Input
|
%label.form-label Example Input
|
||||||
%input.form-control{ placeholder: "A test placeholder" }
|
%input.form-control{ placeholder: "A test placeholder" }
|
||||||
.card
|
|
||||||
.card-body
|
|
||||||
%h2= t(".raised.heading")
|
|
||||||
%p= t(".raised.body")
|
|
||||||
|
|
||||||
.row
|
|
||||||
.col-sm-6
|
|
||||||
= f.text_field :raised_background, class: "color", data: { default: 0xFFFFFF, theme_target: "color" }
|
|
||||||
.col-sm-6
|
|
||||||
= f.text_field :raised_accent, class: "color", data: { default: 0xF7F7F7, theme_target: "color" }
|
|
||||||
.card-footer
|
|
||||||
%p= t(".raised.accent.example")
|
|
||||||
.card
|
.card
|
||||||
.card-body
|
.card-body
|
||||||
.pull-left
|
.pull-left
|
||||||
|
|
|
@ -9,4 +9,4 @@
|
||||||
= user.profile.display_name
|
= user.profile.display_name
|
||||||
.profile__screen-name
|
.profile__screen-name
|
||||||
= user.screen_name
|
= user.screen_name
|
||||||
= render 'user/actions', user: user, type: type
|
= render "user/actions", user:, type:, own_followings:, own_blocks:, own_mutes:
|
||||||
|
|
|
@ -9,18 +9,18 @@
|
||||||
.list-group
|
.list-group
|
||||||
= list_group_item t('.answer'),
|
= list_group_item t('.answer'),
|
||||||
notifications_path('answer'),
|
notifications_path('answer'),
|
||||||
badge: Notification.for(current_user).where(target_type: 'Answer', new: true).count
|
badge: @counters['Answer']
|
||||||
= list_group_item t('.smile'),
|
= list_group_item t('.smile'),
|
||||||
notifications_path('smile'),
|
notifications_path('smile'),
|
||||||
badge: Notification.for(current_user).where(target_type: 'Smile', new: true).count
|
badge: @counters['Smile']
|
||||||
= list_group_item t('.comment'),
|
= list_group_item t('.comment'),
|
||||||
notifications_path('comment'),
|
notifications_path('comment'),
|
||||||
badge: Notification.for(current_user).where(target_type: 'Comment', new: true).count
|
badge: @counters['Comment']
|
||||||
= list_group_item t('.commentsmile'),
|
= list_group_item t('.commentsmile'),
|
||||||
notifications_path('commentsmile'),
|
notifications_path('commentsmile'),
|
||||||
badge: Notification.for(current_user).where(target_type: 'CommentSmile', new: true).count
|
badge: @counters['CommentSmile']
|
||||||
= list_group_item t('.relationship'),
|
= list_group_item t('.relationship'),
|
||||||
notifications_path('relationship'),
|
notifications_path('relationship'),
|
||||||
badge: Notification.for(current_user).where(target_type: 'Relationship', new: true).count
|
badge: @counters['Relationship']
|
||||||
|
|
||||||
.d-none.d-sm-block= render 'shared/links'
|
.d-none.d-sm-block= render 'shared/links'
|
||||||
|
|
|
@ -1,11 +1,14 @@
|
||||||
.profile__actions
|
.profile__actions
|
||||||
- type ||= :nil
|
- type ||= :nil
|
||||||
|
- own_followings ||= nil
|
||||||
|
- own_blocks ||= nil
|
||||||
|
- own_mutes ||= nil
|
||||||
- if user_signed_in? && user == current_user
|
- if user_signed_in? && user == current_user
|
||||||
.d-grid
|
.d-grid
|
||||||
%a.btn.btn-dark{ href: settings_profile_path } Edit profile
|
%a.btn.btn-dark{ href: settings_profile_path } Edit profile
|
||||||
- elsif user_signed_in?
|
- elsif user_signed_in?
|
||||||
.d-grid.gap-2
|
.d-grid.gap-2
|
||||||
- if current_user.following? user
|
- if own_followings&.include?(user.id) || current_user.following?(user)
|
||||||
%button.btn.btn-primary{ type: :button, name: 'user-action', data: { action: :unfollow, type: type, target: user.screen_name } }
|
%button.btn.btn-primary{ type: :button, name: 'user-action', data: { action: :unfollow, type: type, target: user.screen_name } }
|
||||||
= t("voc.unfollow")
|
= t("voc.unfollow")
|
||||||
- else
|
- else
|
||||||
|
@ -19,7 +22,7 @@
|
||||||
%a.dropdown-item.d-block.d-sm-none{ href: '#', data: { bs_target: '#modal-list-memberships', bs_toggle: :modal } }
|
%a.dropdown-item.d-block.d-sm-none{ href: '#', data: { bs_target: '#modal-list-memberships', bs_toggle: :modal } }
|
||||||
%i.fa.fa-list.fa-fw
|
%i.fa.fa-list.fa-fw
|
||||||
= t(".list")
|
= t(".list")
|
||||||
- if current_user.blocking?(user)
|
- if own_blocks&.include?(user.id) || current_user.blocking?(user)
|
||||||
%a.dropdown-item{ href: '#', data: { action: :unblock, target: user.screen_name } }
|
%a.dropdown-item{ href: '#', data: { action: :unblock, target: user.screen_name } }
|
||||||
%i.fa.fa-minus-circle.fa-fw
|
%i.fa.fa-minus-circle.fa-fw
|
||||||
%span.pe-none= t("voc.unblock")
|
%span.pe-none= t("voc.unblock")
|
||||||
|
@ -27,7 +30,7 @@
|
||||||
%a.dropdown-item{ href: '#', data: { action: :block, target: user.screen_name } }
|
%a.dropdown-item{ href: '#', data: { action: :block, target: user.screen_name } }
|
||||||
%i.fa.fa-minus-circle.fa-fw
|
%i.fa.fa-minus-circle.fa-fw
|
||||||
%span.pe-none= t("voc.block")
|
%span.pe-none= t("voc.block")
|
||||||
- if current_user.muting?(user)
|
- if own_mutes&.include?(user.id) || current_user.muting?(user)
|
||||||
%a.dropdown-item{ href: '#', data: { action: :unmute, target: user.screen_name } }
|
%a.dropdown-item{ href: '#', data: { action: :unmute, target: user.screen_name } }
|
||||||
%i.fa.fa-volume-off.fa-fw
|
%i.fa.fa-volume-off.fa-fw
|
||||||
%span.pe-none= t("voc.unmute")
|
%span.pe-none= t("voc.unmute")
|
||||||
|
|
|
@ -1,15 +1,15 @@
|
||||||
.row.row-cols-1.row-cols-sm-2.row-cols-md-3#users
|
.row.row-cols-1.row-cols-sm-2.row-cols-md-3#users
|
||||||
- @users.each do |user|
|
- @users.each do |user|
|
||||||
.col.pb-3
|
.col.pb-3
|
||||||
= render 'shared/userbox', user: user, type: @type
|
= render "shared/userbox", user:, type:, own_followings:, own_blocks:, own_mutes:
|
||||||
|
|
||||||
- if @more_data_available
|
- if @more_data_available
|
||||||
.d-flex.justify-content-center.justify-content-sm-start#paginator
|
.d-flex.justify-content-center.justify-content-sm-start#paginator
|
||||||
= button_to t("voc.load"), @type == :follower ? show_user_followers_path(@user) : show_user_followings_path(@user),
|
= button_to t("voc.load"), type == :follower ? show_user_followers_path(@user) : show_user_followings_path(@user),
|
||||||
class: "btn btn-light",
|
class: "btn btn-light",
|
||||||
method: :get,
|
method: :get,
|
||||||
params: { last_id: @relationships_last_id },
|
params: { last_id: @relationships_last_id },
|
||||||
form: { data: { turbo_stream: true } }
|
form: { data: { turbo_stream: true } }
|
||||||
|
|
||||||
- provide(:title, user_title(@user, 'friends and followers'))
|
- provide(:title, t(".title.#{type}", user: @user.profile.safe_name))
|
||||||
- parent_layout 'user/profile'
|
- parent_layout "user/profile"
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
= turbo_stream.append "users" do
|
= turbo_stream.append "users" do
|
||||||
- @users.each do |user|
|
- @users.each do |user|
|
||||||
.col.pb-3
|
.col.pb-3
|
||||||
= render 'shared/userbox', user: user, type: @type
|
= render "shared/userbox", user:, type:, own_followings:, own_blocks:, own_mutes:
|
||||||
|
|
||||||
= turbo_stream.update "paginator" do
|
= turbo_stream.update "paginator" do
|
||||||
- if @more_data_available
|
- if @more_data_available
|
||||||
= button_to t("voc.load"), @type == :follower ? show_user_followers_path(@user) : show_user_followings_path(@user),
|
= button_to t("voc.load"), type == :follower ? show_user_followers_path(@user) : show_user_followings_path(@user),
|
||||||
class: "btn btn-light",
|
class: "btn btn-light",
|
||||||
method: :get,
|
method: :get,
|
||||||
params: { last_id: @relationships_last_id },
|
params: { last_id: @relationships_last_id },
|
||||||
|
|
|
@ -1 +1,6 @@
|
||||||
QuestionGenerator.compile
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
Rails.application.config.to_prepare do
|
||||||
|
QuestionGenerator.question_base_path = File.expand_path("../questions", __dir__)
|
||||||
|
QuestionGenerator.compile
|
||||||
|
end
|
||||||
|
|
|
@ -8,4 +8,20 @@ Sentry.init do |config|
|
||||||
# of transactions for performance monitoring.
|
# of transactions for performance monitoring.
|
||||||
# We recommend adjusting this value in production
|
# We recommend adjusting this value in production
|
||||||
config.traces_sample_rate = 0.25
|
config.traces_sample_rate = 0.25
|
||||||
|
|
||||||
|
exception_fingerprints = {
|
||||||
|
Excon::Error::ServiceUnavailable => 'external-service',
|
||||||
|
Twitter::Error::InternalServerError => 'external-service',
|
||||||
|
}
|
||||||
|
config.before_send = lambda do |event, hint|
|
||||||
|
# These are used for user-facing errors, not when something goes wrong
|
||||||
|
next if hint[:exception].is_a?(Errors::Base)
|
||||||
|
|
||||||
|
exception_class = hint[:exception].class
|
||||||
|
if exception_fingerprints.key?(exception_class)
|
||||||
|
event.fingerprint = [exception_fingerprints[exception_class]]
|
||||||
|
end
|
||||||
|
|
||||||
|
event
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -49,7 +49,9 @@ en:
|
||||||
primary_color: "Primary colour"
|
primary_color: "Primary colour"
|
||||||
primary_text: "Primary text colour"
|
primary_text: "Primary text colour"
|
||||||
raised_accent: "Raised accent colour"
|
raised_accent: "Raised accent colour"
|
||||||
|
raised_accent_text: "Raised accent text colour"
|
||||||
raised_background: "Raised background colour"
|
raised_background: "Raised background colour"
|
||||||
|
raised_text: "Raised text colour"
|
||||||
success_color: "Success colour"
|
success_color: "Success colour"
|
||||||
success_text: "Success text colour"
|
success_text: "Success text colour"
|
||||||
warning_color: "Warning colour"
|
warning_color: "Warning colour"
|
||||||
|
|
|
@ -651,6 +651,10 @@ en:
|
||||||
index:
|
index:
|
||||||
title: "Questions from %{author_identifier}"
|
title: "Questions from %{author_identifier}"
|
||||||
user:
|
user:
|
||||||
|
show_follow:
|
||||||
|
title:
|
||||||
|
follower: "%{user}'s followers"
|
||||||
|
friend: "%{user}'s followings"
|
||||||
actions:
|
actions:
|
||||||
view_inbox: "View inbox"
|
view_inbox: "View inbox"
|
||||||
privilege: "Check %{user}'s privileges"
|
privilege: "Check %{user}'s privileges"
|
||||||
|
|
|
@ -0,0 +1,311 @@
|
||||||
|
Do:
|
||||||
|
you:
|
||||||
|
- recycle
|
||||||
|
- have:
|
||||||
|
- a:
|
||||||
|
- nickname
|
||||||
|
- any:
|
||||||
|
- siblings
|
||||||
|
- pets
|
||||||
|
- like:
|
||||||
|
- social networks
|
||||||
|
- muffins
|
||||||
|
- video games
|
||||||
|
- the:
|
||||||
|
- city:
|
||||||
|
- or:
|
||||||
|
- country
|
||||||
|
- where you:
|
||||||
|
- live
|
||||||
|
- to:
|
||||||
|
- travel
|
||||||
|
- sing out loud when no one else is around
|
||||||
|
- want:
|
||||||
|
- old times back
|
||||||
|
- to know more:
|
||||||
|
about:
|
||||||
|
- your:
|
||||||
|
- future
|
||||||
|
- relatives
|
||||||
|
- history
|
||||||
|
- new inventions
|
||||||
|
- more:
|
||||||
|
- money
|
||||||
|
- friends
|
||||||
|
- things than you need
|
||||||
|
- think that:
|
||||||
|
- late is better than never
|
||||||
|
- prefer:
|
||||||
|
to:
|
||||||
|
- take baths or showers
|
||||||
|
your:
|
||||||
|
friends:
|
||||||
|
like:
|
||||||
|
- you:
|
||||||
|
- the way you are
|
||||||
|
- social networks
|
||||||
|
- muffins
|
||||||
|
- video games
|
||||||
|
know:
|
||||||
|
[much, too much]:
|
||||||
|
about:
|
||||||
|
- your:
|
||||||
|
- life
|
||||||
|
- hobbies
|
||||||
|
- family
|
||||||
|
- friends
|
||||||
|
- you
|
||||||
|
What:
|
||||||
|
- was:
|
||||||
|
the:
|
||||||
|
best:
|
||||||
|
- day of your life like
|
||||||
|
last:
|
||||||
|
song:
|
||||||
|
- you listened on repeat
|
||||||
|
thing:
|
||||||
|
you:
|
||||||
|
have:
|
||||||
|
- bought
|
||||||
|
- done
|
||||||
|
- eaten
|
||||||
|
your:
|
||||||
|
favourite:
|
||||||
|
song:
|
||||||
|
- as a 5 year old
|
||||||
|
- from a few weeks ago
|
||||||
|
- would:
|
||||||
|
you:
|
||||||
|
do:
|
||||||
|
if:
|
||||||
|
you:
|
||||||
|
had:
|
||||||
|
- one million dollars
|
||||||
|
- the ability to fly
|
||||||
|
were:
|
||||||
|
- a dragon
|
||||||
|
woke up:
|
||||||
|
with:
|
||||||
|
- someone else next to you
|
||||||
|
- some drawings in your face
|
||||||
|
- do:
|
||||||
|
you:
|
||||||
|
do:
|
||||||
|
- for fun
|
||||||
|
- 'on':
|
||||||
|
- the:
|
||||||
|
- weekend
|
||||||
|
like:
|
||||||
|
more,:
|
||||||
|
- dogs or cats
|
||||||
|
- shower or bath
|
||||||
|
- tea or coffee
|
||||||
|
think:
|
||||||
|
about:
|
||||||
|
- the:
|
||||||
|
- Internet
|
||||||
|
- Bad Dragon
|
||||||
|
- dragons
|
||||||
|
- '"fact" accounts'
|
||||||
|
- society
|
||||||
|
- cats
|
||||||
|
- surveillance
|
||||||
|
- coyotes
|
||||||
|
- raccoons
|
||||||
|
- foxes
|
||||||
|
- dogs
|
||||||
|
- lizards
|
||||||
|
- [activity, activities]:
|
||||||
|
do:
|
||||||
|
you:
|
||||||
|
- enjoy the most
|
||||||
|
- kind:
|
||||||
|
of:
|
||||||
|
animals:
|
||||||
|
- do you have
|
||||||
|
- habit:
|
||||||
|
do:
|
||||||
|
you:
|
||||||
|
really:
|
||||||
|
find:
|
||||||
|
cute:
|
||||||
|
- in a person
|
||||||
|
- is:
|
||||||
|
your:
|
||||||
|
- first memory
|
||||||
|
- dream job
|
||||||
|
- favourite:
|
||||||
|
- season
|
||||||
|
- video game
|
||||||
|
- board game
|
||||||
|
- sports team
|
||||||
|
- activity
|
||||||
|
- beverage
|
||||||
|
- Internet browser
|
||||||
|
- piece of music
|
||||||
|
- console
|
||||||
|
- snack
|
||||||
|
- food
|
||||||
|
- animal
|
||||||
|
- programming language:
|
||||||
|
- ''
|
||||||
|
- and why is it:
|
||||||
|
- PHP
|
||||||
|
- Rust
|
||||||
|
- C++
|
||||||
|
- Lisp
|
||||||
|
- Pascal
|
||||||
|
- Swift
|
||||||
|
- Ruby
|
||||||
|
- website:
|
||||||
|
- ''
|
||||||
|
- and why is it:
|
||||||
|
- Reddit
|
||||||
|
- Twitter
|
||||||
|
- Facebook
|
||||||
|
- YouTube
|
||||||
|
the:
|
||||||
|
[best, worst]:
|
||||||
|
thing:
|
||||||
|
- about:
|
||||||
|
the:
|
||||||
|
- Internet
|
||||||
|
your:
|
||||||
|
- favourite:
|
||||||
|
- series
|
||||||
|
- movie
|
||||||
|
- book
|
||||||
|
- country
|
||||||
|
- hometown
|
||||||
|
- one can do:
|
||||||
|
- if:
|
||||||
|
- "they're bored"
|
||||||
|
- ever
|
||||||
|
fast:
|
||||||
|
food:
|
||||||
|
- chain
|
||||||
|
one:
|
||||||
|
- thing you would like to become better at
|
||||||
|
- was:
|
||||||
|
the:
|
||||||
|
last:
|
||||||
|
thing:
|
||||||
|
you:
|
||||||
|
- did
|
||||||
|
- ate
|
||||||
|
- looked for
|
||||||
|
[best, worst]:
|
||||||
|
thing:
|
||||||
|
- "you've eaten so far"
|
||||||
|
- languages do you know
|
||||||
|
- apps do you use daily
|
||||||
|
- 'is heavier: a kilogram of steel, or a kilogram of feathers'
|
||||||
|
Can:
|
||||||
|
you:
|
||||||
|
- swim
|
||||||
|
- speak:
|
||||||
|
- different:
|
||||||
|
- languages
|
||||||
|
- play:
|
||||||
|
- any:
|
||||||
|
- sports
|
||||||
|
- the:
|
||||||
|
- piano
|
||||||
|
- guitar
|
||||||
|
- trumpet
|
||||||
|
- saxophone
|
||||||
|
- baseball
|
||||||
|
- ski
|
||||||
|
- cook
|
||||||
|
- dance
|
||||||
|
- yodel
|
||||||
|
- draw
|
||||||
|
Are:
|
||||||
|
you:
|
||||||
|
- religious
|
||||||
|
Have:
|
||||||
|
you:
|
||||||
|
ever:
|
||||||
|
- been:
|
||||||
|
- to:
|
||||||
|
- Austria
|
||||||
|
- Germany
|
||||||
|
- Japan
|
||||||
|
- Switzerland
|
||||||
|
- France
|
||||||
|
- Sweden
|
||||||
|
- Norway
|
||||||
|
- Finland
|
||||||
|
- Australia
|
||||||
|
- Italy
|
||||||
|
- Russia
|
||||||
|
- China
|
||||||
|
- the:
|
||||||
|
- USA
|
||||||
|
- United Kingdom
|
||||||
|
- caught:
|
||||||
|
- "doing things you shouldn't do"
|
||||||
|
- cheating
|
||||||
|
- mistaken for:
|
||||||
|
- someone else
|
||||||
|
- listened to:
|
||||||
|
- classical music
|
||||||
|
- music:
|
||||||
|
- "from the 80's"
|
||||||
|
- dubstep
|
||||||
|
- nightcore
|
||||||
|
- metal
|
||||||
|
- had:
|
||||||
|
- an:
|
||||||
|
- accident
|
||||||
|
- written:
|
||||||
|
- a love letter
|
||||||
|
- code
|
||||||
|
- in Japanese
|
||||||
|
How:
|
||||||
|
has:
|
||||||
|
your:
|
||||||
|
day:
|
||||||
|
- been
|
||||||
|
old:
|
||||||
|
are:
|
||||||
|
- you
|
||||||
|
many:
|
||||||
|
- open tabs do you currently have
|
||||||
|
- followers is too many
|
||||||
|
Where:
|
||||||
|
do:
|
||||||
|
you:
|
||||||
|
- work
|
||||||
|
- live
|
||||||
|
Which:
|
||||||
|
food:
|
||||||
|
do:
|
||||||
|
you:
|
||||||
|
- love
|
||||||
|
- hate
|
||||||
|
Who:
|
||||||
|
is:
|
||||||
|
the:
|
||||||
|
- most famous person you have met
|
||||||
|
your:
|
||||||
|
- favourite:
|
||||||
|
- Retrospring user
|
||||||
|
- actor
|
||||||
|
- artist
|
||||||
|
- comedian
|
||||||
|
- musician
|
||||||
|
Why:
|
||||||
|
do:
|
||||||
|
- they call it oven when you of in the cold food of out hot eat the food
|
||||||
|
Would:
|
||||||
|
you:
|
||||||
|
rather:
|
||||||
|
live:
|
||||||
|
- in:
|
||||||
|
- a city or in the countryside
|
||||||
|
- a flat or in a house
|
||||||
|
lose:
|
||||||
|
- an arm or a leg
|
||||||
|
be:
|
||||||
|
- the best player on a horrible team or the worst player on a great team
|
|
@ -157,14 +157,14 @@ Rails.application.routes.draw do
|
||||||
get "/@:username/q/:id", to: "question#show", as: :question
|
get "/@:username/q/:id", to: "question#show", as: :question
|
||||||
get "/@:username/followers", to: "user#followers", as: :show_user_followers
|
get "/@:username/followers", to: "user#followers", as: :show_user_followers
|
||||||
get "/@:username/followings", to: "user#followings", as: :show_user_followings
|
get "/@:username/followings", to: "user#followings", as: :show_user_followings
|
||||||
get "/@:username/friends", to: redirect("/@%{username}/followings/p/%{page}")
|
get "/@:username/friends", to: redirect("/@%{username}/followings")
|
||||||
get "/@:username/questions", to: "user#questions", as: :show_user_questions
|
get "/@:username/questions", to: "user#questions", as: :show_user_questions
|
||||||
get "/:username", to: "user#show", as: :user_alt
|
get "/:username", to: "user#show", as: :user_alt
|
||||||
get "/:username/a/:id", to: "answer#show", as: :answer_alt
|
get "/:username/a/:id", to: "answer#show", as: :answer_alt
|
||||||
get "/:username/q/:id", to: "question#show", as: :question_alt
|
get "/:username/q/:id", to: "question#show", as: :question_alt
|
||||||
get "/:username/followers", to: "user#followers", as: :show_user_followers_alt
|
get "/:username/followers", to: "user#followers", as: :show_user_followers_alt
|
||||||
get "/:username/followings", to: "user#followings", as: :show_user_followings_alt
|
get "/:username/followings", to: "user#followings", as: :show_user_followings_alt
|
||||||
get "/:username/friends", to: redirect("/%{username}/followings/p/%{page}")
|
get "/:username/friends", to: redirect("/%{username}/followings")
|
||||||
get "/:username/questions", to: "user#questions", as: :show_user_questions_alt
|
get "/:username/questions", to: "user#questions", as: :show_user_questions_alt
|
||||||
|
|
||||||
get "/feedback/consent", to: "feedback#consent", as: "feedback_consent"
|
get "/feedback/consent", to: "feedback#consent", as: "feedback_consent"
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class AddRaisedAndAccentTextToThemes < ActiveRecord::Migration[6.1]
|
||||||
|
def up
|
||||||
|
add_column :themes, :raised_text, :integer, default: 0x000000, null: false
|
||||||
|
add_column :themes, :raised_accent_text, :integer, default: 0x000000, null: false
|
||||||
|
end
|
||||||
|
|
||||||
|
def down
|
||||||
|
remove_column :themes, :raised_text
|
||||||
|
remove_column :themes, :raised_accent_text
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,14 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class UseBodyTextForRaisedTextsInThemes < ActiveRecord::Migration[6.1]
|
||||||
|
def up
|
||||||
|
execute <<~SQUIRREL
|
||||||
|
UPDATE themes
|
||||||
|
SET raised_text = body_text,
|
||||||
|
raised_accent_text = body_text
|
||||||
|
WHERE body_text != 0;
|
||||||
|
SQUIRREL
|
||||||
|
end
|
||||||
|
|
||||||
|
def down; end
|
||||||
|
end
|
|
@ -181,7 +181,7 @@ ActiveRecord::Schema.define(version: 2023_02_03_054229) do
|
||||||
t.datetime "created_at", null: false
|
t.datetime "created_at", null: false
|
||||||
t.datetime "updated_at", null: false
|
t.datetime "updated_at", null: false
|
||||||
t.index ["name", "resource_type", "resource_id"], name: "index_roles_on_name_and_resource_type_and_resource_id"
|
t.index ["name", "resource_type", "resource_id"], name: "index_roles_on_name_and_resource_type_and_resource_id"
|
||||||
t.index ["resource_type", "resource_id"], name: "index_roles_on_resource"
|
t.index ["resource_type", "resource_id"], name: "index_roles_on_resource_type_and_resource_id"
|
||||||
end
|
end
|
||||||
|
|
||||||
create_table "rpush_apps", force: :cascade do |t|
|
create_table "rpush_apps", force: :cascade do |t|
|
||||||
|
@ -301,6 +301,8 @@ ActiveRecord::Schema.define(version: 2023_02_03_054229) do
|
||||||
t.integer "light_color", default: 16316922
|
t.integer "light_color", default: 16316922
|
||||||
t.integer "light_text", default: 0
|
t.integer "light_text", default: 0
|
||||||
t.integer "input_placeholder", default: 7107965, null: false
|
t.integer "input_placeholder", default: 7107965, null: false
|
||||||
|
t.integer "raised_text", default: 0, null: false
|
||||||
|
t.integer "raised_accent_text", default: 0, null: false
|
||||||
t.index ["user_id", "created_at"], name: "index_themes_on_user_id_and_created_at"
|
t.index ["user_id", "created_at"], name: "index_themes_on_user_id_and_created_at"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,7 @@ services:
|
||||||
- 1234:1234
|
- 1234:1234
|
||||||
|
|
||||||
redis:
|
redis:
|
||||||
image: redis:3.2.11-alpine
|
image: redis:6.2.10-alpine
|
||||||
ports:
|
ports:
|
||||||
- 6379:6379
|
- 6379:6379
|
||||||
|
|
||||||
|
|
|
@ -17,9 +17,9 @@ module Retrospring
|
||||||
|
|
||||||
def month = 1
|
def month = 1
|
||||||
|
|
||||||
def day = 23
|
def day = 31
|
||||||
|
|
||||||
def patch = 0
|
def patch = 1
|
||||||
|
|
||||||
def suffix = ""
|
def suffix = ""
|
||||||
|
|
||||||
|
|
|
@ -28,7 +28,7 @@
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@typescript-eslint/eslint-plugin": "^4.11.0",
|
"@typescript-eslint/eslint-plugin": "^4.11.0",
|
||||||
"@typescript-eslint/parser": "^4.11.0",
|
"@typescript-eslint/parser": "^4.11.0",
|
||||||
"esbuild": "^0.17.4",
|
"esbuild": "^0.17.5",
|
||||||
"eslint": "^7.16.0",
|
"eslint": "^7.16.0",
|
||||||
"eslint-plugin-import": "^2.27.5",
|
"eslint-plugin-import": "^2.27.5",
|
||||||
"stylelint": "^14.16.1",
|
"stylelint": "^14.16.1",
|
||||||
|
|
|
@ -74,7 +74,7 @@
|
||||||
<div class="dialog">
|
<div class="dialog">
|
||||||
<div>
|
<div>
|
||||||
<h1>This page takes way too long to load!</h1>
|
<h1>This page takes way too long to load!</h1>
|
||||||
<img src="images/errors/original/angry_unicorn.png" alt="Unicorn">
|
<img src="/images/errors/original/angry_unicorn.png" alt="Unicorn">
|
||||||
</div>
|
</div>
|
||||||
<p>Sorry about that. Please try refreshing and contact us if the problem persists.</p>
|
<p>Sorry about that. Please try refreshing and contact us if the problem persists.</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -47,6 +47,9 @@ self.addEventListener('install', function (event) {
|
||||||
});
|
});
|
||||||
|
|
||||||
self.addEventListener('fetch', function (event) {
|
self.addEventListener('fetch', function (event) {
|
||||||
|
const url = new URL(event.request.url);
|
||||||
|
if (event.request.method !== 'GET' || !OFFLINE_CACHE_PATHS.includes(url.pathname)) return;
|
||||||
|
|
||||||
event.respondWith(
|
event.respondWith(
|
||||||
(async () => {
|
(async () => {
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -58,6 +58,10 @@ describe InboxController, type: :controller do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "updates the inbox entry status" do
|
||||||
|
expect { subject }.to change { inbox_entry.reload.new? }.from(true).to(false)
|
||||||
|
end
|
||||||
|
|
||||||
context "when requested the turbo stream format" do
|
context "when requested the turbo stream format" do
|
||||||
subject { get :show, format: :turbo_stream }
|
subject { get :show, format: :turbo_stream }
|
||||||
|
|
||||||
|
@ -175,9 +179,7 @@ describe InboxController, type: :controller do
|
||||||
inbox: [],
|
inbox: [],
|
||||||
inbox_last_id: nil,
|
inbox_last_id: nil,
|
||||||
more_data_available: false,
|
more_data_available: false,
|
||||||
inbox_count: 0,
|
inbox_count: 0
|
||||||
delete_id: "ib-delete-all",
|
|
||||||
disabled: true
|
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -209,9 +211,7 @@ describe InboxController, type: :controller do
|
||||||
inbox: [],
|
inbox: [],
|
||||||
inbox_last_id: nil,
|
inbox_last_id: nil,
|
||||||
more_data_available: false,
|
more_data_available: false,
|
||||||
inbox_count: 0,
|
inbox_count: 0
|
||||||
delete_id: "ib-delete-all",
|
|
||||||
disabled: true
|
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -33,5 +33,9 @@ describe NotificationsController do
|
||||||
expect(response).to render_template(:index)
|
expect(response).to render_template(:index)
|
||||||
expect(controller.instance_variable_get(:@notifications)).to have_attributes(size: 2)
|
expect(controller.instance_variable_get(:@notifications)).to have_attributes(size: 2)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "marks notifications as read" do
|
||||||
|
expect { subject }.to change { Notification.for(user).where(new: true).count }.from(2).to(0)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -15,12 +15,14 @@ FactoryBot.define do
|
||||||
dark_color { 6_710_886 }
|
dark_color { 6_710_886 }
|
||||||
dark_text { 15_658_734 }
|
dark_text { 15_658_734 }
|
||||||
raised_background { 16_777_215 }
|
raised_background { 16_777_215 }
|
||||||
|
raised_text { 3_355_443 }
|
||||||
background_color { 13_026_795 }
|
background_color { 13_026_795 }
|
||||||
body_text { 3_355_443 }
|
body_text { 3_355_443 }
|
||||||
muted_text { 3_355_443 }
|
muted_text { 3_355_443 }
|
||||||
input_color { 15_789_556 }
|
input_color { 15_789_556 }
|
||||||
input_text { 6_710_886 }
|
input_text { 6_710_886 }
|
||||||
raised_accent { 16_250_871 }
|
raised_accent { 16_250_871 }
|
||||||
|
raised_accent_text { 3_355_443 }
|
||||||
light_color { 16_316_922 }
|
light_color { 16_316_922 }
|
||||||
light_text { 0 }
|
light_text { 0 }
|
||||||
end
|
end
|
||||||
|
|
|
@ -22,32 +22,34 @@ describe UseCase::DataExport::Theme, :data_export do
|
||||||
expect(json_file("theme.json")).to eq(
|
expect(json_file("theme.json")).to eq(
|
||||||
{
|
{
|
||||||
theme: {
|
theme: {
|
||||||
id: theme.id,
|
id: theme.id,
|
||||||
user_id: user.id,
|
user_id: user.id,
|
||||||
primary_color: 9342168,
|
primary_color: 9342168,
|
||||||
primary_text: 16777215,
|
primary_text: 16777215,
|
||||||
danger_color: 14257035,
|
danger_color: 14257035,
|
||||||
danger_text: 16777215,
|
danger_text: 16777215,
|
||||||
success_color: 12573067,
|
success_color: 12573067,
|
||||||
success_text: 16777215,
|
success_text: 16777215,
|
||||||
warning_color: 14261899,
|
warning_color: 14261899,
|
||||||
warning_text: 16777215,
|
warning_text: 16777215,
|
||||||
info_color: 9165273,
|
info_color: 9165273,
|
||||||
info_text: 16777215,
|
info_text: 16777215,
|
||||||
dark_color: 6710886,
|
dark_color: 6710886,
|
||||||
dark_text: 15658734,
|
dark_text: 15658734,
|
||||||
raised_background: 16777215,
|
raised_background: 16777215,
|
||||||
background_color: 13026795,
|
raised_text: 3355443,
|
||||||
body_text: 3355443,
|
background_color: 13026795,
|
||||||
muted_text: 3355443,
|
body_text: 3355443,
|
||||||
created_at: "2022-12-10T13:37:42.000Z",
|
muted_text: 3355443,
|
||||||
updated_at: "2022-12-10T13:37:42.000Z",
|
created_at: "2022-12-10T13:37:42.000Z",
|
||||||
input_color: 15789556,
|
updated_at: "2022-12-10T13:37:42.000Z",
|
||||||
input_text: 6710886,
|
input_color: 15789556,
|
||||||
raised_accent: 16250871,
|
input_text: 6710886,
|
||||||
light_color: 16316922,
|
raised_accent: 16250871,
|
||||||
light_text: 0,
|
raised_accent_text: 3355443,
|
||||||
input_placeholder: 7107965
|
light_color: 16316922,
|
||||||
|
light_text: 0,
|
||||||
|
input_placeholder: 7107965
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
|
@ -81,6 +81,7 @@ RSpec.describe User, type: :model do
|
||||||
# nor .mail (.email is, however)
|
# nor .mail (.email is, however)
|
||||||
include_examples "invalid email", "fritz.fantom@proton.mail"
|
include_examples "invalid email", "fritz.fantom@proton.mail"
|
||||||
# common typos:
|
# common typos:
|
||||||
|
include_examples "invalid email", "fritz.fantom@aoo.com"
|
||||||
include_examples "invalid email", "fritz.fantom@fmail.com"
|
include_examples "invalid email", "fritz.fantom@fmail.com"
|
||||||
include_examples "invalid email", "fritz.fantom@gamil.com"
|
include_examples "invalid email", "fritz.fantom@gamil.com"
|
||||||
include_examples "invalid email", "fritz.fantom@gemail.com"
|
include_examples "invalid email", "fritz.fantom@gemail.com"
|
||||||
|
@ -93,6 +94,7 @@ RSpec.describe User, type: :model do
|
||||||
include_examples "invalid email", "fritz.fantom@gmaile.com"
|
include_examples "invalid email", "fritz.fantom@gmaile.com"
|
||||||
include_examples "invalid email", "fritz.fantom@gmaill.com"
|
include_examples "invalid email", "fritz.fantom@gmaill.com"
|
||||||
include_examples "invalid email", "fritz.fantom@gmali.com"
|
include_examples "invalid email", "fritz.fantom@gmali.com"
|
||||||
|
include_examples "invalid email", "fritz.fantom@gmaul.com"
|
||||||
include_examples "invalid email", "fritz.fantom@gnail.com"
|
include_examples "invalid email", "fritz.fantom@gnail.com"
|
||||||
include_examples "invalid email", "fritz.fantom@hotamil.com"
|
include_examples "invalid email", "fritz.fantom@hotamil.com"
|
||||||
include_examples "invalid email", "fritz.fantom@hotmai.com"
|
include_examples "invalid email", "fritz.fantom@hotmai.com"
|
||||||
|
|
228
yarn.lock
228
yarn.lock
|
@ -49,115 +49,115 @@
|
||||||
resolved "https://registry.yarnpkg.com/@csstools/selector-specificity/-/selector-specificity-2.0.2.tgz#1bfafe4b7ed0f3e4105837e056e0a89b108ebe36"
|
resolved "https://registry.yarnpkg.com/@csstools/selector-specificity/-/selector-specificity-2.0.2.tgz#1bfafe4b7ed0f3e4105837e056e0a89b108ebe36"
|
||||||
integrity sha512-IkpVW/ehM1hWKln4fCA3NzJU8KwD+kIOvPZA4cqxoJHtE21CCzjyp+Kxbu0i5I4tBNOlXPL9mjwnWlL0VEG4Fg==
|
integrity sha512-IkpVW/ehM1hWKln4fCA3NzJU8KwD+kIOvPZA4cqxoJHtE21CCzjyp+Kxbu0i5I4tBNOlXPL9mjwnWlL0VEG4Fg==
|
||||||
|
|
||||||
"@esbuild/android-arm64@0.17.4":
|
"@esbuild/android-arm64@0.17.5":
|
||||||
version "0.17.4"
|
version "0.17.5"
|
||||||
resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.17.4.tgz#0a900a7e448cc038ae5a751255257fc67163ed32"
|
resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.17.5.tgz#a145f43018e639bed94ed637369e2dcdd6bf9ea2"
|
||||||
integrity sha512-91VwDrl4EpxBCiG6h2LZZEkuNvVZYJkv2T9gyLG/mhGG1qrM7i5SwUcg/hlSPnL/4hDT0TFcF35/XMGSn0bemg==
|
integrity sha512-KHWkDqYAMmKZjY4RAN1PR96q6UOtfkWlTS8uEwWxdLtkRt/0F/csUhXIrVfaSIFxnscIBMPynGfhsMwQDRIBQw==
|
||||||
|
|
||||||
"@esbuild/android-arm@0.17.4":
|
"@esbuild/android-arm@0.17.5":
|
||||||
version "0.17.4"
|
version "0.17.5"
|
||||||
resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.17.4.tgz#fe32ce82eb6064d3dc13c0d8ca0e440bbc776c93"
|
resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.17.5.tgz#9fa2deff7fc5d180bb4ecff70beea3a95ac44251"
|
||||||
integrity sha512-R9GCe2xl2XDSc2XbQB63mFiFXHIVkOP+ltIxICKXqUPrFX97z6Z7vONCLQM1pSOLGqfLrGi3B7nbhxmFY/fomg==
|
integrity sha512-crmPUzgCmF+qZXfl1YkiFoUta2XAfixR1tEnr/gXIixE+WL8Z0BGqfydP5oox0EUOgQMMRgtATtakyAcClQVqQ==
|
||||||
|
|
||||||
"@esbuild/android-x64@0.17.4":
|
"@esbuild/android-x64@0.17.5":
|
||||||
version "0.17.4"
|
version "0.17.5"
|
||||||
resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.17.4.tgz#6ae1056f6ecf1963c1d076cf5f0109b52d8049f6"
|
resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.17.5.tgz#145fc61f810400e65a56b275280d1422a102c2ef"
|
||||||
integrity sha512-mGSqhEPL7029XL7QHNPxPs15JVa02hvZvysUcyMP9UXdGFwncl2WU0bqx+Ysgzd+WAbv8rfNa73QveOxAnAM2w==
|
integrity sha512-8fI/AnIdmWz/+1iza2WrCw8kwXK9wZp/yZY/iS8ioC+U37yJCeppi9EHY05ewJKN64ASoBIseufZROtcFnX5GA==
|
||||||
|
|
||||||
"@esbuild/darwin-arm64@0.17.4":
|
"@esbuild/darwin-arm64@0.17.5":
|
||||||
version "0.17.4"
|
version "0.17.5"
|
||||||
resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.17.4.tgz#5064d81ee5b8d646a5b7cc3e53c98cb983c4af55"
|
resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.17.5.tgz#61fb0546aa4bae0850817d6e0d008b1cb3f64b49"
|
||||||
integrity sha512-tTyJRM9dHvlMPt1KrBFVB5OW1kXOsRNvAPtbzoKazd5RhD5/wKlXk1qR2MpaZRYwf4WDMadt0Pv0GwxB41CVow==
|
integrity sha512-EAvaoyIySV6Iif3NQCglUNpnMfHSUgC5ugt2efl3+QDntucJe5spn0udNZjTgNi6tKVqSceOw9tQ32liNZc1Xw==
|
||||||
|
|
||||||
"@esbuild/darwin-x64@0.17.4":
|
"@esbuild/darwin-x64@0.17.5":
|
||||||
version "0.17.4"
|
version "0.17.5"
|
||||||
resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.17.4.tgz#67f0213b3333248b32a97a7fc3fee880c2157674"
|
resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.17.5.tgz#54b770f0c49f524ae9ba24c85d6dea8b521f610d"
|
||||||
integrity sha512-phQuC2Imrb3TjOJwLN8EO50nb2FHe8Ew0OwgZDH1SV6asIPGudnwTQtighDF2EAYlXChLoMJwqjAp4vAaACq6w==
|
integrity sha512-ha7QCJh1fuSwwCgoegfdaljowwWozwTDjBgjD3++WAy/qwee5uUi1gvOg2WENJC6EUyHBOkcd3YmLDYSZ2TPPA==
|
||||||
|
|
||||||
"@esbuild/freebsd-arm64@0.17.4":
|
"@esbuild/freebsd-arm64@0.17.5":
|
||||||
version "0.17.4"
|
version "0.17.5"
|
||||||
resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.4.tgz#8eaaa126d9ff24822c730f06a71ac2d1091dc1c2"
|
resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.5.tgz#be1dd18b7b9411f10bdc362ba8bff16386175367"
|
||||||
integrity sha512-oH6JUZkocgmjzzYaP5juERLpJQSwazdjZrTPgLRmAU2bzJ688x0vfMB/WTv4r58RiecdHvXOPC46VtsMy/mepg==
|
integrity sha512-VbdXJkn2aI2pQ/wxNEjEcnEDwPpxt3CWWMFYmO7CcdFBoOsABRy2W8F3kjbF9F/pecEUDcI3b5i2w+By4VQFPg==
|
||||||
|
|
||||||
"@esbuild/freebsd-x64@0.17.4":
|
"@esbuild/freebsd-x64@0.17.5":
|
||||||
version "0.17.4"
|
version "0.17.5"
|
||||||
resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.17.4.tgz#314eff900a71abf64d4e5bea31e430d8ebd78d79"
|
resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.17.5.tgz#c9c1960fa3e1eada4e5d4be2a11a2f04ce14198f"
|
||||||
integrity sha512-U4iWGn/9TrAfpAdfd56eO0pRxIgb0a8Wj9jClrhT8hvZnOnS4dfMPW7o4fn15D/KqoiVYHRm43jjBaTt3g/2KA==
|
integrity sha512-olgGYND1/XnnWxwhjtY3/ryjOG/M4WfcA6XH8dBTH1cxMeBemMODXSFhkw71Kf4TeZFFTN25YOomaNh0vq2iXg==
|
||||||
|
|
||||||
"@esbuild/linux-arm64@0.17.4":
|
"@esbuild/linux-arm64@0.17.5":
|
||||||
version "0.17.4"
|
version "0.17.5"
|
||||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.17.4.tgz#5bed6bb8eb1d331644f8b31c87b8df57f204e84e"
|
resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.17.5.tgz#34d96d11c6899017ecae42fb97de8e0c3282902f"
|
||||||
integrity sha512-UkGfQvYlwOaeYJzZG4cLV0hCASzQZnKNktRXUo3/BMZvdau40AOz9GzmGA063n1piq6VrFFh43apRDQx8hMP2w==
|
integrity sha512-8a0bqSwu3OlLCfu2FBbDNgQyBYdPJh1B9PvNX7jMaKGC9/KopgHs37t+pQqeMLzcyRqG6z55IGNQAMSlCpBuqg==
|
||||||
|
|
||||||
"@esbuild/linux-arm@0.17.4":
|
"@esbuild/linux-arm@0.17.5":
|
||||||
version "0.17.4"
|
version "0.17.5"
|
||||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.17.4.tgz#6eaa41f37e231d113da715a1d9cc820e5523aeb6"
|
resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.17.5.tgz#86332e6293fd713a54ab299a5e2ed7c60c9e1c07"
|
||||||
integrity sha512-S2s9xWTGMTa/fG5EyMGDeL0wrWVgOSQcNddJWgu6rG1NCSXJHs76ZP9AsxjB3f2nZow9fWOyApklIgiTGZKhiw==
|
integrity sha512-YBdCyQwA3OQupi6W2/WO4FnI+NWFWe79cZEtlbqSESOHEg7a73htBIRiE6uHPQe7Yp5E4aALv+JxkRLGEUL7tw==
|
||||||
|
|
||||||
"@esbuild/linux-ia32@0.17.4":
|
"@esbuild/linux-ia32@0.17.5":
|
||||||
version "0.17.4"
|
version "0.17.5"
|
||||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.17.4.tgz#3fc352bb54e0959fda273cd2253b1c72ca41b8c2"
|
resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.17.5.tgz#7bd9185c844e7dfce6a01dfdec584e115602a8c4"
|
||||||
integrity sha512-3lqFi4VFo/Vwvn77FZXeLd0ctolIJH/uXkH3yNgEk89Eh6D3XXAC9/iTPEzeEpsNE5IqGIsFa5Z0iPeOh25IyA==
|
integrity sha512-uCwm1r/+NdP7vndctgq3PoZrnmhmnecWAr114GWMRwg2QMFFX+kIWnp7IO220/JLgnXK/jP7VKAFBGmeOYBQYQ==
|
||||||
|
|
||||||
"@esbuild/linux-loong64@0.17.4":
|
"@esbuild/linux-loong64@0.17.5":
|
||||||
version "0.17.4"
|
version "0.17.5"
|
||||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.17.4.tgz#86d54f690be53669cd2a38a5333ecf2608c11189"
|
resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.17.5.tgz#2907d4120c7b3642b96be6014f77e7624c378eea"
|
||||||
integrity sha512-HqpWZkVslDHIwdQ9D+gk7NuAulgQvRxF9no54ut/M55KEb3mi7sQS3GwpPJzSyzzP0UkjQVN7/tbk88/CaX4EQ==
|
integrity sha512-3YxhSBl5Sb6TtBjJu+HP93poBruFzgXmf3PVfIe4xOXMj1XpxboYZyw3W8BhoX/uwxzZz4K1I99jTE/5cgDT1g==
|
||||||
|
|
||||||
"@esbuild/linux-mips64el@0.17.4":
|
"@esbuild/linux-mips64el@0.17.5":
|
||||||
version "0.17.4"
|
version "0.17.5"
|
||||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.17.4.tgz#3dbd897bd8f047fef35e69bd253b8f07ca7fe483"
|
resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.17.5.tgz#fc98be741e8080ecd13b404d5fca5302d3835bf4"
|
||||||
integrity sha512-d/nMCKKh/SVDbqR9ju+b78vOr0tNXtfBjcp5vfHONCCOAL9ad8gN9dC/u+UnH939pz7wO+0u/x9y1MaZcb/lKA==
|
integrity sha512-Hy5Z0YVWyYHdtQ5mfmfp8LdhVwGbwVuq8mHzLqrG16BaMgEmit2xKO+iDakHs+OetEx0EN/2mUzDdfdktI+Nmg==
|
||||||
|
|
||||||
"@esbuild/linux-ppc64@0.17.4":
|
"@esbuild/linux-ppc64@0.17.5":
|
||||||
version "0.17.4"
|
version "0.17.5"
|
||||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.17.4.tgz#defaff6db9a60f08936fc0c59e0eabfb1055968a"
|
resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.17.5.tgz#ea12e8f6b290a613ac4903c9e00835c69ced065c"
|
||||||
integrity sha512-lOD9p2dmjZcNiTU+sGe9Nn6G3aYw3k0HBJies1PU0j5IGfp6tdKOQ6mzfACRFCqXjnBuTqK7eTYpwx09O5LLfg==
|
integrity sha512-5dbQvBLbU/Y3Q4ABc9gi23hww1mQcM7KZ9KBqabB7qhJswYMf8WrDDOSw3gdf3p+ffmijMd28mfVMvFucuECyg==
|
||||||
|
|
||||||
"@esbuild/linux-riscv64@0.17.4":
|
"@esbuild/linux-riscv64@0.17.5":
|
||||||
version "0.17.4"
|
version "0.17.5"
|
||||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.17.4.tgz#270a09f6f4205a8a8c8ed3c7dbabdcebaafa8a84"
|
resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.17.5.tgz#ce47b15fd4227eeb0590826e41bdc430c5bfd06c"
|
||||||
integrity sha512-mTGnwWwVshAjGsd8rP+K6583cPDgxOunsqqldEYij7T5/ysluMHKqUIT4TJHfrDFadUwrghAL6QjER4FeqQXoA==
|
integrity sha512-fp/KUB/ZPzEWGTEUgz9wIAKCqu7CjH1GqXUO2WJdik1UNBQ7Xzw7myIajpxztE4Csb9504ERiFMxZg5KZ6HlZQ==
|
||||||
|
|
||||||
"@esbuild/linux-s390x@0.17.4":
|
"@esbuild/linux-s390x@0.17.5":
|
||||||
version "0.17.4"
|
version "0.17.5"
|
||||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.17.4.tgz#197695bece68f514dcdcc286562b5d48c5dad5f9"
|
resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.17.5.tgz#962fa540d7498967270eb1d4b9ac6c4a4f339735"
|
||||||
integrity sha512-AQYuUGp50XM29/N/dehADxvc2bUqDcoqrVuijop1Wv72SyxT6dDB9wjUxuPZm2HwIM876UoNNBMVd+iX/UTKVQ==
|
integrity sha512-kRV3yw19YDqHTp8SfHXfObUFXlaiiw4o2lvT1XjsPZ++22GqZwSsYWJLjMi1Sl7j9qDlDUduWDze/nQx0d6Lzw==
|
||||||
|
|
||||||
"@esbuild/linux-x64@0.17.4":
|
"@esbuild/linux-x64@0.17.5":
|
||||||
version "0.17.4"
|
version "0.17.5"
|
||||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.17.4.tgz#db50cdfb071c0d367025c1c98563aab1318f800e"
|
resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.17.5.tgz#9fa52884c3d876593a522aa1d4df43b717907050"
|
||||||
integrity sha512-+AsFBwKgQuhV2shfGgA9YloxLDVjXgUEWZum7glR5lLmV94IThu/u2JZGxTgjYby6kyXEx8lKOqP5rTEVBR0Rw==
|
integrity sha512-vnxuhh9e4pbtABNLbT2ANW4uwQ/zvcHRCm1JxaYkzSehugoFd5iXyC4ci1nhXU13mxEwCnrnTIiiSGwa/uAF1g==
|
||||||
|
|
||||||
"@esbuild/netbsd-x64@0.17.4":
|
"@esbuild/netbsd-x64@0.17.5":
|
||||||
version "0.17.4"
|
version "0.17.5"
|
||||||
resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.17.4.tgz#e4d5d8022f8eddbd7d9899d58265915444f46f3b"
|
resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.17.5.tgz#47bb187b86aad9622051cb80c27e439b7d9e3a9a"
|
||||||
integrity sha512-zD1TKYX9553OiLS/qkXPMlWoELYkH/VkzRYNKEU+GwFiqkq0SuxsKnsCg5UCdxN3cqd+1KZ8SS3R+WG/Hxy2jQ==
|
integrity sha512-cigBpdiSx/vPy7doUyImsQQBnBjV5f1M99ZUlaJckDAJjgXWl6y9W17FIfJTy8TxosEF6MXq+fpLsitMGts2nA==
|
||||||
|
|
||||||
"@esbuild/openbsd-x64@0.17.4":
|
"@esbuild/openbsd-x64@0.17.5":
|
||||||
version "0.17.4"
|
version "0.17.5"
|
||||||
resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.17.4.tgz#9b770e1e7745824cbe155f5a742fc781855a7e68"
|
resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.17.5.tgz#abc55c35a1ed2bc3c5ede2ef50a3b2f87395009a"
|
||||||
integrity sha512-PY1NjEsLRhPEFFg1AV0/4Or/gR+q2dOb9s5rXcPuCjyHRzbt8vnHJl3vYj+641TgWZzTFmSUnZbzs1zwTzjeqw==
|
integrity sha512-VdqRqPVIjjZfkf40LrqOaVuhw9EQiAZ/GNCSM2UplDkaIzYVsSnycxcFfAnHdWI8Gyt6dO15KHikbpxwx+xHbw==
|
||||||
|
|
||||||
"@esbuild/sunos-x64@0.17.4":
|
"@esbuild/sunos-x64@0.17.5":
|
||||||
version "0.17.4"
|
version "0.17.5"
|
||||||
resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.17.4.tgz#4c6d2290f8bf39ab9284f5a1b9a2210858e2d6e6"
|
resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.17.5.tgz#b83c080a2147662599a5d18b2ff47f07c93e03a0"
|
||||||
integrity sha512-B3Z7s8QZQW9tKGleMRXvVmwwLPAUoDCHs4WZ2ElVMWiortLJFowU1NjAhXOKjDgC7o9ByeVcwyOlJ+F2r6ZgmQ==
|
integrity sha512-ItxPaJ3MBLtI4nK+mALLEoUs6amxsx+J1ibnfcYMkqaCqHST1AkF4aENpBehty3czqw64r/XqL+W9WqU6kc2Qw==
|
||||||
|
|
||||||
"@esbuild/win32-arm64@0.17.4":
|
"@esbuild/win32-arm64@0.17.5":
|
||||||
version "0.17.4"
|
version "0.17.5"
|
||||||
resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.17.4.tgz#424954b6d598f40e2c5a0d85e3af07147fb41909"
|
resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.17.5.tgz#2a4c41f427d9cf25b75f9d61493711a482106850"
|
||||||
integrity sha512-0HCu8R3mY/H5V7N6kdlsJkvrT591bO/oRZy8ztF1dhgNU5xD5tAh5bKByT1UjTGjp/VVBsl1PDQ3L18SfvtnBQ==
|
integrity sha512-4u2Q6qsJTYNFdS9zHoAi80spzf78C16m2wla4eJPh4kSbRv+BpXIfl6TmBSWupD8e47B1NrTfrOlEuco7mYQtg==
|
||||||
|
|
||||||
"@esbuild/win32-ia32@0.17.4":
|
"@esbuild/win32-ia32@0.17.5":
|
||||||
version "0.17.4"
|
version "0.17.5"
|
||||||
resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.17.4.tgz#2c94e9c3a82c779d3f07b3fb5c482a2e3fecedb1"
|
resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.17.5.tgz#7c14e3250725d0e2c21f89c98eb6abb520cba0e0"
|
||||||
integrity sha512-VUjhVDQycse1gLbe06pC/uaA0M+piQXJpdpNdhg8sPmeIZZqu5xPoGWVCmcsOO2gaM2cywuTYTHkXRozo3/Nkg==
|
integrity sha512-KYlm+Xu9TXsfTWAcocLuISRtqxKp/Y9ZBVg6CEEj0O5J9mn7YvBKzAszo2j1ndyzUPk+op+Tie2PJeN+BnXGqQ==
|
||||||
|
|
||||||
"@esbuild/win32-x64@0.17.4":
|
"@esbuild/win32-x64@0.17.5":
|
||||||
version "0.17.4"
|
version "0.17.5"
|
||||||
resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.17.4.tgz#9b7760cdc77678bdbc5b582fae2cf3de449df048"
|
resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.17.5.tgz#a8f3d26d8afc5186eccda265ceb1820b8e8830be"
|
||||||
integrity sha512-0kLAjs+xN5OjhTt/aUA6t48SfENSCKgGPfExADYTOo/UCn0ivxos9/anUVeSfg+L+2O9xkFxvJXIJfG+Q4sYSg==
|
integrity sha512-XgA9qWRqby7xdYXuF6KALsn37QGBMHsdhmnpjfZtYxKxbTOwfnDM6MYi2WuUku5poNaX2n9XGVr20zgT/2QwCw==
|
||||||
|
|
||||||
"@eslint/eslintrc@^0.4.3":
|
"@eslint/eslintrc@^0.4.3":
|
||||||
version "0.4.3"
|
version "0.4.3"
|
||||||
|
@ -835,33 +835,33 @@ es-to-primitive@^1.2.1:
|
||||||
is-date-object "^1.0.1"
|
is-date-object "^1.0.1"
|
||||||
is-symbol "^1.0.2"
|
is-symbol "^1.0.2"
|
||||||
|
|
||||||
esbuild@^0.17.4:
|
esbuild@^0.17.5:
|
||||||
version "0.17.4"
|
version "0.17.5"
|
||||||
resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.17.4.tgz#af4f8f78604c67f8e6afbdee36a3f4211ecfc859"
|
resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.17.5.tgz#cd76d75700d49ac050ad9eedfbed777bd6a9d930"
|
||||||
integrity sha512-zBn9MeCwT7W5F1a3lXClD61ip6vQM+H8Msb0w8zMT4ZKBpDg+rFAraNyWCDelB/2L6M3g6AXHPnsyvjMFnxtFw==
|
integrity sha512-Bu6WLCc9NMsNoMJUjGl3yBzTjVLXdysMltxQWiLAypP+/vQrf+3L1Xe8fCXzxaECus2cEJ9M7pk4yKatEwQMqQ==
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
"@esbuild/android-arm" "0.17.4"
|
"@esbuild/android-arm" "0.17.5"
|
||||||
"@esbuild/android-arm64" "0.17.4"
|
"@esbuild/android-arm64" "0.17.5"
|
||||||
"@esbuild/android-x64" "0.17.4"
|
"@esbuild/android-x64" "0.17.5"
|
||||||
"@esbuild/darwin-arm64" "0.17.4"
|
"@esbuild/darwin-arm64" "0.17.5"
|
||||||
"@esbuild/darwin-x64" "0.17.4"
|
"@esbuild/darwin-x64" "0.17.5"
|
||||||
"@esbuild/freebsd-arm64" "0.17.4"
|
"@esbuild/freebsd-arm64" "0.17.5"
|
||||||
"@esbuild/freebsd-x64" "0.17.4"
|
"@esbuild/freebsd-x64" "0.17.5"
|
||||||
"@esbuild/linux-arm" "0.17.4"
|
"@esbuild/linux-arm" "0.17.5"
|
||||||
"@esbuild/linux-arm64" "0.17.4"
|
"@esbuild/linux-arm64" "0.17.5"
|
||||||
"@esbuild/linux-ia32" "0.17.4"
|
"@esbuild/linux-ia32" "0.17.5"
|
||||||
"@esbuild/linux-loong64" "0.17.4"
|
"@esbuild/linux-loong64" "0.17.5"
|
||||||
"@esbuild/linux-mips64el" "0.17.4"
|
"@esbuild/linux-mips64el" "0.17.5"
|
||||||
"@esbuild/linux-ppc64" "0.17.4"
|
"@esbuild/linux-ppc64" "0.17.5"
|
||||||
"@esbuild/linux-riscv64" "0.17.4"
|
"@esbuild/linux-riscv64" "0.17.5"
|
||||||
"@esbuild/linux-s390x" "0.17.4"
|
"@esbuild/linux-s390x" "0.17.5"
|
||||||
"@esbuild/linux-x64" "0.17.4"
|
"@esbuild/linux-x64" "0.17.5"
|
||||||
"@esbuild/netbsd-x64" "0.17.4"
|
"@esbuild/netbsd-x64" "0.17.5"
|
||||||
"@esbuild/openbsd-x64" "0.17.4"
|
"@esbuild/openbsd-x64" "0.17.5"
|
||||||
"@esbuild/sunos-x64" "0.17.4"
|
"@esbuild/sunos-x64" "0.17.5"
|
||||||
"@esbuild/win32-arm64" "0.17.4"
|
"@esbuild/win32-arm64" "0.17.5"
|
||||||
"@esbuild/win32-ia32" "0.17.4"
|
"@esbuild/win32-ia32" "0.17.5"
|
||||||
"@esbuild/win32-x64" "0.17.4"
|
"@esbuild/win32-x64" "0.17.5"
|
||||||
|
|
||||||
escape-string-regexp@^1.0.5:
|
escape-string-regexp@^1.0.5:
|
||||||
version "1.0.5"
|
version "1.0.5"
|
||||||
|
|
Loading…
Reference in New Issue