Compare commits
10 Commits
8333b3d1f0
...
c28c4a00b7
Author | SHA1 | Date | |
---|---|---|---|
|
c28c4a00b7 | ||
|
0433e71560 | ||
|
73ce07dc01 | ||
|
1968f5e88e | ||
|
8463fc218d | ||
|
f2b05fde71 | ||
|
87cf00673c | ||
|
695306a242 | ||
|
d859a94280 | ||
|
44e7a33d7d |
45
api notes
Normal file
45
api notes
Normal file
@ -0,0 +1,45 @@
|
||||
/random/:id ?
|
||||
- id specified for random is currently undefined, but will be used to get a random from a list id/name
|
||||
|
||||
/list/:page
|
||||
- id specified for list is currently undefined, but will be used to get via list ids/names
|
||||
|
||||
---- new stuff to do with multiple lists:
|
||||
|
||||
lists {
|
||||
id: serial
|
||||
user_id: user this belongs to!
|
||||
parent_id: another list, optional
|
||||
name: when generated, make a slug, if slug is not unique, append a number and try again (incrementing number until a new unique slug is found)
|
||||
slug: based on name, uniqueness required (enforced behind the scenes by name, unless explicitly given (in which case, must meet constraints and not exist already))
|
||||
timestamp
|
||||
}
|
||||
|
||||
tasks -> {
|
||||
list_id: optional foreign key
|
||||
parent_id: optional foreign key (to a task!)
|
||||
}
|
||||
|
||||
|
||||
/new -> option to add list_id or parent_id or parent_content or list_name
|
||||
/edit -> option to add / remove same things
|
||||
/list -> option to only select from same things
|
||||
- deprecate /list and use /get for its options!
|
||||
/random -> option to only select from same things
|
||||
/get -> option to get from list / parent via id/content/name
|
||||
|
||||
/list/new/:name -> create a list
|
||||
/list/get/:nameORslugORid -> get a list
|
||||
/list/do/:nameORslugORid -> mark everything on a list done (alternately, lists themselves can have seperate done values!!)
|
||||
/list/undo/:nameORslugORid ->
|
||||
/list/edit/:nameORslugORid ->
|
||||
/list/delete/:nameORslugORid -> all tasks are deleted or are removed from list to either its parent, or no list (depending on options sent)
|
||||
|
||||
/list/parent -> get parent list
|
||||
/list/children -> get children lists
|
||||
|
||||
/parent -> get parent task
|
||||
/children -> get children tasks
|
||||
|
||||
|
||||
/list(/:id_or_slug)(/:page) --- ?
|
1
app.moon
1
app.moon
@ -12,6 +12,7 @@ class Simplex extends Application
|
||||
|
||||
layout: main
|
||||
|
||||
@include locate "githook"
|
||||
@include locate "users"
|
||||
@include locate "api"
|
||||
@include locate "docs"
|
||||
|
@ -4,7 +4,7 @@ import unescape from require "lapis.util"
|
||||
|
||||
import APIKeys, Users, Tasks from require "models"
|
||||
import locate from require "locator"
|
||||
import api_request, abort, assert_model from locate "helpers.api"
|
||||
import request, abort, assert_model from locate "helpers.api"
|
||||
-- import random from locate "calc"
|
||||
-- import escape_similar_to from locate "db"
|
||||
|
||||
@ -43,7 +43,7 @@ class API extends Application
|
||||
@path: "/v1"
|
||||
@name: "api_"
|
||||
|
||||
@before_filter( api_request =>
|
||||
@before_filter( request =>
|
||||
return if @user
|
||||
if auth = @req.headers["authorization"]
|
||||
if auth\len! > 0
|
||||
@ -55,7 +55,7 @@ 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!)
|
||||
)
|
||||
|
||||
[action: "/:action(/:id)"]: api_request =>
|
||||
[action: "/:action(/:id)"]: request =>
|
||||
switch @params.action
|
||||
when "new"
|
||||
unless @params.content or tonumber @params.id
|
||||
@ -89,7 +89,7 @@ class API extends Application
|
||||
|
||||
|
||||
|
||||
[list: "/list"]: api_request =>
|
||||
[list: "/list"]: request =>
|
||||
assert_valid @params, {
|
||||
{"count", exists: true, is_integer: true, optional: true, "Count is not an integer."}
|
||||
{"done", exists: true, one_of: {true, false}, optional: true, "Done is not a boolean."}
|
||||
@ -120,7 +120,7 @@ class API extends Application
|
||||
|
||||
|
||||
|
||||
[random: "/random"]: api_request =>
|
||||
[random: "/random"]: request =>
|
||||
-- assert_valid @params, {
|
||||
-- {"count", exists: true, is_integer: true, optional: true, "Count is not an integer."}
|
||||
-- {"done", exists: true, one_of: {true, false}, optional: true, "Done is not a boolean."}
|
||||
@ -146,11 +146,11 @@ class API extends Application
|
||||
-- else
|
||||
-- abort!
|
||||
|
||||
[new_key: "/key/new"]: api_request =>
|
||||
[new_key: "/key/new"]: request =>
|
||||
api_key = assert_model APIKeys\create(@user)
|
||||
return json: { success: true, :api_key }
|
||||
|
||||
[delete_key: "/key/delete(/:key)"]: api_request =>
|
||||
[delete_key: "/key/delete(/:key)"]: request =>
|
||||
if @params.id
|
||||
abort "api_key IDs do not exist anymore (sorry!)." -- no one should ever run into this
|
||||
elseif @params.key
|
||||
|
1
applications/githook/.gitignore
vendored
Normal file
1
applications/githook/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
*.lua
|
21
applications/githook/LICENSE
Normal file
21
applications/githook/LICENSE
Normal file
@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016-2018 Paul Liverman III
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
55
applications/githook/ReadMe.md
Normal file
55
applications/githook/ReadMe.md
Normal file
@ -0,0 +1,55 @@
|
||||
## Installation
|
||||
|
||||
(Note: I'm going to rewrite this to explain how to use with locator, a simple
|
||||
server locator I designed for use with Lapis and these sub-applications.)
|
||||
|
||||
Dependencies:
|
||||
|
||||
- Lapis (duh)
|
||||
- MoonScript
|
||||
- OpenResty user needs a bash shell (ch -s /bin/bash user)
|
||||
|
||||
From the shell:
|
||||
|
||||
```bash
|
||||
git subtree add --prefix githook https://github.com/lazuscripts/githook.git master --squash
|
||||
```
|
||||
|
||||
(`--prefix` specifies where it will be saved.)
|
||||
|
||||
Alternately, you can add it as a remote for easier maintenance:
|
||||
|
||||
```bash
|
||||
git remote add -f githook https://github.com/lazuscripts/githook.git
|
||||
git subtree add --prefix githook githook master --squash
|
||||
```
|
||||
|
||||
From your main application class: `@include "githook.githook"` (or wherever you put it)
|
||||
|
||||
### Updating
|
||||
|
||||
From the shell:
|
||||
|
||||
```bash
|
||||
git subtree pull --prefix githook https://github.com/lazuscripts/githook.git master --squash
|
||||
```
|
||||
|
||||
Or, if it is set up as remote:
|
||||
|
||||
```bash
|
||||
git subtree pull --prefix githook githook master --squash
|
||||
```
|
||||
|
||||
## Config
|
||||
|
||||
All configuration is optional. Without configuration, will attempt to update any
|
||||
time it is visited.
|
||||
|
||||
- `githook_branch "branch"` which branch you want updating (as string)
|
||||
(to prevent updates triggering when pushing unrelated branches)
|
||||
- `githook_secret "secret"` the secret string used on GitHub
|
||||
|
||||
Will attempt to checkout, pull, update submodules if needed, compile all code,
|
||||
then run migrations, and finally update the running server without interruption.
|
||||
|
||||
Returns a log along with exit codes on success or failure.
|
152
applications/githook/githook.moon
Normal file
152
applications/githook/githook.moon
Normal file
@ -0,0 +1,152 @@
|
||||
lapis = require "lapis"
|
||||
config = require("lapis.config").get!
|
||||
|
||||
import respond_to, json_params from require "lapis.application"
|
||||
import hmac_sha1, hmac_sha256 from require "lapis.util.encoding"
|
||||
import encode from require "cjson"
|
||||
import GithookLogs from require "models"
|
||||
import locate, autoload, registry from require "locator"
|
||||
import settings from autoload "utility"
|
||||
import execute from locate "utility.shell"
|
||||
import insert, concat from table
|
||||
|
||||
const_compare = (string1, string2) ->
|
||||
local fail, dummy
|
||||
|
||||
for i = 1, math.max #string1, #string2, 100
|
||||
if string1\sub(i,i) ~= string2\sub(i,i)
|
||||
fail = true
|
||||
else
|
||||
dummy = true -- attempting to make execution time equal
|
||||
|
||||
return not fail
|
||||
|
||||
hex_dump = (str) ->
|
||||
len = string.len str
|
||||
hex = ""
|
||||
|
||||
for i = 1, len
|
||||
hex ..= string.format( "%02x", string.byte( str, i ) )
|
||||
|
||||
return hex
|
||||
|
||||
run_update = (branch) ->
|
||||
exit_codes, logs = {}, {}
|
||||
failure = false
|
||||
|
||||
commands = registry.githook_commands branch, config._name
|
||||
unless commands
|
||||
commands = {
|
||||
{"git checkout #{branch} 2> /dev/stdout"}
|
||||
{"git pull origin 2> /dev/stdout"}
|
||||
{"git submodule init 2> /dev/stdout"}
|
||||
{"git submodule update 2> /dev/stdout"}
|
||||
{"code=0\nfor file in $(find . -type f -name \"*.moon\"); do moonc \"$file\" 2> /dev/stdout\ntmp=$?\nif [ ! $tmp -eq 0 ]; then code=$tmp\nfi; done\necho $code", false}
|
||||
{"lapis migrate #{config._name} 2> /dev/stdout"}
|
||||
{"lapis build #{config._name} 2> /dev/stdout"}
|
||||
}
|
||||
for cmd in *commands
|
||||
code, output = execute unpack cmd
|
||||
insert exit_codes, code
|
||||
insert logs, cmd[1]
|
||||
insert logs, " #{output\gsub "\n", "\n "}"
|
||||
if code != 0
|
||||
failure = true
|
||||
break
|
||||
|
||||
log = concat logs, "\n"
|
||||
|
||||
if failure
|
||||
if settings["githook.save_logs"]
|
||||
GithookLogs\create {
|
||||
success: false
|
||||
exit_codes: encode exit_codes
|
||||
:log
|
||||
}
|
||||
return status: 500, json: {
|
||||
status: "failure"
|
||||
message: "a subprocess returned a non-zero exit code"
|
||||
:log
|
||||
:exit_codes
|
||||
}
|
||||
else
|
||||
if settings["githook.save_logs"] and settings["githook.save_on_success"]
|
||||
GithookLogs\create {
|
||||
exit_codes: encode exit_codes
|
||||
:log
|
||||
}
|
||||
elseif settings["githook.save_logs"]
|
||||
GithookLogs\create! -- we still record WHEN there was a success
|
||||
return status: 200, json: {
|
||||
status: "success"
|
||||
message: "server updated to latest version of '#{branch}'"
|
||||
:log
|
||||
:exit_codes
|
||||
}
|
||||
|
||||
ignored = (branch) ->
|
||||
return status: 200, json: {
|
||||
status: "success"
|
||||
message: "ignored push (looking for updates to '#{branch}')"
|
||||
}
|
||||
|
||||
unauthorized = ->
|
||||
return status: 401, json: {
|
||||
status: "unauthorized",
|
||||
message: "invalid credentials or no credentials were sent"
|
||||
}
|
||||
|
||||
invalid = (reason) ->
|
||||
return status: 400, json: {
|
||||
status: "invalid request"
|
||||
message: reason
|
||||
}
|
||||
|
||||
class extends lapis.Application
|
||||
[githook: "/githook"]: respond_to {
|
||||
before: =>
|
||||
@branch = config.githook_branch or settings["githook.branch"] or "master"
|
||||
|
||||
GET: =>
|
||||
unless settings["githook.allow_get"]
|
||||
return status: 405, json: {
|
||||
status: "method not allowed",
|
||||
message: "Githook is not accepting GET requests."
|
||||
}
|
||||
|
||||
unless settings["githook.run_without_auth"]
|
||||
return unauthorized!
|
||||
|
||||
@results = run_update(@branch)
|
||||
return render: locate "views.githook_get"
|
||||
|
||||
POST: json_params =>
|
||||
secret = config.githook_secret or settings["githook.secret"]
|
||||
if secret
|
||||
ngx.req.read_body!
|
||||
if body = ngx.req.get_body_data!
|
||||
local authorized
|
||||
if github_hash = @req.headers["X-Hub-Signature"]
|
||||
authorized = const_compare "sha1=#{hex_dump hmac_sha1 secret, body}", github_hash
|
||||
elseif gogs_hash = @req.headers["X-Gogs-Signature"]
|
||||
authorized = const_compare gogs_hash, hex_dump hmac_sha256 secret, body
|
||||
elseif @params.secret
|
||||
authorized = const_compare @params.secret, secret
|
||||
unless authorized
|
||||
return unauthorized!
|
||||
if @params.ref == "refs/heads/#{@branch}"
|
||||
return run_update(@branch)
|
||||
elseif @params.ref == nil
|
||||
return invalid "'ref' not defined in request body"
|
||||
else
|
||||
return ignored(@branch)
|
||||
else
|
||||
return invalid "no request body"
|
||||
elseif settings["githook.run_without_auth"]
|
||||
if @params.ref == "refs/heads/#{@branch}"
|
||||
return run_update(@branch)
|
||||
else
|
||||
return ignored(@branch)
|
||||
else
|
||||
return unauthorized!
|
||||
}
|
25
applications/githook/migrations.moon
Normal file
25
applications/githook/migrations.moon
Normal file
@ -0,0 +1,25 @@
|
||||
import create_table, types, create_index from require "lapis.db.schema"
|
||||
|
||||
import autoload from require "locator"
|
||||
import settings from autoload "utility"
|
||||
|
||||
{
|
||||
[1519992142]: =>
|
||||
create_table "githook_logs", {
|
||||
{"id", types.serial primary_key: true}
|
||||
{"success", types.boolean default: true}
|
||||
{"exit_codes", types.text null: true}
|
||||
{"log", types.text null: true}
|
||||
|
||||
{"created_at", types.time}
|
||||
{"updated_at", types.time}
|
||||
}
|
||||
create_index "githook_logs", "id", unique: true
|
||||
create_index "githook_logs", "success"
|
||||
settings["githook.save_logs"] = true
|
||||
settings["githook.save_on_success"] = true
|
||||
settings["githook.allow_get"] = true
|
||||
settings["githook.run_without_auth"] = false
|
||||
-- settings["githook.branch"] = "master"
|
||||
settings.save!
|
||||
}
|
4
applications/githook/models/GithookLogs.moon
Normal file
4
applications/githook/models/GithookLogs.moon
Normal file
@ -0,0 +1,4 @@
|
||||
import Model from require "lapis.db.model"
|
||||
|
||||
class GithookLogs extends Model
|
||||
@timestamp: true
|
10
applications/githook/views/githook_get.moon
Normal file
10
applications/githook/views/githook_get.moon
Normal file
@ -0,0 +1,10 @@
|
||||
import Widget from require "lapis.html"
|
||||
|
||||
class extends Widget
|
||||
content: =>
|
||||
h2 "#{@results.json.status\sub(1, 1)\upper!}#{@results.json.status\sub 2}"
|
||||
element "table", ->
|
||||
tr ->
|
||||
for code in *@results.json.exit_codes
|
||||
th code
|
||||
pre @results.json.log
|
@ -2,7 +2,7 @@ import json_params, capture_errors, yield_error from require "lapis.application"
|
||||
import insert, remove from table
|
||||
import max from math
|
||||
|
||||
api_request = (fn) ->
|
||||
request = (fn) ->
|
||||
json_params capture_errors {
|
||||
fn,
|
||||
on_error: =>
|
||||
@ -28,7 +28,7 @@ assert_model = (result, err) ->
|
||||
return result
|
||||
|
||||
{
|
||||
:api_request
|
||||
:request
|
||||
:abort
|
||||
:assert_model
|
||||
}
|
||||
|
@ -20,7 +20,7 @@ class extends Widget
|
||||
link rel: "stylesheet", href: "/static/main.css"
|
||||
body ->
|
||||
div class: "container", ->
|
||||
h1(@title or "Simplex")
|
||||
h1(@title or "Simplex Task Manager")
|
||||
div class: "row", ->
|
||||
div class: "column btns", ->
|
||||
if @user
|
||||
|
@ -6,12 +6,19 @@
|
||||
fetch: "https://github.com/lazuscripts/users"
|
||||
}
|
||||
}
|
||||
{
|
||||
path: "applications.githook"
|
||||
remote: {
|
||||
name: "githook"
|
||||
fetch: "https://github.com/lazuscripts/githook"
|
||||
}
|
||||
}
|
||||
{
|
||||
path: "applications"
|
||||
}
|
||||
-- { -- not actually useful
|
||||
-- path: "helpers"
|
||||
-- }
|
||||
-- } -- NOTE also to be deprecated by the version added to utility
|
||||
{
|
||||
path: "utility"
|
||||
remote: {
|
||||
|
@ -2,11 +2,23 @@ import Widget from require "lapis.html"
|
||||
|
||||
class LoggedOut extends Widget
|
||||
content: =>
|
||||
p "This introduction will be written soon(TM)."
|
||||
p ->
|
||||
text "For now, forward any questions or ideas to "
|
||||
text "Simplex is a task manager designed to be as flexible as possible. Organize your tasks the way you want to, instead of conforming to someone else's idea. Right now, Simplex offers a minimal web interface, and "
|
||||
a href: @url_for("docs_index"), "extensive API documentation"
|
||||
text ". It is developed by making the easiest to use API first, and then building a website to utilize its functionality."
|
||||
|
||||
p ->
|
||||
text "Forward any questions or ideas to "
|
||||
a href: "https://twitter.com/Guard13007", "@Guard13007"
|
||||
text " on Twitter."
|
||||
p ->
|
||||
text "Or email me: "
|
||||
text " on Twitter. Or email me: "
|
||||
a href: "mailto:paul.liverman.iii@gmail.com", "paul.liverman.iii@gmail.com"
|
||||
|
||||
hr!
|
||||
|
||||
p "The ultimate goal of Simplex is a task manager anyone can use, and only costing $1.50/year to garuntee the servers remain working. So affordable, even a broke college student could pay for it."
|
||||
|
||||
p "Next features to be implemented:"
|
||||
ul ->
|
||||
li "Multiple task lists."
|
||||
li "Duplicating tasks and lists."
|
||||
li "Optional hierarchical structure for lists and tasks."
|
||||
|
Loading…
Reference in New Issue
Block a user