wip interface, err fixes, reorganization, config added, test ready

This commit is contained in:
Paul Liverman III 2018-03-16 16:33:32 -07:00
parent 7c6f7dab03
commit aeab084ecb
7 changed files with 247 additions and 105 deletions

126
app.moon
View File

@ -1,115 +1,33 @@
import Application from require "lapis" import Application from require "lapis"
import json_params, capture_errors_json, yield_error, assert_error from require "lapis.application"
import assert_valid from require "lapis.validate"
import Keys, Tasks from require "models" import Keys, Tasks from require "models"
import locate from require "locator" import autoload, locate, registry from require "locator"
import random from locate "calc" import settings from autoload "utility"
import escape_similar_to from locate "db"
get_key = =>
yield_error "api_key not specified." unless @params.api_key and @params.api_key\len! > 0
if key = Keys\find uuid: @params.api_key
return key
else
yield_error "Invalid api_key."
get_task = =>
assert_valid @params, {
{"api_key", exists: true, "api_key not specified."}
{"id", exists: true, "Task id not specified."}
{"id", is_integer: true, "Task id is invalid."}
}
key = Keys\find uuid: @params.api_key
yield_error "Invalid api_key." unless key
task = Tasks\find id: @params.id
yield_error "Invalid task id." unless task
unless task.user_id == key.user_id
yield_error "Invalid task id."
return task
class extends Application class extends Application
-- api_key AND text @before_filter =>
[new: "/new"]: capture_errors_json => settings.load!
json_params => registry.before_filter(@)
key = get_key(@)
yield_error "Task text not specified." unless @params.text and @params.text\len! > 0
task = assert_error Tasks\create { -- layout: "layout"
user_id: key.user_id @include locate "users"
text: @params.text @include locate "api"
}
return json: { success: true, :task } [index: "/"]: =>
if @user
@keys = Keys\find user_id: @user.id
@tasks = Tasks\find user_id: @user.id -- TODO convert to paginated
-- api_key AND id unless #@keys > 0
[do: "/do"]: capture_errors_json => table.insert @keys, Keys\create user_id: @user.id
json_params =>
task = get_task(@)
task = assert_error task\update { done: true }
return json: { success: true, :task }
-- api_key AND id return render: "index.logged_in"
[undo: "/undo"]: capture_errors_json =>
json_params =>
task = get_task(@)
task = assert_error task\update { done: false }
return json: { success: true, :task }
-- api_key AND (id OR (done true/false/nil AND/OR page))
[fetch: "/fetch"]: capture_errors_json =>
json_params =>
if @params.id
task = get_task(@)
return json: { success: true, :task }
else else
key = get_key(@) return redirect_to: @url_for "user_login"
page = tonumber(@params.page) or 1 -- TODO
-- return render: "index.logged_out"
local paginator -- [generate_api_key: "/generate_api_key"]: =>
if @params.done != nil -- if @user
paginator = Tasks\paginated "WHERE user_id = ? AND done = ? ORDER BY id ASC", key.user_id, @params.done, per_page: 50 -- if key = Keys\create user_id: @user.id
else -- return json: { success: true, :key }
paginator = Tasks\paginated "WHERE user_id = ? ORDER BY id ASC", key.user_id, per_page: 50
tasks = paginator\get_page page
return json: { success: true, :tasks }
-- api_key AND done true/false/nil
[random: "/fetch/random"]: capture_errors_json =>
json_params =>
key = get_key(@)
local tasks
if @params.done
offset = random Tasks\count "user_id = ? AND done = ? ORDER BY id ASC", key.user_id, @params.done
tasks = Tasks\select "WHERE user_id = ? AND done = ? ORDER BY id ASC OFFSET ? LIMIT 1", key.user_id, @params.done, offset
else
offset = random Tasks\count "user_id = ? ORDER BY id ASC", key.user_id
tasks = Tasks\select "WHERE user_id = ? ORDER BY id ASC OFFSET ? LIMIT 1", key.user_id, offset
if tasks and #tasks == 1
return json: { success: true, task: tasks[1] }
else
return status: 500, json: { errors: "No task matches query." }
-- api_key AND done true/false/nil AND/OR case true
[search: "/search"]: capture_errors_json =>
json_params =>
key = get_key(@)
like = @params.case and "ILIKE" or "LIKE"
local tasks
if @params.done
tasks = Tasks\select "WHERE user_id = ? AND done = ? AND text #{like} ? ORDER BY id ASC", key.user_id, @params.done, escape_similar_to @params.text
else
tasks = Tasks\select "WHERE user_id = ? AND text #{like} ? ORDER BY id ASC", key.user_id, escape_similar_to @params.text
if tasks and #tasks == 1
return json: { success: true, task: tasks[1] }
else
return status: 500, json: { errors: "No task matches query." }

