From c041451360086aaffad96a9dae2b8b1a8bec4083 Mon Sep 17 00:00:00 2001 From: Paul Liverman III Date: Tue, 1 May 2018 17:15:46 -0700 Subject: [PATCH] new API features, better API structure, bug fixes w /get /do /undo --- applications/api.moon | 92 +++++++++++++++++++++++++------------------ helpers/api.moon | 2 +- migrations.moon | 10 +++-- models/APIKeys.moon | 2 +- 4 files changed, 62 insertions(+), 44 deletions(-) diff --git a/applications/api.moon b/applications/api.moon index a529fcf..7540074 100644 --- a/applications/api.moon +++ b/applications/api.moon @@ -8,12 +8,15 @@ import api_request, abort, assert_model from locate "helpers.api" -- import escape_similar_to from locate "db" get_task = => + unless @params.content or tonumber @params.id + @params.content = @params.id + @params.id = nil if @params.id assert_valid @params, { {"id", exists: true, min_length: 1, "Attempted to select by task id, but no id specified."} {"id", is_integer: true, "Task id specified is not an integer."} } - @task = assert_model Tasks\find id: @params.id, user_id: @user.id + @task = assert_model Tasks\find id: tonumber(@params.id), user_id: @user.id elseif @params.content assert_valid @params, { {"content", exists: true, min_length: 1, "Attempted to select by task content, but no content specified."} @@ -24,6 +27,17 @@ get_task = => abort 404, "Invalid task specified." unless @task +set_bool = (name) => + if @params[name] == "true" + @params[name] = true + elseif @params[name] == "false" + @params[name] = false + if @params[name] != nil and "boolean" != type @params[name] + abort "#{name} must be true/false only." + +send_task = => + @write json: { success: true, task: @task } + class API extends Application @path: "/v1" @name: "api_" @@ -40,40 +54,39 @@ class API extends Application abort "Auth: Invalid api_key." unless @user -- NOTE this should also delete the api_key and error (this should never happen!) ) - [new: "/new"]: api_request => - assert_valid @params, { - {"content", exists: true, min_length: 1, "Task content not specified."} - } + [action: "/:action(/:id)"]: api_request => + switch @params.action + when "new" + unless @params.content or tonumber @params.id + @params.content = @params.id + assert_valid @params, { {"content", exists: true, min_length: 1, "Task content not specified."} } + @task = assert_model Tasks\create user_id: @user.id, content: @params.content + send_task(@) + when "get", "do", "undo", "edit", "delete" + get_task(@) + else + abort "Invalid action: #{@params.action}" - task = assert_model Tasks\create { - user_id: @user.id - content: @params.content - } + switch @params.action + when "do" + @task = assert_model @task\update done: true + when "undo" + @task = assert_model @task\update done: false + when "edit" + assert_valid @params, { + {"new_content", exists: true, min_length: 1, optional: true, "Cannot set no content on a task."} + } + set_bool(@, "done") + @task = assert_model @task\update content: @params.new_content, done: @params.done + when "delete" + if @task\delete! + return json: { success: true } + else + abort 500, "Error deleting task." - return json: { success: true, :task } + send_task(@) - [get: "/get"]: api_request => - get_task(@) - return json: { success: true, :task } - [do: "/do"]: api_request => - get_task(@) - @task = assert_model @task\update done: true - - return json: { success: true, :task } - - [undo: "/undo"]: api_request => - get_task(@) - @task = assert_model @task\update done: false - - return json: { success: true, :task } - - [delete: "/delete"]: api_request => - get_task(@) - if @task\delete! - return json: { success: true } - else - abort 500, "Error deleting task." [list: "/list"]: api_request => assert_valid @params, { @@ -82,7 +95,9 @@ class API extends Application {"page", exists: true, is_integer: true, optional: true, "Page is not an integer."} {"order", exists: true, one_of: {"asc", "desc"}, optional: true, "Invalid order. (Must be 'asc' or 'desc'.)"} } + @params.count = tonumber @params.count @params.count or= 50 + @params.page = tonumber @params.page @params.page or= 1 @params.order or= "asc" @params.page = 1 if @params.page < 1 @@ -91,6 +106,7 @@ class API extends Application if @params.done == nil Paginator = Tasks\paginated "WHERE user_id = ? ORDER BY created_at #{@params.order}", @user.id, per_page: @params.count else + set_bool(@, "done") Paginator = Tasks\paginated "WHERE user_id = ? AND done = ? ORDER BY created_at #{@params.order}", @user.id, @params.done, per_page: @params.count num_pages = Paginator\num_pages! @@ -98,9 +114,11 @@ class API extends Application @params.page = num_pages tasks = Paginator\get_page(@params.page) - -- returns page in case it returned a different page than you asked for! (in the case you ask for a page beyond the end) + -- returns page in case it returned a different page than you asked for! (in the case you ask for an out-of-range page) return json: { success: true, page: @params.page, pages: num_pages, :tasks } + + [random: "/random"]: api_request => -- assert_valid @params, { -- {"count", exists: true, is_integer: true, optional: true, "Count is not an integer."} @@ -131,20 +149,16 @@ class API extends Application api_key = assert_model APIKeys\create(@user) return json: { success: true, :api_key } - [delete_key: "/key/delete"]: api_request => + [delete_key: "/key/delete(/:key)"]: api_request => if @params.id - assert_valid @params, { - {"id", exists: true, min_length: 1, "Attempted to select by API key id, but no id specified."} - {"id", is_integer: true, "API key id is not an integer."} - } - @key_to_delete = assert_model APIKeys\find id: @params.id, user_id: @user.id + abort "api_key IDs do not exist anymore (sorry!)." -- no one should ever run into this elseif @params.key assert_valid @params, { {"key", exists: true, min_length: 32, max_length: 32, "Invalid api_key specified."} } @key_to_delete = assert_model APIKeys\find key: @params.key, user_id: @user.id else - abort 400, "No api_key specified." + abort "No api_key specified." abort 404, "Invalid api_key specified." unless @key_to_delete if @key_to_delete\delete! diff --git a/helpers/api.moon b/helpers/api.moon index a14116b..4395bf0 100644 --- a/helpers/api.moon +++ b/helpers/api.moon @@ -14,7 +14,7 @@ api_request = (fn) -> insert errors, err[2] else insert errors, err - return(:status, json: { :errors }) + return(:status, json: { success: false, :errors }) } abort = (status, message) -> diff --git a/migrations.moon b/migrations.moon index 3c76ce8..3d83d3c 100644 --- a/migrations.moon +++ b/migrations.moon @@ -1,4 +1,4 @@ -import create_table, types, create_index, add_column from require "lapis.db.schema" +import create_table, types, create_index, add_column, drop_column from require "lapis.db.schema" import make_migrations, autoload from require "locator" import settings from autoload "utility" @@ -37,9 +37,13 @@ make_migrations { [1524605427]: => add_column "api_keys", "id", types.serial primary_key: true + -- technically there should be a migration here to wipe out the api_keys table + -- due to a strange bug with how adding an id to api_keys works (I think) + [1524607145]: => settings.set "simplex.key-increment", 100 -- I had been accidentally deleting this key over and over again - -- technically there should be a migration here to wipe out the api_keys table - -- due to a strange bug with how adding an id to api_keys works (I think) + [1525245815]: => + drop_column "api_keys", "id" + } diff --git a/models/APIKeys.moon b/models/APIKeys.moon index b02cf85..63c7f69 100644 --- a/models/APIKeys.moon +++ b/models/APIKeys.moon @@ -15,8 +15,8 @@ class APIKeys extends Model error "API Keys need to be created using a user model." values = {} + values.user_id = user.id while true - values.user_id = user.id values.key = encode_base64(bcrypt.digest "#{settings["simplex.key-increment"]}#{user.name}#{user.digest}", settings["users.bcrypt-digest-rounds"])\sub 1, 32 settings["simplex.key-increment"] += 1 unless APIKeys\find key: values.key