diff --git a/Gemfile b/Gemfile index 3f23fef6..99544a19 100644 --- a/Gemfile +++ b/Gemfile @@ -8,7 +8,7 @@ gem 'bcrypt' gem 'sinatra-flash', require: 'sinatra/flash' gem 'sinatra-xsendfile', require: 'sinatra/xsendfile' gem 'puma', '5.6.5', require: nil -gem 'sidekiq', '~> 5.2.0' +gem 'sidekiq', '~> 7.0.8' gem 'mail' gem 'net-smtp' gem 'tilt' diff --git a/Gemfile.lock b/Gemfile.lock index 539127bf..9ef6a41b 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -49,7 +49,7 @@ GEM climate_control (0.2.0) coderay (1.1.3) concurrent-ruby (1.2.2) - connection_pool (2.3.0) + connection_pool (2.4.0) coveralls_reborn (0.25.0) simplecov (>= 0.18.1, < 0.22.0) term-ansicolor (~> 1.6) @@ -187,11 +187,11 @@ GEM net-protocol netrc (0.11.0) nio4r (2.5.8) - nokogiri (1.13.10-x86_64-linux) + nokogiri (1.14.3-x86_64-linux) racc (~> 1.4) ox (2.14.11) paypal-recurring (1.1.0) - pg (1.4.4) + pg (1.5.3) progress (3.6.0) pry (0.14.1) coderay (~> 1.1) @@ -199,7 +199,7 @@ GEM public_suffix (5.0.0) puma (5.6.5) nio4r (~> 2.0) - racc (1.6.2) + racc (1.7.1) rack (2.2.6.4) rack-cache (1.13.0) rack (>= 0.4) @@ -215,6 +215,8 @@ GEM rb-inotify (0.10.1) ffi (~> 1.0) redis (4.5.1) + redis-client (0.14.1) + connection_pool redis-namespace (1.9.0) redis (>= 4) regexp_parser (2.6.0) @@ -230,7 +232,7 @@ GEM rszr (1.3.0) ruby-progressbar (1.11.0) ruby2_keywords (0.0.5) - sanitize (6.0.1) + sanitize (6.0.2) crass (~> 1.0.2) nokogiri (>= 1.12.0) sass (3.7.4) @@ -239,17 +241,17 @@ GEM rb-fsevent (~> 0.9, >= 0.9.4) rb-inotify (~> 0.9, >= 0.9.7) sax-machine (1.3.2) - sequel (5.62.0) - sequel_pg (1.17.0) + sequel (5.68.0) + sequel_pg (1.17.1) pg (>= 0.18.0, != 1.2.0) sequel (>= 4.38.0) shotgun (0.9.2) rack (>= 1.0) - sidekiq (5.2.10) - connection_pool (~> 2.2, >= 2.2.2) - rack (~> 2.0) - rack-protection (>= 1.5.0) - redis (~> 4.5, < 4.6.0) + sidekiq (7.0.8) + concurrent-ruby (< 2) + connection_pool (>= 2.3.0) + rack (>= 2.2.4) + redis-client (>= 0.11.0) simplecov (0.21.2) docile (~> 1.1) simplecov-html (~> 0.11) @@ -370,7 +372,7 @@ DEPENDENCIES sequel sequel_pg shotgun - sidekiq (~> 5.2.0) + sidekiq (~> 7.0.8) simplecov simpleidn sinatra diff --git a/app/create.rb b/app/create.rb index 101633bd..3506d43c 100644 --- a/app/create.rb +++ b/app/create.rb @@ -1,7 +1,12 @@ CREATE_MATCH_REGEX = /^username$|^password$|^email$|^new_tags_string$|^is_education$/ +def education_whitelist_required? + return true if params[:is_education] == 'true' && $config['education_tag_whitelist'] + false +end + def education_whitelisted? - return true if params[:is_education] == 'true' && $config['education_tag_whitelist'] && !$config['education_tag_whitelist'].select {|t| params[:new_tags_string].match(t)}.empty? + return true if education_whitelist_required? && !$config['education_tag_whitelist'].select {|t| params[:new_tags_string].match(t)}.empty? false end @@ -63,8 +68,13 @@ post '/create' do ga_adgroupid: session[:ga_adgroupid] ) - if education_whitelisted? - @site.email_confirmed = true + if education_whitelist_required? + if education_whitelisted? + @site.email_confirmed = true + else + flash[:error] = 'The class tag is invalid.' + return {result: 'error'}.to_json + end else if !hcaptcha_valid? flash[:error] = 'The captcha was not valid, please try again.' diff --git a/app/settings.rb b/app/settings.rb index 27b8b6cd..e343582f 100644 --- a/app/settings.rb +++ b/app/settings.rb @@ -20,6 +20,9 @@ get '/settings/:username/?' do |username| pass if Site.select(:id).where(username: username).first.nil? require_login require_ownership_for_settings + + @bluesky_did = $redis_proxy.hget "dns-_atproto.#{@site.username}.neocities.org", 'TXT' + @title = "Site settings for #{username}" erb :'settings/site' end @@ -174,15 +177,33 @@ post '/settings/:username/custom_domain' do end end +post '/settings/:username/bluesky_set_did' do + require_login + require_ownership_for_settings + redirect '/settings' if !@site.domain.empty? + + # todo standards based validation + if params[:did].length > 50 + flash[:error] = 'DID provided was too long' + elsif !params[:did].match(/^did=did:plc:([a-z|0-9)]+)$/) + flash[:error] = 'DID was invalid' + else + $redis_proxy.hset "dns-_atproto.#{@site.username}.neocities.org", 'TXT', params[:did] + flash[:success] = 'DID set! You can now verify the domain on the Bluesky app.' + end + + redirect "/settings/#{@site.username}#bluesky" +end + post '/settings/:username/generate_api_key' do require_login require_ownership_for_settings - is_new = current_site.api_key.nil? - current_site.generate_api_key! + is_new = @site.api_key.nil? + @site.generate_api_key! msg = is_new ? "New API key has been generated." : "API key has been regenerated." flash[:success] = msg - redirect "/settings/#{current_site.username}#api_key" + redirect "/settings/#{@site.username}#api_key" end post '/settings/change_password' do diff --git a/models/event.rb b/models/event.rb index cdb25fd2..88122284 100644 --- a/models/event.rb +++ b/models/event.rb @@ -35,6 +35,7 @@ class Event < Sequel::Model ds = select_all(:events). order(:created_at.desc). join_table(:inner, :sites, id: :site_id). + where(follow_id: nil). exclude(Sequel.qualify(:sites, :is_deleted) => true). exclude(Sequel.qualify(:events, :is_deleted) => true). exclude(is_banned: true) diff --git a/models/site.rb b/models/site.rb index 9e3927c3..f45c2bea 100644 --- a/models/site.rb +++ b/models/site.rb @@ -35,6 +35,7 @@ class Site < Sequel::Model application/rss+xml application/x-elc image/webp + image/avif image/x-xcf application/epub application/epub+zip @@ -43,11 +44,11 @@ class Site < Sequel::Model } VALID_EXTENSIONS = %w{ - html htm txt text css js jpg jpeg png gif svg md markdown eot ttf woff woff2 json geojson csv tsv mf ico pdf asc key pgp xml mid midi manifest otf webapp less sass rss kml dae obj mtl scss webp xcf epub gltf bin webmanifest knowl atom opml rdf map gpg + html htm txt text css js jpg jpeg png gif svg md markdown eot ttf woff woff2 json geojson csv tsv mf ico pdf asc key pgp xml mid midi manifest otf webapp less sass rss kml dae obj mtl scss webp avif xcf epub gltf bin webmanifest knowl atom opml rdf map gpg resolveHandle } VALID_EDITABLE_EXTENSIONS = %w{ - html htm txt js css scss md manifest less webmanifest xml json opml rdf svg gpg pgp + html htm txt js css scss md manifest less webmanifest xml json opml rdf svg gpg pgp resolveHandle } MINIMUM_PASSWORD_LENGTH = 5 @@ -166,6 +167,7 @@ class Site < Sequel::Model MAX_COMMENTS_PER_DAY = 5 SANDBOX_TIME = 14.days BLACK_BOX_WAIT_TIME = 10.seconds + MAX_DISPLAY_FOLLOWS = 56*3 many_to_many :tags @@ -568,8 +570,8 @@ class Site < Sequel::Model follows_dataset.all end - def profile_follows_actioning_ids - follows_dataset.select(:actioning_site_id).exclude(:sites__site_changed => false).all + def profile_follows_actioning_ids(limit=nil) + follows_dataset.select(:actioning_site_id).exclude(:sites__site_changed => false).limit(limit).all end =begin @@ -1447,6 +1449,10 @@ class Site < Sequel::Model paginate(current_page, limit) end + def newest_follows + follows_dataset.where(:follows__created_at => (1.month.ago..Time.now)).order(:follows__created_at.desc).all + end + def host !domain.empty? ? domain : "#{username}.neocities.org" end diff --git a/tests/acceptance/settings/site_tests.rb b/tests/acceptance/settings/site_tests.rb index 5a9b4c27..387aad27 100644 --- a/tests/acceptance/settings/site_tests.rb +++ b/tests/acceptance/settings/site_tests.rb @@ -145,6 +145,35 @@ describe 'site/settings' do end end +describe 'api key' do + include Capybara::DSL + + before do + Capybara.reset_sessions! + @site = Fabricate :site + @child_site = Fabricate :site, parent_site_id: @site.id + page.set_rack_session id: @site.id + end + + it 'sets api key' do + visit "/settings/#{@child_site[:username]}#api_key" + _(@site.api_key).must_be_nil + _(@child_site.api_key).must_be_nil + click_button 'Generate API Key' + _(@site.reload.api_key).must_be_nil + _(@child_site.reload.api_key).wont_be_nil + _(page.body).must_match @child_site.api_key + end + + it 'regenerates api key for child site' do + visit "/settings/#{@child_site[:username]}#api_key" + @child_site.generate_api_key! + api_key = @child_site.api_key + click_button 'Generate API Key' + _(@child_site.reload.api_key).wont_equal api_key + end +end + describe 'delete' do include Capybara::DSL diff --git a/tests/acceptance/site_tests.rb b/tests/acceptance/site_tests.rb index 1656ddb4..5ab20e76 100644 --- a/tests/acceptance/site_tests.rb +++ b/tests/acceptance/site_tests.rb @@ -64,36 +64,45 @@ describe 'site page' do end - it 'allows site blocking and unblocking' do - tag = SecureRandom.hex 10 - blocked_site = Fabricate :site, new_tags_string: tag, created_at: 2.weeks.ago, site_changed: true, views: Site::BROWSE_MINIMUM_FOLLOWER_VIEWS+1 - site = Fabricate :site + describe 'blocking' do + before do + @tag = SecureRandom.hex 10 + @blocked_site = Fabricate :site, new_tags_string: @tag, created_at: 2.weeks.ago, site_changed: true, views: Site::BROWSE_MINIMUM_FOLLOWER_VIEWS+1 + end - page.set_rack_session id: site.id + after do + @blocked_site.destroy + end - visit "/browse?tag=#{tag}" + it 'allows site blocking and unblocking' do + site = Fabricate :site - _(page.find('.website-Gallery .username a')['href']).must_match /\/site\/#{blocked_site.username}/ + page.set_rack_session id: site.id - visit "/site/#{blocked_site.username}" + visit "/browse?tag=#{@tag}" - click_link 'Block' - click_button 'Block Site' + _(page.find('.website-Gallery .username a')['href']).must_match /\/site\/#{@blocked_site.username}/ - visit "/browse?tag=#{tag}" + visit "/site/#{@blocked_site.username}" - _(page).must_have_content /no active sites found/i + click_link 'Block' + click_button 'Block Site' - site.reload - _(site.blockings.length).must_equal 1 - _(site.blockings.first.site_id).must_equal blocked_site.id + visit "/browse?tag=#{@tag}" - visit "/site/#{blocked_site.username}" + _(page).must_have_content /no active sites found/i - click_link 'Unblock' + site.reload + _(site.blockings.length).must_equal 1 + _(site.blockings.first.site_id).must_equal @blocked_site.id - visit "/browse?tag=#{tag}" - _(page.find('.website-Gallery .username a')['href']).must_match /\/site\/#{blocked_site.username}/ + visit "/site/#{@blocked_site.username}" + + click_link 'Unblock' + + visit "/browse?tag=#{@tag}" + _(page.find('.website-Gallery .username a')['href']).must_match /\/site\/#{@blocked_site.username}/ + end end it '404s if site is banned' do diff --git a/vagrant/webapp.sh b/vagrant/webapp.sh index f0fb1228..fbddae89 100644 --- a/vagrant/webapp.sh +++ b/vagrant/webapp.sh @@ -4,7 +4,28 @@ DEBIAN_FRONTEND=noninteractive . /vagrant/vagrant/redis.sh -apt-get install -y git curl zlib1g-dev build-essential libssl-dev libreadline-dev libyaml-dev libsqlite3-dev sqlite3 libxml2-dev libxslt1-dev libcurl4-openssl-dev libffi-dev libpq-dev libmagickwand-dev imagemagick libmagickwand-dev libmagic-dev file clamav-daemon +apt-get install -y \ + build-essential \ + clamav-daemon \ + curl \ + file \ + git \ + imagemagick \ + libcurl4-openssl-dev \ + libffi-dev \ + libimlib2-dev \ + libmagic-dev \ + libmagickwand-dev \ + libpq-dev \ + libreadline-dev \ + libsqlite3-dev \ + libssl-dev \ + libwebp-dev \ + libxml2-dev \ + libxslt1-dev \ + libyaml-dev \ + sqlite3 \ + zlib1g-dev sed -i 's|[#]*DetectPUA false|DetectPUA true|g' /etc/clamav/clamd.conf diff --git a/views/_follows.erb b/views/_follows.erb index d9e1a6aa..851257e7 100644 --- a/views/_follows.erb +++ b/views/_follows.erb @@ -1,8 +1,8 @@ -<% site_followings = site.followings %> -<% if (!is_current_site && !site_followings.empty?) || is_current_site %> +<% site_followings = site.followings_dataset.count %> +<% if (!is_current_site && site_followings > 0) || is_current_site %>
You are not following any sites yet. Add some by browsing sites or looking at your tags. <% else %> <% site.followings_dataset.select(:site_id).all.each do |following| %> @@ -12,17 +12,22 @@
" target="_blank">Tumblr
-" target="_blank">Mastodon +" target="_blank">Mastodon diff --git a/views/settings/site.erb b/views/settings/site.erb index bf34f3ae..09b732d9 100644 --- a/views/settings/site.erb +++ b/views/settings/site.erb @@ -26,15 +26,19 @@
Bluesky Integration (beta)
+ ++ You can now verify control of your site on Neocities to create a handle on Bluesky. +
+ ++ Bluesky App "Settings" "Change my handle" "I have my own domain" +
+ ++ Domain: @<%= @site.username %>.neocities.org +
+ ++TXT value: +
+ + \ No newline at end of file diff --git a/views/site.erb b/views/site.erb index b8df7627..bbbd2c35 100644 --- a/views/site.erb +++ b/views/site.erb @@ -74,9 +74,9 @@ <% end %>