mirror of
https://github.com/neocities/neocities.git
synced 2025-04-24 17:22:35 +02:00
Merge branch 'master' into missing-br
This commit is contained in:
commit
22b8af52c3
20 changed files with 311 additions and 136 deletions
2
Gemfile
2
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'
|
||||
|
|
28
Gemfile.lock
28
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
|
||||
|
|
|
@ -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.'
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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 %>
|
||||
<div class="following-list">
|
||||
<h3><a href="/site/<%= site.username %>/follows"><%= is_current_site ? 'Sites you follow' : 'This site follows' %></a></h3>
|
||||
<% if site_followings.empty? %>
|
||||
<% if site_followings == 0 %>
|
||||
<p>You are not following any sites yet. Add some by <a href="/browse">browsing sites</a> or looking at your tags.
|
||||
<% else %>
|
||||
<% site.followings_dataset.select(:site_id).all.each do |following| %>
|
||||
|
@ -12,17 +12,22 @@
|
|||
</div>
|
||||
<% end %>
|
||||
|
||||
<% site_follows = site.follows %>
|
||||
<% if (!is_current_site && !site_follows.empty?) || is_current_site %>
|
||||
<% site_follows = site.follows_dataset.count %>
|
||||
<% if (!is_current_site && site_follows > 0) || is_current_site %>
|
||||
<div class="follower-list">
|
||||
<h3><a href="/site/<%= site.username %>/followers">Followers</a></h3>
|
||||
<% if site_follows.empty? %>
|
||||
<% if site_follows == 0 %>
|
||||
No followers yet.
|
||||
<% else %>
|
||||
<% site.profile_follows_actioning_ids.each do |follow| %>
|
||||
<% site_profile_follows_actioning_ids = site.profile_follows_actioning_ids %>
|
||||
<% site_profile_follows_actioning_ids[0...Site::MAX_DISPLAY_FOLLOWS].each do |follow| %>
|
||||
<% follow_actioning_site = follow.actioning_site_dataset.select(:username).first %>
|
||||
<a href="/site/<%= follow_actioning_site.username %>" title="<%= follow_actioning_site.title %>"><img src="<%= follow_actioning_site.screenshot_url 'index.html', '50x50' %>" class="avatar" onerror="this.src='/img/50x50.png'"></a>
|
||||
<% end %>
|
||||
|
||||
<% if Site::MAX_DISPLAY_FOLLOWS < site_profile_follows_actioning_ids.count %>
|
||||
<a href="/site/<%= site.username %>/followers"><strong>see more <i class="fa fa-arrow-right"></i></strong></a>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
|
|
@ -10,51 +10,32 @@
|
|||
<script src="/js/news/event.js"></script>
|
||||
<script src="/js/news/site.js"></script>
|
||||
|
||||
<% if defined?(site) && !params[:event_id] %>
|
||||
<% follow_events = site.newest_follows %>
|
||||
<% unless follow_events.empty? %>
|
||||
<div class="news-item follow">
|
||||
<div class="icon"><a href="/site/<%= site.username %>" title="<%= site.username %>" class="avatar" style="background-image: url(<%= site.screenshot_url 'index.html', '50x50' %>);"></a></div>
|
||||
|
||||
<div class="text">
|
||||
<strong>New Followers</strong>
|
||||
</div>
|
||||
|
||||
<div class="content">
|
||||
<% follow_events.first.site.newest_follows.each_with_index do |event,i| %>
|
||||
<a href="/site/<%= event.actioning_site.username %>" class="user" title="<%= event.actioning_site.title %>"><i class="fa fa-user"><% if event.actioning_site.supporter? %><i class="fa fa-heart"></i><% end %></i><%= event.actioning_site.username %></a><% unless follow_events.length == i+1 %>, <% end %>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
<% end %>
|
||||
|
||||
<% events.each do |event| %>
|
||||
<% if event.profile_comment_id %>
|
||||
<div class="news-item comment" id="event_<%= event.id %>">
|
||||
<%== erb :'_news_profile_comment', layout: false, locals: {profile_comment: event.profile_comment, event: event} %>
|
||||
<% elsif event.tip_id %>
|
||||
<% actioning_site = event.actioning_site_dataset.select(:id, :username, :title, :domain, :stripe_customer_id, :plan_type).first %>
|
||||
<% event_site = event.site_dataset.select(:id, :username, :title, :domain, :stripe_customer_id, :plan_type).first %>
|
||||
<% tip = event.tip %>
|
||||
<div class="news-item tip">
|
||||
<div class="title">
|
||||
<div class="icon">
|
||||
<% if actioning_site %>
|
||||
<a href="/site/<%= actioning_site.username %>" title="<%= actioning_site.username %>" class="avatar" style="background-image: url(<%= actioning_site.screenshot_url 'index.html', '50x50' %>);"></a>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<div class="text">
|
||||
<div class="headline">
|
||||
<% if actioning_site %>
|
||||
<% if current_site && current_site.id == actioning_site.id %>
|
||||
<a href="/site/<%= current_site.username %>" class="you">You</a>
|
||||
<% else %>
|
||||
<a href="/site/<%= actioning_site.username %>" class="user" title="<%= actioning_site.title %>"><i class="fa fa-user"><% if actioning_site.supporter? %><i class="fa fa-heart"></i><% end %></i><%= actioning_site.username %></a>
|
||||
<% end %>
|
||||
<% else %>
|
||||
An anonymous donor
|
||||
<% end %>
|
||||
|
||||
sent a <strong><%= tip.amount_string %></strong> tip to
|
||||
|
||||
<% if current_site && event_site.id == current_site.id %>
|
||||
<a href="/site/<%= current_site.username %>" class="you">you</a>!
|
||||
<% else %>
|
||||
<a href="/site/<%= event_site.username %>" class="user" title="<%= event_site.title %>"><i class="fa fa-user"><% if event_site.supporter? %><i class="fa fa-heart"></i><% end %></i><%= event_site.username %></a>!
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<span class="comment"><%= tip.message %></span>
|
||||
</div>
|
||||
|
||||
<span class="date">
|
||||
<a href="/site/<%= event_site.username %>?event_id=<%= event.id %>"><%= event.created_at.ago %></a>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="news-item comment" id="event_<%= event.id %>">
|
||||
<%== erb :'_news_tip', layout: false, locals: {tip: event.tip, event: event} %>
|
||||
<% elsif event.follow_id %>
|
||||
<% actioning_site = event.actioning_site_dataset.select(:id, :username, :title, :domain, :stripe_customer_id, :plan_type).first %>
|
||||
<% next if actioning_site.nil? %>
|
||||
|
|
36
views/_news_tip.erb
Normal file
36
views/_news_tip.erb
Normal file
|
@ -0,0 +1,36 @@
|
|||
<% actioning_site = event.tip.actioning_site_dataset.select(:id, :username, :stripe_customer_id, :plan_type, :parent_site_id).first %>
|
||||
<% event_site = event.site_dataset.select(:id, :username, :stripe_customer_id, :plan_type, :parent_site_id).first %>
|
||||
|
||||
<div class="title">
|
||||
|
||||
<div class="icon">
|
||||
<% if actioning_site %>
|
||||
<a href="/site/<%= actioning_site.username %>" title="<%= actioning_site.username %>" class="avatar" style="background-image: url(<%= actioning_site.screenshot_url 'index.html', '50x50' %>);"></a>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<div class="text">
|
||||
<% if actioning_site %>
|
||||
<% if current_site && current_site.id == actioning_site.id %>
|
||||
<a href="/site/<%= current_site.username %>" class="you">You</a>
|
||||
<% else %>
|
||||
<a href="/site/<%= actioning_site.username %>" class="user" title="<%= actioning_site.title %>"><i class="fa fa-user"><% if actioning_site.supporter? %><i class="fa fa-heart"></i><% end %></i><%= actioning_site.username %></a>
|
||||
<% end %>
|
||||
<% else %>
|
||||
An anonymous donor
|
||||
<% end %>
|
||||
|
||||
sent a <strong style="color: #229954 !important;"><%= tip.amount_string %></strong> tip to
|
||||
<% if current_site && event_site.id == current_site.id %>
|
||||
<a href="/site/<%= current_site.username %>" class="you">you</a>
|
||||
<% else %>
|
||||
<a href="/site/<%= event_site.username %>" class="user" title="<%= event_site.title %>"><i class="fa fa-user"><% if event_site.supporter? %><i class="fa fa-heart"></i><% end %></i><%= event_site.username %></a>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<span class="date">
|
||||
<a href="/site/<%= event_site.username %>?event_id=<%= event.id %>"><%= event.created_at.ago %></a>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="content"><%== sanitize_comment tip.message %></div>
|
|
@ -13,4 +13,4 @@
|
|||
<br>
|
||||
<a href="https://www.tumblr.com/share?<%= Rack::Utils.build_query(v: 3, u: "#{page_uri}", t: "#{site.title}") %>" target="_blank">Tumblr</a>
|
||||
<br>
|
||||
<a href="https://toot.kytta.dev/?<%= Rack::Utils.build_query(text: "#{page_uri}") %>" target="_blank">Mastodon</a>
|
||||
<a href="https://toot.kytta.dev/?<%= Rack::Utils.build_query(text: "#{site.title}: #{page_uri}") %>" target="_blank">Mastodon</a>
|
||||
|
|
|
@ -26,15 +26,19 @@
|
|||
<li class="active"><a href="#profile" data-toggle="tab">Profile</a></li>
|
||||
<!-- <li><a href="#domain" data-toggle="tab">Domain Name</a></li> -->
|
||||
<li><a href="#custom_domain" data-toggle="tab">Custom Domain</a></li>
|
||||
<li><a href="#username" data-toggle="tab">Change Site Name</a></li>
|
||||
<li><a href="#username" data-toggle="tab">Rename</a></li>
|
||||
<li><a href="#tipping" data-toggle="tab">Tipping</a></li>
|
||||
|
||||
<li><a href="#api_key" data-toggle="tab">API Key</a></li>
|
||||
<li><a href="#api_key" data-toggle="tab">API</a></li>
|
||||
|
||||
<% if @site.admin_nsfw != true %>
|
||||
<li><a href="#nsfw" data-toggle="tab">18+</a></li>
|
||||
<% end %>
|
||||
|
||||
<% if @site.domain.empty? %>
|
||||
<li><a href="#bluesky" data-toggle="tab">Bluesky</a></li>
|
||||
<% end %>
|
||||
|
||||
<li><a href="#delete" data-toggle="tab">Delete</a></li>
|
||||
</ul>
|
||||
<div class="tab-content">
|
||||
|
@ -64,6 +68,10 @@
|
|||
</div>
|
||||
<% end %>
|
||||
|
||||
<div class="tab-pane" id="bluesky">
|
||||
<%== erb :'settings/site/bluesky' %>
|
||||
</div>
|
||||
|
||||
<div class="tab-pane" id="delete">
|
||||
<%== erb :'settings/site/delete' %>
|
||||
</div>
|
||||
|
|
24
views/settings/site/bluesky.erb
Normal file
24
views/settings/site/bluesky.erb
Normal file
|
@ -0,0 +1,24 @@
|
|||
<h2>Bluesky Integration (beta)</h2>
|
||||
|
||||
<p>
|
||||
You can now verify control of your site on Neocities to create a handle on <a href="https://bsky.app/">Bluesky</a>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<strong>Bluesky App <i class="fa fa-arrow-right"></i> "Settings" <i class="fa fa-arrow-right"></i> "Change my handle" <i class="fa fa-arrow-right"></i> "I have my own domain"</strong>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Domain: <span style="color: gray">@</span><strong><%= @site.username %>.neocities.org</strong>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
TXT value:
|
||||
</p>
|
||||
|
||||
<form method="POST" action="/settings/<%= @site.username %>/bluesky_set_did">
|
||||
<%== csrf_token_input_html %>
|
||||
<input name="did" type="text" style="width: 50%" placeholder="did=did:plc:somethingexamplesomething" value="<%= @bluesky_did %>">
|
||||
<br>
|
||||
<input class="btn-Action" type="submit" value="Update">
|
||||
</form>
|
|
@ -74,9 +74,9 @@
|
|||
</p>
|
||||
<% end %>
|
||||
</div>
|
||||
<%== erb :'_news', layout: false, locals: {site: @site, events: @latest_events} %>
|
||||
<%== erb :'_news', layout: false, locals: {site: site, events: @latest_events} %>
|
||||
<% else %>
|
||||
<div class="site-profile-padding"><%== erb :'_news', layout: false, locals: {site: @site, events: @latest_events} %></div>
|
||||
<div class="site-profile-padding"><%== erb :'_news', layout: false, locals: {site: site, events: @latest_events} %></div>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -163,42 +163,47 @@
|
|||
|
||||
var editor = {}
|
||||
|
||||
|
||||
$(document).ready(function() {
|
||||
$.get("/site_files/download/<%= Addressable::URI.parse(@filename).normalized_path.to_s %>", function(resp) {
|
||||
editor = ace.edit("editor")
|
||||
setTheme()
|
||||
<% if @ace_mode %>
|
||||
editor.getSession().setMode("ace/mode/<%= @ace_mode %>")
|
||||
<% end %>
|
||||
editor.getSession().setTabSize(2)
|
||||
editor.getSession().setUseWrapMode(true)
|
||||
editor.setFontSize(14)
|
||||
editor.setShowPrintMargin(false)
|
||||
editor.setOptions({
|
||||
maxLines: Infinity,
|
||||
autoScrollEditorIntoView: true
|
||||
})
|
||||
$.ajax({
|
||||
url: "/site_files/download/<%= Addressable::URI.parse(@filename).normalized_path.to_s %>",
|
||||
cache: false,
|
||||
success: function(resp) {
|
||||
editor = ace.edit("editor")
|
||||
setTheme()
|
||||
<% if @ace_mode %>
|
||||
editor.getSession().setMode("ace/mode/<%= @ace_mode %>")
|
||||
<% end %>
|
||||
editor.getSession().setTabSize(2)
|
||||
editor.getSession().setUseWrapMode(true)
|
||||
editor.setFontSize(14)
|
||||
editor.setShowPrintMargin(false)
|
||||
editor.setOptions({
|
||||
maxLines: Infinity,
|
||||
autoScrollEditorIntoView: true
|
||||
})
|
||||
|
||||
// Disable autocomplete
|
||||
editor.setBehavioursEnabled(false)
|
||||
// Disable autocomplete
|
||||
editor.setBehavioursEnabled(false)
|
||||
|
||||
editor.setValue(resp, -1)
|
||||
editor.getSession().setUndoManager(new ace.UndoManager())
|
||||
editor.setValue(resp, -1)
|
||||
editor.getSession().setUndoManager(new ace.UndoManager())
|
||||
|
||||
editor.on('change', function(obj) {
|
||||
$('a#saveButton,a#saveAndExitButton').css('opacity', 1)
|
||||
unsavedChanges = true
|
||||
})
|
||||
editor.on('change', function(obj) {
|
||||
$('a#saveButton,a#saveAndExitButton').css('opacity', 1)
|
||||
unsavedChanges = true
|
||||
})
|
||||
|
||||
editor.commands.addCommand({
|
||||
name: 'saveCommand',
|
||||
bindKey: {win: 'Ctrl-S', mac: 'Command-S'},
|
||||
exec: function(editor) {
|
||||
saveTextFile(false)
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
editor.commands.addCommand({
|
||||
name: 'saveCommand',
|
||||
bindKey: {win: 'Ctrl-S', mac: 'Command-S'},
|
||||
exec: function(editor) {
|
||||
saveTextFile(false)
|
||||
}
|
||||
})
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
window.onbeforeunload = function() {
|
||||
if(unsavedChanges == true)
|
||||
|
|
|
@ -64,7 +64,11 @@ class LetsEncryptWorker
|
|||
puts "testing #{challenge_url}"
|
||||
|
||||
begin
|
||||
res = HTTP.timeout(connect: 10, write: 10, read: 10).follow.get(challenge_url)
|
||||
# Some dumb letsencrypt related cert expiration issue hotfix
|
||||
ctx = OpenSSL::SSL::SSLContext.new
|
||||
ctx.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
||||
|
||||
res = HTTP.timeout(connect: 10, write: 10, read: 10).follow.get(challenge_url, ssl_context: ctx)
|
||||
rescue => e
|
||||
puts e.inspect
|
||||
puts "error with #{challenge_url}"
|
||||
|
|
|
@ -6,7 +6,7 @@ class ScreenshotWorker
|
|||
HARD_TIMEOUT = 30.freeze
|
||||
PAGE_WAIT_TIME = 5.freeze # 3D/VR sites take a bit to render after loading usually.
|
||||
include Sidekiq::Worker
|
||||
sidekiq_options queue: :screenshots, retry: 2, backtrace: true
|
||||
sidekiq_options queue: :screenshots, retry: 10, backtrace: true
|
||||
|
||||
def perform(username, path)
|
||||
site = Site[username: username]
|
||||
|
@ -47,19 +47,21 @@ class ScreenshotWorker
|
|||
base_image_tmpfile_path = "/tmp/#{SecureRandom.uuid}.png"
|
||||
|
||||
http_resp = HTTP.basic_auth(user: api_user, pass: api_password).get(uri)
|
||||
BlackBox.new(site, path).check_uri(http_resp.headers['X-URL']) if defined?(BlackBox)
|
||||
BlackBox.new(site, path).check_uri(http_resp.headers['X-URL']) if defined?(BlackBox) && http_resp.headers['X-URL']
|
||||
File.write base_image_tmpfile_path, http_resp.to_s
|
||||
|
||||
user_screenshots_path = File.join SCREENSHOTS_PATH, Site.sharding_dir(username), username
|
||||
screenshot_path = File.join user_screenshots_path, File.dirname(path_for_screenshot)
|
||||
FileUtils.mkdir_p screenshot_path unless Dir.exist?(screenshot_path)
|
||||
|
||||
FileUtils.cp base_image_tmpfile_path, File.join(user_screenshots_path, "#{path_for_screenshot}.png")
|
||||
|
||||
Site::SCREENSHOT_RESOLUTIONS.each do |res|
|
||||
width, height = res.split('x').collect {|r| r.to_i}
|
||||
|
||||
full_screenshot_path = File.join(user_screenshots_path, "#{path_for_screenshot}.#{res}.webp")
|
||||
|
||||
opts = {quality: 90, resize_w: width, resize_h: height}
|
||||
opts = {resize_w: width, resize_h: height, near_lossless: 0}
|
||||
|
||||
if width == height
|
||||
opts.merge! crop_x: 160, crop_y: 0, crop_w: 960, crop_h: 960
|
||||
|
@ -69,6 +71,8 @@ class ScreenshotWorker
|
|||
end
|
||||
|
||||
true
|
||||
rescue WebP::EncoderError => e
|
||||
puts "Failed: #{username} #{path} #{e.inspect}"
|
||||
rescue => e
|
||||
raise e
|
||||
ensure
|
||||
|
|
|
@ -24,11 +24,20 @@ class ThumbnailWorker
|
|||
format = File.extname(path).gsub('.', '')
|
||||
full_thumbnail_path = File.join(user_thumbnails_path, "#{path}.#{res}.webp")
|
||||
|
||||
image = Rszr::Image.load site_file_path
|
||||
if image.width > image.height
|
||||
image.resize! width, :auto
|
||||
else
|
||||
image.resize! :auto, height
|
||||
begin
|
||||
image = Rszr::Image.load site_file_path
|
||||
rescue Rszr::LoadError
|
||||
next
|
||||
end
|
||||
|
||||
begin
|
||||
if image.width > image.height
|
||||
image.resize! width, :auto
|
||||
else
|
||||
image.resize! :auto, height
|
||||
end
|
||||
rescue Rszr::TransformationError
|
||||
next
|
||||
end
|
||||
|
||||
begin
|
||||
|
|
Loading…
Add table
Reference in a new issue