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 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"
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
import autoload, locate, registry from require "locator"
import settings from autoload "utility"
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
@before_filter =>
settings.load!
registry.before_filter(@)
task = assert_error Tasks\create {
user_id: key.user_id
text: @params.text
}
-- layout: "layout"
@include locate "users"
@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
[do: "/do"]: capture_errors_json =>
json_params =>
task = get_task(@)
task = assert_error task\update { done: true }
return json: { success: true, :task }
unless #@keys > 0
table.insert @keys, Keys\create user_id: @user.id
-- api_key AND id
[undo: "/undo"]: capture_errors_json =>
json_params =>
task = get_task(@)
task = assert_error task\update { done: false }
return json: { success: true, :task }
return render: "index.logged_in"
-- 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
key = get_key(@)
page = tonumber(@params.page) or 1
return redirect_to: @url_for "user_login"
-- TODO
-- return render: "index.logged_out"
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 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." }
-- [generate_api_key: "/generate_api_key"]: =>
-- if @user
-- if key = Keys\create user_id: @user.id
-- return json: { success: true, :key }

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"
}
}
{
path: "applications"
}
{
path: "utility"
remote: {

View File

@ -20,4 +20,10 @@ make_migrations {
{"created_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"