121
applications/api.moon Normal file
View File

@ -0,0 +1,121 @@
import Application from require "lapis"
import json_params, capture_errors_json, yield_error, assert_error from require "lapis.application"
import assert_valid from require "lapis.validate"
import Keys, Tasks from require "models"
import locate from require "locator"
import random from locate "calc"
import escape_similar_to from locate "db"
standard_err = ->
return status: 500, json: { errors: {"No task matches query."} }
get_key = =>
yield_error "api_key not specified." unless @params.api_key and @params.api_key\len! > 0
if key = Keys\find uuid: @params.api_key
return key
else
yield_error "Invalid api_key."
get_task = =>
assert_valid @params, {
{"id", exists: true, "Task id not specified."}
{"id", is_integer: true, "Task id is invalid."}
}
key = get_key(@)
task = Tasks\find id: @params.id
yield_error "Invalid task id." unless task
unless task.user_id == key.user_id
yield_error "Invalid task id."
return task
class extends Application
-- api_key AND text
[new: "/new"]: capture_errors_json =>
json_params =>
key = get_key(@)
yield_error "Task text not specified." unless @params.text and @params.text\len! > 0
task = assert_error Tasks\create {
user_id: key.user_id
text: @params.text
}
return json: { success: true, :task }
-- api_key AND id
[do: "/do"]: capture_errors_json =>
json_params =>
if task = get_task(@)
task = assert_error task\update { done: true }
return json: { success: true, :task }
else
return standard_err!
-- api_key AND id
[undo: "/undo"]: capture_errors_json =>
json_params =>
if task = get_task(@)
task = assert_error task\update { done: false }
return json: { success: true, :task }
else
return standard_err!
-- api_key AND (id OR (done true/false/nil AND/OR page))
[fetch: "/fetch"]: capture_errors_json =>
json_params =>
if @params.id
if task = get_task(@)
return json: { success: true, :task }
else
return standard_err!
else
key = get_key(@)
page = tonumber(@params.page) or 1
local paginator
if @params.done != nil
paginator = Tasks\paginated "WHERE user_id = ? AND done = ? ORDER BY id ASC", key.user_id, @params.done, per_page: 50
else
paginator = Tasks\paginated "WHERE user_id = ? ORDER BY id ASC", key.user_id, per_page: 50
tasks = paginator\get_page page
return json: { success: true, :tasks }
-- api_key AND done true/false/nil
[random: "/fetch/random"]: capture_errors_json =>
json_params =>
key = get_key(@)
local tasks
if @params.done
offset = random Tasks\count "user_id = ? AND done = ? ORDER BY id ASC", key.user_id, @params.done
tasks = Tasks\select "WHERE user_id = ? AND done = ? ORDER BY id ASC OFFSET ? LIMIT 1", key.user_id, @params.done, offset
else
offset = random Tasks\count "user_id = ? ORDER BY id ASC", key.user_id
tasks = Tasks\select "WHERE user_id = ? ORDER BY id ASC OFFSET ? LIMIT 1", key.user_id, offset
if tasks and #tasks == 1
return json: { success: true, task: tasks[1] }
else
return standard_err!
-- api_key AND done true/false/nil AND/OR case true
[search: "/search"]: capture_errors_json =>
json_params =>
key = get_key(@)
like = @params.case and "ILIKE" or "LIKE"
local tasks
if @params.done
tasks = Tasks\select "WHERE user_id = ? AND done = ? AND text #{like} ? ORDER BY id ASC", key.user_id, @params.done, escape_similar_to @params.text
else
tasks = Tasks\select "WHERE user_id = ? AND text #{like} ? ORDER BY id ASC", key.user_id, escape_similar_to @params.text
if tasks and #tasks >= 1
return json: { success: true, :tasks }
else
return standard_err!

