mirror of
https://github.com/neocities/neocities.git
synced 2025-04-24 17:22:35 +02:00
start tracking files in our database
This commit is contained in:
parent
d2f349acd6
commit
aedc5e363c
5 changed files with 132 additions and 36 deletions
30
migrations/052_site_files_composite_keys.rb
Normal file
30
migrations/052_site_files_composite_keys.rb
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
Sequel.migration do
|
||||||
|
up {
|
||||||
|
DB.drop_table :site_files
|
||||||
|
|
||||||
|
DB.create_table! :site_files do
|
||||||
|
Integer :site_id
|
||||||
|
String :path
|
||||||
|
Bigint :size
|
||||||
|
String :sha1_hash
|
||||||
|
Boolean :is_directory, default: false
|
||||||
|
DateTime :created_at
|
||||||
|
DateTime :updated_at
|
||||||
|
primary_key [:site_id, :path], :name => :site_files_pk
|
||||||
|
end
|
||||||
|
}
|
||||||
|
|
||||||
|
down {
|
||||||
|
DB.drop_table :site_files
|
||||||
|
|
||||||
|
DB.create_table! :site_files do
|
||||||
|
Integer :site_id, index: true
|
||||||
|
String :path
|
||||||
|
Bigint :size
|
||||||
|
String :sha1_hash
|
||||||
|
Boolean :is_directory, default: false
|
||||||
|
DateTime :created_at
|
||||||
|
DateTime :updated_at
|
||||||
|
end
|
||||||
|
}
|
||||||
|
end
|
|
@ -144,6 +144,8 @@ class Site < Sequel::Model
|
||||||
many_to_one :parent, :key => :parent_site_id, :class => self
|
many_to_one :parent, :key => :parent_site_id, :class => self
|
||||||
one_to_many :children, :key => :parent_site_id, :class => self
|
one_to_many :children, :key => :parent_site_id, :class => self
|
||||||
|
|
||||||
|
one_to_many :site_files
|
||||||
|
|
||||||
def account_sites_dataset
|
def account_sites_dataset
|
||||||
Site.where(Sequel.|({id: owner.id}, {parent_site_id: owner.id})).order(:parent_site_id.desc, :username)
|
Site.where(Sequel.|({id: owner.id}, {parent_site_id: owner.id})).order(:parent_site_id.desc, :username)
|
||||||
end
|
end
|
||||||
|
@ -453,8 +455,11 @@ class Site < Sequel::Model
|
||||||
relative_path = scrubbed_path path
|
relative_path = scrubbed_path path
|
||||||
path = files_path path
|
path = files_path path
|
||||||
|
|
||||||
if File.exist?(path) &&
|
site_file = site_files_dataset.where(path: relative_path).first
|
||||||
Digest::SHA1.file(path).digest == Digest::SHA1.file(uploaded.path).digest
|
|
||||||
|
uploaded_sha1 = Digest::SHA1.file(uploaded.path).hexdigest
|
||||||
|
|
||||||
|
if site_file && site_file.sha1_hash == uploaded_sha1
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -504,9 +509,20 @@ class Site < Sequel::Model
|
||||||
FileUtils.mkdir_p dirname
|
FileUtils.mkdir_p dirname
|
||||||
end
|
end
|
||||||
|
|
||||||
|
uploaded_size = uploaded.size
|
||||||
|
|
||||||
FileUtils.mv uploaded.path, path
|
FileUtils.mv uploaded.path, path
|
||||||
File.chmod 0640, path
|
File.chmod 0640, path
|
||||||
|
|
||||||
|
site_file ||= SiteFile.new site_id: self.id, path: relative_path
|
||||||
|
|
||||||
|
site_file.set_all(
|
||||||
|
size: uploaded_size,
|
||||||
|
sha1_hash: uploaded_sha1,
|
||||||
|
updated_at: Time.now
|
||||||
|
)
|
||||||
|
site_file.save
|
||||||
|
|
||||||
purge_cache path
|
purge_cache path
|
||||||
|
|
||||||
ext = File.extname(path).gsub(/^./, '')
|
ext = File.extname(path).gsub(/^./, '')
|
||||||
|
@ -581,6 +597,7 @@ class Site < Sequel::Model
|
||||||
|
|
||||||
path = path[1..path.length] if path[0] == '/'
|
path = path[1..path.length] if path[0] == '/'
|
||||||
|
|
||||||
|
site_files_dataset.where(path: path).delete
|
||||||
SiteChangeFile.filter(site_id: self.id, filename: path).delete
|
SiteChangeFile.filter(site_id: self.id, filename: path).delete
|
||||||
|
|
||||||
true
|
true
|
||||||
|
|
6
models/site_file.rb
Normal file
6
models/site_file.rb
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
class SiteFile < Sequel::Model
|
||||||
|
|
||||||
|
unrestrict_primary_key
|
||||||
|
plugin :update_primary_key
|
||||||
|
many_to_one :site
|
||||||
|
end
|
BIN
tests/files/img/test.jpg
Normal file
BIN
tests/files/img/test.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 37 KiB |
|
@ -1,62 +1,88 @@
|
||||||
require_relative './environment.rb'
|
require_relative './environment.rb'
|
||||||
|
|
||||||
|
include Rack::Test::Methods
|
||||||
|
|
||||||
|
def app
|
||||||
|
Sinatra::Application
|
||||||
|
end
|
||||||
|
|
||||||
|
def upload(hash)
|
||||||
|
post '/site_files/upload', hash.merge(csrf_token: 'abcd'), {'rack.session' => { 'id' => @site.id, '_csrf_token' => 'abcd' }}
|
||||||
|
end
|
||||||
|
|
||||||
|
def delete_file(hash)
|
||||||
|
post '/site_files/delete', hash.merge(csrf_token: 'abcd'), {'rack.session' => { 'id' => @site.id, '_csrf_token' => 'abcd' }}
|
||||||
|
end
|
||||||
|
|
||||||
describe 'site_files' do
|
describe 'site_files' do
|
||||||
|
before do
|
||||||
|
@site = Fabricate :site
|
||||||
|
ThumbnailWorker.jobs.clear
|
||||||
|
PurgeCacheWorker.jobs.clear
|
||||||
|
ScreenshotWorker.jobs.clear
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'delete' do
|
||||||
|
it 'works' do
|
||||||
|
upload 'files[]' => Rack::Test::UploadedFile.new('./tests/files/test.jpg', 'image/jpeg')
|
||||||
|
file_path = @site.files_path 'test.jpg'
|
||||||
|
File.exists?(file_path).must_equal true
|
||||||
|
delete_file filename: 'test.jpg'
|
||||||
|
File.exists?(file_path).must_equal false
|
||||||
|
SiteFile[site_id: @site.id, path: 'test.jpg'].must_be_nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
describe 'upload' do
|
describe 'upload' do
|
||||||
it 'succeeds with index.html file' do
|
it 'succeeds with index.html file' do
|
||||||
site = Fabricate :site
|
@site.site_changed.must_equal false
|
||||||
site.site_changed.must_equal false
|
upload 'files[]' => Rack::Test::UploadedFile.new('./tests/files/index.html', 'text/html')
|
||||||
PurgeCacheWorker.jobs.clear
|
|
||||||
ScreenshotWorker.jobs.clear
|
|
||||||
|
|
||||||
post '/site_files/upload', {
|
|
||||||
'files[]' => Rack::Test::UploadedFile.new('./tests/files/index.html', 'text/html'),
|
|
||||||
'csrf_token' => 'abcd'
|
|
||||||
}, {'rack.session' => { 'id' => site.id, '_csrf_token' => 'abcd' }}
|
|
||||||
last_response.body.must_match /successfully uploaded/i
|
last_response.body.must_match /successfully uploaded/i
|
||||||
File.exists?(site.files_path('index.html')).must_equal true
|
File.exists?(@site.files_path('index.html')).must_equal true
|
||||||
|
|
||||||
args = ScreenshotWorker.jobs.first['args']
|
args = ScreenshotWorker.jobs.first['args']
|
||||||
args.first.must_equal site.username
|
args.first.must_equal @site.username
|
||||||
args.last.must_equal 'index.html'
|
args.last.must_equal 'index.html'
|
||||||
site.reload.site_changed.must_equal true
|
@site.reload.site_changed.must_equal true
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'succeeds with valid file' do
|
it 'succeeds with valid file' do
|
||||||
site = Fabricate :site
|
upload 'files[]' => Rack::Test::UploadedFile.new('./tests/files/test.jpg', 'image/jpeg')
|
||||||
PurgeCacheWorker.jobs.clear
|
|
||||||
ThumbnailWorker.jobs.clear
|
|
||||||
post '/site_files/upload', {
|
|
||||||
'files[]' => Rack::Test::UploadedFile.new('./tests/files/test.jpg', 'image/jpeg'),
|
|
||||||
'csrf_token' => 'abcd'
|
|
||||||
}, {'rack.session' => { 'id' => site.id, '_csrf_token' => 'abcd' }}
|
|
||||||
last_response.body.must_match /successfully uploaded/i
|
last_response.body.must_match /successfully uploaded/i
|
||||||
File.exists?(site.files_path('test.jpg')).must_equal true
|
File.exists?(@site.files_path('test.jpg')).must_equal true
|
||||||
|
|
||||||
queue_args = PurgeCacheWorker.jobs.first['args'].first
|
queue_args = PurgeCacheWorker.jobs.first['args'].first
|
||||||
queue_args['site'].must_equal site.username
|
queue_args['site'].must_equal @site.username
|
||||||
queue_args['path'].must_equal '/test.jpg'
|
queue_args['path'].must_equal '/test.jpg'
|
||||||
|
|
||||||
ThumbnailWorker.jobs.length.must_equal 1
|
ThumbnailWorker.jobs.length.must_equal 1
|
||||||
ThumbnailWorker.drain
|
ThumbnailWorker.drain
|
||||||
|
|
||||||
Site::THUMBNAIL_RESOLUTIONS.each do |resolution|
|
Site::THUMBNAIL_RESOLUTIONS.each do |resolution|
|
||||||
File.exists?(site.thumbnail_path('test.jpg', resolution)).must_equal true
|
File.exists?(@site.thumbnail_path('test.jpg', resolution)).must_equal true
|
||||||
end
|
end
|
||||||
|
|
||||||
site.site_changed.must_equal false
|
@site.site_changed.must_equal false
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'overwrites existing file with new file' do
|
||||||
|
upload 'files[]' => Rack::Test::UploadedFile.new('./tests/files/test.jpg', 'image/jpeg')
|
||||||
|
last_response.body.must_match /successfully uploaded/i
|
||||||
|
digest = @site.reload.site_files.first.sha1_hash
|
||||||
|
upload 'files[]' => Rack::Test::UploadedFile.new('./tests/files/img/test.jpg', 'image/jpeg')
|
||||||
|
last_response.body.must_match /successfully uploaded/i
|
||||||
|
@site.reload.changed_count.must_equal 2
|
||||||
|
@site.site_files.count.must_equal 1
|
||||||
|
digest.wont_equal @site.reload.site_files.first.sha1_hash
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'works with directory path' do
|
it 'works with directory path' do
|
||||||
site = Fabricate :site
|
upload(
|
||||||
ThumbnailWorker.jobs.clear
|
|
||||||
PurgeCacheWorker.jobs.clear
|
|
||||||
post '/site_files/upload', {
|
|
||||||
'dir' => 'derpie/derptest',
|
'dir' => 'derpie/derptest',
|
||||||
'files[]' => Rack::Test::UploadedFile.new('./tests/files/test.jpg', 'image/jpeg'),
|
'files[]' => Rack::Test::UploadedFile.new('./tests/files/test.jpg', 'image/jpeg')
|
||||||
'csrf_token' => 'abcd'
|
)
|
||||||
}, {'rack.session' => { 'id' => site.id, '_csrf_token' => 'abcd' }}
|
|
||||||
last_response.body.must_match /successfully uploaded/i
|
last_response.body.must_match /successfully uploaded/i
|
||||||
File.exists?(site.files_path('derpie/derptest/test.jpg')).must_equal true
|
File.exists?(@site.files_path('derpie/derptest/test.jpg')).must_equal true
|
||||||
|
|
||||||
PurgeCacheWorker.jobs.length.must_equal 1
|
PurgeCacheWorker.jobs.length.must_equal 1
|
||||||
queue_args = PurgeCacheWorker.jobs.first['args'].first
|
queue_args = PurgeCacheWorker.jobs.first['args'].first
|
||||||
|
@ -66,11 +92,28 @@ describe 'site_files' do
|
||||||
ThumbnailWorker.drain
|
ThumbnailWorker.drain
|
||||||
|
|
||||||
Site::THUMBNAIL_RESOLUTIONS.each do |resolution|
|
Site::THUMBNAIL_RESOLUTIONS.each do |resolution|
|
||||||
File.exists?(site.thumbnail_path('derpie/derptest/test.jpg', resolution)).must_equal true
|
File.exists?(@site.thumbnail_path('derpie/derptest/test.jpg', resolution)).must_equal true
|
||||||
site.thumbnail_url('derpie/derptest/test.jpg', resolution).must_equal(
|
@site.thumbnail_url('derpie/derptest/test.jpg', resolution).must_equal(
|
||||||
File.join "#{Site::THUMBNAILS_URL_ROOT}", site.username, "/derpie/derptest/test.jpg.#{resolution}.jpg"
|
File.join "#{Site::THUMBNAILS_URL_ROOT}", @site.username, "/derpie/derptest/test.jpg.#{resolution}.jpg"
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it 'does not store new file if hash matches' do
|
||||||
|
upload(
|
||||||
|
'dir' => 'derpie/derptest',
|
||||||
|
'files[]' => Rack::Test::UploadedFile.new('./tests/files/test.jpg', 'image/jpeg')
|
||||||
|
)
|
||||||
|
@site.reload.changed_count.must_equal 1
|
||||||
|
|
||||||
|
upload(
|
||||||
|
'dir' => 'derpie/derptest',
|
||||||
|
'files[]' => Rack::Test::UploadedFile.new('./tests/files/test.jpg', 'image/jpeg')
|
||||||
|
)
|
||||||
|
@site.reload.changed_count.must_equal 1
|
||||||
|
|
||||||
|
upload 'files[]' => Rack::Test::UploadedFile.new('./tests/files/index.html', 'text/html')
|
||||||
|
@site.reload.changed_count.must_equal 2
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
Loading…
Add table
Reference in a new issue