diff --git a/app.rb b/app.rb index 67ae8f57..d016a5b2 100644 --- a/app.rb +++ b/app.rb @@ -594,7 +594,7 @@ post '/api/upload' do api_success 'your file(s) have been successfully uploaded' end -post '/api/:delete' do +post '/api/delete' do require_api_credentials api_error 'missing_filenames', 'you must provide files to delete' if params[:filenames].nil? || params[:filenames].empty? @@ -603,15 +603,15 @@ post '/api/:delete' do params[:filenames].each do |filename| unless filename.is_a?(String) && Site.valid_filename?(filename) - api_error 'bad_filename', "#{filename} is not a valid filename, canceled all deletes" + api_error 'bad_filename', "#{filename} is not a valid filename, canceled deleting" end if !current_site.file_exists?(filename) - api_error 'missing_files', "#{filename} was not found on your site, canceled all deletes" + api_error 'missing_files', "#{filename} was not found on your site, canceled deleting" end if filename == 'index.html' - api_error 'cannot_delete_index', 'you cannot delete your index.html file, canceled all deletes' + api_error 'cannot_delete_index', 'you cannot delete your index.html file, canceled deleting' end filenames << filename @@ -621,7 +621,31 @@ post '/api/:delete' do current_site.delete_file(filename) end - api_success 'files have been deleted' + api_success 'file(s) have been deleted' +end + +get '/api/info' do + if params[:sitename] + site = Site[username: params[:sitename]] + api_error 'site_not_found', "could not find site #{params[:sitename]}" if site.nil? + api_success api_info_for(site) + else + init_api_credentials + api_success api_info_for(current_site) + end +end + +def api_info_for(site) + { + info: { + sitename: site.username, + hits: site.hits, + created_at: site.created_at.rfc2822, + last_updated: site.updated_at.rfc2822, + domain: site.domain, + tags: site.tags.collect {|t| t.name} + } + } end # Catch-all for missing api calls @@ -676,32 +700,45 @@ def encoding_fix(file) end def require_api_credentials - if auth = request.env['HTTP_AUTHORIZATION'] - - begin - user, pass = Base64.decode64(auth.match(/Basic (.+)/)[1]).split(':') - rescue - api_error_invalid_auth - end - - if Site.valid_login? user, pass - site = Site[username: user] - - if site.nil? || site.is_banned - api_error_invalid_auth - end - - session[:id] = site.id - else - api_error_invalid_auth - end + if !request.env['HTTP_AUTHORIZATION'].nil? + init_api_credentials else api_error_invalid_auth end end -def api_success(message) - halt({result: 'success', message: message}.to_json) +def init_api_credentials + auth = request.env['HTTP_AUTHORIZATION'] + + begin + user, pass = Base64.decode64(auth.match(/Basic (.+)/)[1]).split(':') + rescue + api_error_invalid_auth + end + + if Site.valid_login? user, pass + site = Site[username: user] + + if site.nil? || site.is_banned + api_error_invalid_auth + end + + session[:id] = site.id + else + api_error_invalid_auth + end +end + +def api_success(message_or_obj) + output = {result: 'success'} + + if message_or_obj.is_a?(String) + output[:message] = message_or_obj + else + output.merge! message_or_obj + end + + halt output.to_json end def api_error(error_type, message) diff --git a/models/site.rb b/models/site.rb index 0687e371..f7ba700b 100644 --- a/models/site.rb +++ b/models/site.rb @@ -73,10 +73,11 @@ class Site < Sequel::Model end def new_tags=(tags_string) - tags_string.gsub! /[^a-zA-Z0-9, ]/, '' + tags_string.gsub! ', ', ',' tags = tags_string.split ',' + tags_string.gsub! /[^a-zA-Z0-9, ]/, '' tags.collect! {|c| (c.match(/^\w+\s\w+/) || c.match(/^\w+/)).to_s } - @new_tag_strings = tags + @new_tag_strings = tags.sort end def before_validation diff --git a/tests/api_tests.rb b/tests/api_tests.rb index d6b5e04f..c5361152 100644 --- a/tests/api_tests.rb +++ b/tests/api_tests.rb @@ -14,6 +14,45 @@ def create_site @pass = site_attr[:password] end +describe 'api info' do + it 'fails for no input' do + get '/api/info' + res[:error_type] = 'missing_sitename' + end + + it 'fails for nonexistent site' do + get '/api/info', sitename: 'notexist' + res[:error_type].must_equal 'site_not_found' + end + + it 'succeeds for valid sitename' do + create_site + @site.update hits: 31337, domain: 'derp.com', new_tags: 'derpie, man' + get '/api/info', sitename: @user + res[:result].must_equal 'success' + res[:info][:sitename].must_equal @site.username + res[:info][:hits].must_equal 31337 + res[:info][:created_at].must_equal @site.created_at.rfc2822 + res[:info][:last_updated].must_equal @site.updated_at.rfc2822 + res[:info][:domain].must_equal 'derp.com' + res[:info][:tags].must_equal ['derpie', 'man'] + end + + it 'fails for bad auth' do + basic_authorize 'derp', 'fake' + get '/api/info' + res[:error_type].must_equal 'invalid_auth' + end + + it 'succeeds for api auth' do + create_site + @site.update hits: 12345 + basic_authorize @user, @pass + get '/api/info' + res[:info][:hits] == 12345 + end +end + describe 'api delete' do it 'fails with no or bad auth' do post '/api/delete', filenames: ['hi.html'] diff --git a/views/api.erb b/views/api.erb index 4794ba21..f3d195ea 100644 --- a/views/api.erb +++ b/views/api.erb @@ -52,10 +52,10 @@ var NeoCities = require('neocities') var api = new NeoCities('YOURUSERNAME', 'YOURPASSWORD') -// Upload a file called local.html from your computer, -// which will be named newfile.html on the site. - -api.uploadFile('newfile.html', './local.html', function(resp) { +api.uploadFiles([{ + name: 'newfileonsite.html' + path: './local.html' +}], function(resp) { if(resp.result == 'error') throw new Error(resp.error_type+' - '+resp.message) @@ -63,6 +63,10 @@ api.uploadFile('newfile.html', './local.html', function(resp) { console.log(resp) }) + +

+ +

POST /api/delete

@@ -80,4 +84,18 @@ api.uploadFile('newfile.html', './local.html', function(resp) { curl -d "filenames[]=img1.jpg" -d "filenames[]=img2.jpg" \
https://YOURUSER:YOURPASS@neocities.org/api/delete
+ +

GET /api/info

+

+ This call lets you retreive information about a web site. This call does not require site authorization if you provide a sitename argument. Note that the sitename is the same as a username. If you provide auth credentials, you will receive the info for the auth user's site. +

+

Examples

+
Using cURL
+ + $ curl https://neocities.org/api/info?sitename=youpi + + + + $ curl https://YOURUSER:YOURPASS@neocities.org/api/info +