25
config.moon Normal file
View File

@ -0,0 +1,25 @@
config = require "lapis.config"
import autoload from require "locator"
import sql_password, session_secret from autoload "secret"
config {"production", "development"}, ->
session_name "simplex"
secret session_secret
postgres ->
host "127.0.0.1"
user "postgres"
password sql_password
config "production", ->
postgres ->
database "simplex"
num_workers 4
code_cache "on"
port 8251
config "development", ->
postgres ->
database "dev.simplex"
num_workers 2
code_cache "off"
port 8250

View File

@ -6,6 +6,9 @@
fetch: "https://github.com/lazuscripts/users" fetch: "https://github.com/lazuscripts/users"
} }
} }
{
path: "applications"
}
{ {
path: "utility" path: "utility"
remote: { remote: {

View File

@ -20,4 +20,10 @@ make_migrations {
{"created_at", types.time} {"created_at", types.time}
{"updated_at", types.time} {"updated_at", types.time}
} }
create_index "keys", "user_id"
create_index "keys", "uuid"
create_index "tasks", "id"
create_index "tasks", "user_id"
create_index "tasks", "user_id", "done"
} }

44
static/index.js Normal file
View File

@ -0,0 +1,44 @@
function request(url) {
var xhr = new XMLHttpRequest();
xhr.open("POST", url, true);
xhr.setRequestHeader("Content-Type", "application/json");
return xhr;
}
function check(id) {
var checkbox = document.getElementById("task-"+id);
if (checkbox.checked) {
var xhr = request("/do");
xhr.onreadystatechange = function() {
if (xhr.readyState === 4) {
// TODO handle success / errors
console.log(xhr.responseText);
}
}
xhr.send(JSON.stringify({api_key: API_KEY, id: id}));
} else {
var xhr = request("/undo");
xhr.onreadystatechange = function() {
if (xhr.readyState === 4) {
// TODO handle success / errors
console.log(xhr.responseText);
}
}
xhr.send(JSON.stringify({api_key: API_KEY, id: id}));
}
}
function new() {
var text = document.getElementById("new-task");
console.log(text); // TEMPORARY
var xhr = request("/new");
xhr.onreadystatechange = function() {
if (xhr.readyState === 4) {
// TODO handle success / errors
console.log(xhr.responseText);
}
}
xhr.send(JSON.stringify({api_key: API_KEY, text: text.value}));
return false; // prevent form submission
}

View File

@ -0,0 +1,25 @@
import Widget from require "lapis.html"
class extends Widget
content: =>
script -> raw "var API_KEY = '#{@keys[1].uuid}';"
script src: "/static/index.js"
p "API Keys:"
ul ->
for key in *@keys
li key.uuid
-- li ->
-- a onclick: "new_key()"
p "Tasks:"
ul ->
for task in *@tasks
li ->
input type: "checkbox", id: "task-#{task.id}", onchange: "check(#{task.id})" checked: task.done
text " #{task.text}"
li ->
form {
onsubmit: "new()"
}, ->
input type: "text", id: "new-task", placeholder: "new task"
input type: "submit", value: "add task"