Skip to content

Commit

Permalink
Support uploads using the put saver
Browse files Browse the repository at this point in the history
TiddlyWiki's upload.js saver is old and deprecated so let's see if
we can switch to using the put saver.

Includes:
- A bogus WebDAV header to convince TiddlyWiki that the put
  saver is usable
- A new controller method and route for the "put" saves
- Clear the url from $:/UploadURL when serving a site to make
  sure TW doesn't try to use the upload saver

There's a related PR for TiddlyWiki that exposes the error messages
to the user, see TiddlyWiki/TiddlyWiki5#6589

Issue: #148
  • Loading branch information
simonbaird committed Apr 10, 2022
1 parent 4ec6ef2 commit 6c9f92c
Show file tree
Hide file tree
Showing 6 changed files with 108 additions and 14 deletions.
31 changes: 29 additions & 2 deletions rails/app/controllers/tiddlywiki_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ class TiddlywikiController < ApplicationController
before_action :find_site

# TiddlyWiki can't provide the token for saving so we need to skip it
skip_before_action :verify_authenticity_token, only: :save
skip_before_action :verify_authenticity_token, only: [:upload_save, :put_save]

# Rails wants a token for options requests, which TiddlyWiki similarly can't provide
skip_before_action :verify_authenticity_token,
Expand All @@ -20,6 +20,9 @@ class TiddlywikiController < ApplicationController
def serve
return site_not_available unless site_visible?

# Convince TiddlyWiki it can use the put saver
dummy_webdav_header if request.options? && @site.enable_put_saver?

etag_header

# Avoid site download for head or options requests
Expand Down Expand Up @@ -92,7 +95,8 @@ def download
download_html_content(@site.download_content, @site.name)
end

def save
# Using the "upload" saver
def upload_save
begin
if site_saveable?
@site.file_upload(params[:userfile])
Expand All @@ -108,6 +112,24 @@ def save
end
end

# Using the "put" saver
def put_save
begin
if site_saveable?
@site.file_upload(request.body)
@site.increment_save_count
head 204
else
err_message = "If this is your site please log in at #{main_site_url} and try again."
render status: 403, plain: err_message
end
rescue => e
# Todo: Should probably give a generic "Save failed!" message, and log the real problem
err_message = "#{e.class.name} #{e.message}"
render status: 500, plain: err_message
end
end

private

def update_view_count_and_access_timestamp
Expand Down Expand Up @@ -200,4 +222,9 @@ def cors_headers
response.set_header 'Access-Control-Allow-Headers', 'X-Requested-With'
end

# TiddlyWiki just checks if the header exists so the value doesn't matter
def dummy_webdav_header
response.set_header 'dav', "Dummy WebDAV header to enable TiddlyWiki's PUT saver"
end

end
3 changes: 2 additions & 1 deletion rails/app/models/site.rb
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,8 @@ def looks_valid?
end

def html_content(signed_in_user: nil)
th_file.apply_tiddlyhost_mods(name, signed_in_user: signed_in_user).to_html
th_file.apply_tiddlyhost_mods(name,
signed_in_user: signed_in_user, enable_put_saver: enable_put_saver).to_html
end

def json_data(opts={})
Expand Down
3 changes: 2 additions & 1 deletion rails/config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@
get '/favicon.ico', to: 'tiddlywiki#favicon'
get '/download', to: 'tiddlywiki#download'

post '/', to: 'tiddlywiki#save'
post '/', to: 'tiddlywiki#upload_save'
put '/', to: 'tiddlywiki#put_save'
end

#
Expand Down
20 changes: 13 additions & 7 deletions rails/lib/th_file.rb
Original file line number Diff line number Diff line change
Expand Up @@ -38,17 +38,22 @@ def self.from_empty(empty_type)
from_file(empty_path(empty_type))
end

def apply_tiddlyhost_mods(site_name, for_download: false, signed_in_user: nil)
def apply_tiddlyhost_mods(site_name, for_download: false, enable_put_saver: false, signed_in_user: nil)
if is_tw5?

upload_url = if !for_download
# The url for uploads is the same as the site url
Settings.subdomain_site_url(site_name)
else
# Clear $:/UploadURL so the save button in the downloaded file will not try
# to use upload.js. It should use another save method, probably download to file.
upload_url = if for_download || enable_put_saver
# Clear $:/UploadURL for downloads so the save button in the downloaded
# file will not try to use upload.js. It should use another save
# method, probably download to file.
#
# Todo: Consider if we should do that also when signed_in_user is nil.
#
# Clear $:/UploadURL when using the put saver otherwise TW will
# prioritize the upload saver
""
else
# The url for uploads is the same as the site url
Settings.subdomain_site_url(site_name)
end

