aboutsummaryrefslogtreecommitdiff
path: root/src/guff/api
diff options
context:
space:
mode:
Diffstat (limited to 'src/guff/api')
-rw-r--r--src/guff/api/content-type.cr10
-rw-r--r--src/guff/api/dir.cr23
-rw-r--r--src/guff/api/file.cr23
-rw-r--r--src/guff/api/methods.cr366
-rw-r--r--src/guff/api/post.cr80
-rw-r--r--src/guff/api/site.cr39
-rw-r--r--src/guff/api/tag.cr21
-rw-r--r--src/guff/api/test.cr28
-rw-r--r--src/guff/api/util.cr31
9 files changed, 621 insertions, 0 deletions
diff --git a/src/guff/api/content-type.cr b/src/guff/api/content-type.cr
new file mode 100644
index 0000000..589e6b0
--- /dev/null
+++ b/src/guff/api/content-type.cr
@@ -0,0 +1,10 @@
+module Guff::API::ContentType
+ CONTENT_TYPES = {
+ "development": "text/html; charset=utf-8",
+ "production": "application/json; charset=utf8",
+ }
+
+ private def get_content_type
+ CONTENT_TYPES[@models.config["environment"]]
+ end
+end
diff --git a/src/guff/api/dir.cr b/src/guff/api/dir.cr
new file mode 100644
index 0000000..9b3779e
--- /dev/null
+++ b/src/guff/api/dir.cr
@@ -0,0 +1,23 @@
+require "json"
+
+module Guff
+ module API
+ module DirAPI
+ private def do_dir_add(
+ context : HTTP::Server::Context,
+ args : Hash(String, String)
+ )
+ # TODO
+ {ok: true}.to_json
+ end
+
+ private def do_dir_remove(
+ context : HTTP::Server::Context,
+ args : Hash(String, String)
+ )
+ # TODO
+ {ok: true}.to_json
+ end
+ end
+ end
+end
diff --git a/src/guff/api/file.cr b/src/guff/api/file.cr
new file mode 100644
index 0000000..353de9d
--- /dev/null
+++ b/src/guff/api/file.cr
@@ -0,0 +1,23 @@
+require "json"
+
+module Guff
+ module API
+ module FileAPI
+ private def do_file_add(
+ context : HTTP::Server::Context,
+ args : Hash(String, String)
+ )
+ # TODO
+ {ok: true}.to_json
+ end
+
+ private def do_file_remove(
+ context : HTTP::Server::Context,
+ args : Hash(String, String)
+ )
+ # TODO
+ {ok: true}.to_json
+ end
+ end
+ end
+end
diff --git a/src/guff/api/methods.cr b/src/guff/api/methods.cr
new file mode 100644
index 0000000..758cca9
--- /dev/null
+++ b/src/guff/api/methods.cr
@@ -0,0 +1,366 @@
+require "json"
+
+module Guff
+ module API
+ module Methods
+ METHODS = {
+ "post": {
+ "get_posts": {
+ text: "Get posts matching query.",
+
+ args: {
+ "q": {
+ text: "Search string.",
+ type: :text,
+ required: false,
+ default: "",
+ },
+
+ "page": {
+ text: "Page number",
+ type: :int,
+ required: false,
+ default: "1",
+ },
+
+ "tags": {
+ text: "Comma-separated list of tags (union)",
+ # type: :tag_list,
+ type: :json,
+ required: false,
+ default: "",
+ },
+
+ "sort": {
+ text: "Sort order of results",
+ type: :sort,
+ required: false,
+ default: "date,desc",
+ },
+
+ "cols": {
+ text: "Column list",
+ type: :text,
+ required: false,
+ },
+ },
+ },
+
+ "add_post": {
+ text: "Create new post.",
+ args: {
+ "name": {
+ text: "Post title.",
+ type: :text,
+ required: true,
+ },
+
+ "slug": {
+ text: "Post slug.",
+ type: :slug,
+ required: true,
+ },
+
+ "body": {
+ text: "Post body.",
+ type: :text,
+ required: true,
+ },
+
+ "tags": {
+ text: "Post tags.",
+ # type: :tag_list,
+ type: :json,
+ required: false,
+ default: "",
+ },
+ },
+ },
+
+ "update_post": {
+ text: "Update existing post.",
+ args: {
+ "name": {
+ text: "Post title.",
+ type: :text,
+ required: false,
+ },
+
+ "slug": {
+ text: "Post slug.",
+ type: :slug,
+ required: false,
+ },
+
+ "body": {
+ text: "Post body.",
+ type: :text,
+ required: false,
+ },
+
+ "tags": {
+ text: "Post tags.",
+ type: :json,
+ required: false,
+ },
+
+ "posted": {
+ text: "Is this post posted?",
+ type: :bool,
+ required: false,
+ },
+ },
+ },
+
+ "remove_posts": {
+ text: "Remove existing posts.",
+
+ args: {
+ "post_ids": {
+ text: "Post IDs.",
+ type: :int_list,
+ required: false,
+ default: "",
+ },
+
+ "tags": {
+ text: "Post tags.",
+ # type: :tag_list,
+ type: :json,
+ required: false,
+ default: "",
+ },
+ },
+ },
+
+ "set_tags": {
+ text: "Set tags for posts.",
+
+ args: {
+ "post_ids": {
+ text: "Post IDs.",
+ type: :int_list,
+ required: true,
+ },
+ },
+ },
+ },
+
+ "dir": {
+ "add": {
+ text: "Create new directory",
+
+ args: {
+ "path": {
+ text: "Path to new directory",
+ type: :path,
+ required: true,
+ },
+ },
+ },
+
+ "remove": {
+ text: "Remove directory",
+
+ args: {
+ "path": {
+ text: "Path to existing directory",
+ type: :path,
+ required: true,
+ },
+ },
+ },
+ },
+
+ "file": {
+ "add": {
+ text: "Upload new file",
+
+ args: {
+ "path": {
+ text: "Destination file path",
+ type: :path,
+ required: true,
+ },
+ },
+ },
+
+ "remove": {
+ text: "Remove existing file",
+
+ args: {
+ "path": {
+ text: "Destination file path",
+ type: :path,
+ required: true,
+ },
+ },
+ },
+ },
+
+ "tag": {
+ "get_tags": {
+ text: "Get list of tags",
+ },
+
+ "remove_tags": {
+ text: "Remove set of tags",
+
+ args: {
+ "tags": {
+ text: "Tags to remove.",
+ # type: :tag_list,
+ type: :json,
+ required: false,
+ default: "",
+ },
+ },
+ },
+ },
+
+ "site": {
+ "add_site": {
+ text: "Create a new site",
+
+ args: {
+ "name": {
+ text: "Name of this site",
+ type: :text,
+ required: true,
+ },
+
+ "default": {
+ text: "Is this the default site?",
+ type: :bool,
+ required: false,
+ default: "f",
+ },
+
+ "domains": {
+ text: "Array of domain matches.",
+ type: :domain_list,
+ required: true,
+ },
+ },
+ },
+
+ "remove_sites": {
+ text: "Remove one or more existing sites",
+
+ args: {
+ "site_ids": {
+ text: "IDs of sites to remove",
+ type: :int_list,
+ required: true,
+ },
+ },
+ },
+
+ "set_default": {
+ text: "Set new default site",
+
+ args: {
+ "site_id": {
+ text: "ID of new default site",
+ type: :int,
+ required: true,
+ },
+ },
+ },
+
+ "set_domains": {
+ text: "Set domains for given site",
+
+ args: {
+ "site_id": {
+ text: "ID of site",
+ type: :int,
+ required: true,
+ },
+
+ "domains": {
+ text: "Domains for this site.",
+ type: :domain_list,
+ required: true,
+ },
+ },
+ },
+ },
+
+ "test": {
+ "version": {
+ text: "Get version",
+ },
+
+ "get_posts": {
+ text: "Test get posts",
+ },
+
+ "error": {
+ text: "Test error response",
+ },
+ }
+ }
+
+ TYPE_CHECKS = {
+ text: /.*/,
+ slug: /^[a-z0-9\.-]+$/,
+ int: /^\d+$/,
+ int_list: /^\d+(?:,\d+)*$/,
+ sort: /^[a-z0-9_]+,(?:asc|desc)$/,
+
+ # FIXME: lock these down more
+ json: /.*/,
+ path: /^[^\/].*[^\/]$/,
+ }
+
+ private def get_method_args(
+ params : HTTP::Params,
+ namespace : String,
+ method : String
+ )
+ return {} of String => String unless (
+ METHODS[namespace]? &&
+ METHODS[namespace][method] &&
+ METHODS[namespace][method][:args]?
+ )
+
+ # get method args
+ args = METHODS[namespace][method][:args] as \
+ Hash(String, Hash(Symbol, String | Symbol | Bool))
+
+ args.keys.reduce({} of String => String) do |r, arg_name|
+ arg_data = args[arg_name] as Hash(Symbol, String|Symbol|Bool)
+
+ # check for required parameter
+ if arg_data[:required] && !params.has_key?(arg_name)
+ raise "missing required parameter: %s" % [arg_name]
+ end
+
+ # get value
+ val = if arg_data[:required]
+ params.fetch(arg_name)
+ # elsif arg_data.has_key?(:default)
+ elsif arg_data[:default]?
+ params.fetch(arg_name, arg_data[:default] as String)
+ else
+ nil
+ end
+
+ if val
+ # check value
+ if !TYPE_CHECKS[arg_data[:type]].match(val)
+ raise "invalid parameter format: %s" % [arg_name]
+ end
+
+ # add value to result
+ r[arg_name] = val
+ end
+
+ # return result
+ r
+ end
+ end
+ end
+ end
+end
diff --git a/src/guff/api/post.cr b/src/guff/api/post.cr
new file mode 100644
index 0000000..0bc6377
--- /dev/null
+++ b/src/guff/api/post.cr
@@ -0,0 +1,80 @@
+require "json"
+
+module Guff
+ module API
+ module PostAPI
+ private def do_post_get_posts(
+ context : HTTP::Server::Context,
+ args : Hash(String, String)
+ )
+ @models.post.get_posts(
+ site_id: get_site(context),
+ q: args["q"]? || "",
+ tags: get_posts_tags(args["tags"]),
+ page: args.has_key?("page") ? args["page"].to_i : 1,
+ ).to_json
+ end
+
+ private def do_post_add_post(
+ context : HTTP::Server::Context,
+ args : Hash(String, String)
+ )
+ post_id = @models.post.add_post(
+ site_id: get_site(context),
+ slug: args["slug"],
+ name: args["name"],
+ body: args["body"],
+ tags: get_tags(args["tags"]?),
+ )
+
+ # return json
+ { post_id: post_id }.to_json
+ end
+
+ private def do_post_update_post(
+ context : HTTP::Server::Context,
+ args : Hash(String, String)
+ )
+ post_id = @models.post.update_post(
+ site_id: get_site(context),
+ post_id: args["post_id"].to_i,
+ slug: args["slug"]?,
+ name: args["name"],
+ body: args["body"],
+ tags: args.has_key?("tags") ? get_tags(args["tags"]?) : nil,
+ posted: args["posted"]?,
+ )
+
+ # return json
+ { ok: true }.to_json
+ end
+
+ private def do_post_remove_posts(
+ context : HTTP::Server::Context,
+ args : Hash(String, String)
+ )
+ @models.post.remove_posts(
+ site_id: get_site(context),
+ post_ids: args["post_ids"].split(',').map { |post_id|
+ post_id.to_s.to_i
+ },
+ )
+
+ { ok: true }.to_json
+ end
+
+ private def do_post_set_tags(
+ context : HTTP::Server::Context,
+ args : Hash(String, String)
+ )
+ @models.post.set_tags(
+ site_id: get_site(context),
+ post_id: (args["post_id"] as String).to_i,
+ tags: get_tags(args["tags"]?),
+ )
+
+ { ok: true}.to_json
+ end
+ end
+ end
+end
diff --git a/src/guff/api/site.cr b/src/guff/api/site.cr
new file mode 100644
index 0000000..b99f550
--- /dev/null
+++ b/src/guff/api/site.cr
@@ -0,0 +1,39 @@
+require "json"
+
+module Guff
+ module API
+ module SiteAPI
+ private def do_site_add_site(
+ context : HTTP::Server::Context,
+ args : Hash(String, String)
+ )
+ # TODO
+ {ok: true}.to_json
+ end
+
+ private def do_site_remove_sites(
+ context : HTTP::Server::Context,
+ args : Hash(String, String)
+ )
+ # TODO
+ {ok: true}.to_json
+ end
+
+ private def do_site_set_default(
+ context : HTTP::Server::Context,
+ args : Hash(String, String)
+ )
+ # TODO
+ {ok: true}.to_json
+ end
+
+ private def do_site_set_domains(
+ context : HTTP::Server::Context,
+ args : Hash(String, String)
+ )
+ # TODO
+ {ok: true}.to_json
+ end
+ end
+ end
+end
diff --git a/src/guff/api/tag.cr b/src/guff/api/tag.cr
new file mode 100644
index 0000000..e91fb60
--- /dev/null
+++ b/src/guff/api/tag.cr
@@ -0,0 +1,21 @@
+require "json"
+
+module Guff
+ module API
+ module TagAPI
+ private def do_tag_get_tags(
+ context : HTTP::Server::Context,
+ args : Hash(String, String)
+ )
+ [{foo: "bar"}, {foo: "asdf"}].to_json
+ end
+
+ private def do_tag_remove_tags(
+ context : HTTP::Server::Context,
+ args : Hash(String, String)
+ )
+ true.to_json
+ end
+ end
+ end
+end
diff --git a/src/guff/api/test.cr b/src/guff/api/test.cr
new file mode 100644
index 0000000..7549c11
--- /dev/null
+++ b/src/guff/api/test.cr
@@ -0,0 +1,28 @@
+require "json"
+
+module Guff
+ module API
+ module TestAPI
+ private def do_test_version(
+ context : HTTP::Server::Context,
+ args : Hash(String, String)
+ )
+ {version: Guff::VERSION}.to_json
+ end
+
+ private def do_test_get_posts(
+ context : HTTP::Server::Context,
+ args : Hash(String, String)
+ )
+ [{foo: "bar"}, {foo: "asdf"}].to_json
+ end
+
+ private def do_test_error(
+ context : HTTP::Server::Context,
+ args : Hash(String, String)
+ )
+ raise "some random error"
+ end
+ end
+ end
+end
diff --git a/src/guff/api/util.cr b/src/guff/api/util.cr
new file mode 100644
index 0000000..525f098
--- /dev/null
+++ b/src/guff/api/util.cr
@@ -0,0 +1,31 @@
+require "json"
+
+module Guff
+ module API
+ module Util
+ private def get_site(context : HTTP::Server::Context) : Int?
+ @models.site.to_site(context.request.headers["host"]?)
+ end
+
+ private def get_tags(
+ s : String?
+ ) : Array(String)
+ if s && s.size > 0
+ Array(String).from_json(s)
+ else
+ [] of String
+ end
+ end
+
+ private def get_posts_tags(
+ s : String?
+ ) : Array(Array(String))
+ if s && s.size > 0
+ Array(Array(String)).from_json(s)
+ else
+ [] of Array(String)
+ end
+ end
+ end
+ end
+end