if !for_download && signed_in_user
Expand All @@ -73,6 +78,7 @@ def apply_tiddlyhost_mods(site_name, for_download: false, signed_in_user: nil)

# Set this otherwise TiddlyWiki won't consider upload.js usable unless there
# is a username and password present.
# (Not needed for put saver but should be harmless.)
'$:/UploadWithUrlOnly' => 'yes',

# Autosave is nice, but I'm thinking we should start with it off to generate
Expand Down
53 changes: 50 additions & 3 deletions rails/test/controllers/tiddlywiki_controller_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ def assert_tid_not_found(url)
site.th_file.write_tiddlers({'NewTiddler'=>'Hey now'}).to_html)

# Now simulate a save
save_site_as_user(user: site.user, site: site, fixture_file: 'index.html')
upload_save_site_as_user(user: site.user, site: site, fixture_file: 'index.html')

# Should see these fields are updated
site.reload
Expand All @@ -146,6 +146,35 @@ def assert_tid_not_found(url)
th_file = fetch_site_as_user(user: site.user, site: site)
assert_equal 'Hey now', th_file.tiddler_content('NewTiddler')

if th_file.is_tw5?
# Same thing again but using the put saver
# (compatible with TW5 only)

site.update(enable_put_saver: true)
prev_blob_key = site.blob.key

File.write(modified_tw_file,
site.th_file.write_tiddlers({'NewTiddler'=>'Hi from put saver'}).to_html)

put_save_site_as_user(user: site.user, site: site, content_file: modified_tw_file)

# Should see these fields are updated
site.reload
assert_not_equal original_blob_key, site.blob.key
assert_not_equal prev_blob_key, site.blob.key
assert original_size < site.raw_byte_size
assert_equal site_name, site.name
assert_equal tw_version, site.tw_version

# Confirm the site has the new tiddler
assert_equal "Hi from put saver", site.th_file.tiddler_content('NewTiddler')

# Confirm it via http get
th_file = fetch_site_as_user(user: site.user, site: site)
assert_equal 'Hi from put saver', th_file.tiddler_content('NewTiddler')

end

# Clean up temporary file
File.delete(modified_tw_file)
end
Expand All @@ -167,7 +196,14 @@ def fetch_site_as_user(user: @user, site: @site, expected_status: 200)
th_file = ThFile.new(response.body)

# Sanity checks
assert_equal site.name, th_file.get_site_name
if site.enable_put_saver?
# Fixme: get_site_name can't work because $:/UploadURL isn't set
#assert_equal site.name, th_file.get_site_name
assert_equal '', th_file.tiddler_content('$:/UploadURL') if th_file.is_tw5?
else
assert_equal site.name, th_file.get_site_name
assert_equal site.url, th_file.tiddler_content('$:/UploadURL') if th_file.is_tw5?
end
assert_equal 'Hi there', th_file.tiddler_content('MyTiddler')
assert_equal 'Bar', th_file.tiddler_content('Foo')
assert_equal '123', th_file.tiddler_content('Baz')
Expand All @@ -183,7 +219,7 @@ def fetch_site_as_user(user: @user, site: @site, expected_status: 200)
end
end

def save_site_as_user(site:, user:, fixture_file:, expected_status: 200)
def upload_save_site_as_user(site:, user:, fixture_file:, expected_status: 200)
host! site.host
sign_in user

Expand All @@ -201,4 +237,15 @@ def save_site_as_user(site:, user:, fixture_file:, expected_status: 200)
# Todo maybe: Is there anything else worth asserting in the headers?
end

def put_save_site_as_user(site:, user:, content_file:, expected_status: 204)
host! site.host
sign_in user

put '/', params: File.read(content_file),
headers: { 'Content-Type' => 'text/html;charset=UTF-8' }

assert_response expected_status
assert_equal '', response.body
end

end
12 changes: 12 additions & 0 deletions rails/test/models/tw_file_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,18 @@ class TwFileTest < ActiveSupport::TestCase
# We can't get the name without $:/UploadURL...
assert_nil tw.get_site_name
end

ThFile.from_empty(:tw5).apply_tiddlyhost_mods('coolsite', enable_put_saver: true).tap do |tw|
{
'$:/UploadURL' => '',
'$:/UploadWithUrlOnly' => 'yes',
'$:/config/AutoSave' => 'no',

}.each do |tiddler_name, expected_content|
assert_equal expected_content, tw.tiddler_content(tiddler_name)
end

end
end

test "tiddlyhost mods for classic" do
Expand Down

0 comments on commit 6c9f92c

Please sign in to comment.