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, }, "posted_year": { text: "Post date year filter", type: :int, required: false, }, "posted_month": { text: "Post date month filter", type: :int, required: false, }, "posted_day": { text: "Post date day filter", type: :int, required: false, }, "created_year": { text: "Creation date year filter", type: :int, required: false, }, "created_month": { text: "Creation date month filter", type: :int, required: false, }, "created_day": { text: "Creation date day filter", type: :int, required: false, }, "page": { text: "Page number", type: :int, required: false, default: "1", }, "tags": { text: "Comma-separated list of tags (union)", type: :json, required: false, }, "sort": { text: "Sort order of results", type: :json, required: false, }, "cols": { text: "Column list", type: :text, required: false, }, "slug": { text: "Post slug", type: :text, required: false, }, "state": { text: "Post state (draft, posted, deleted)", type: :state, required: false, default: "posted", }, }, }, "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, }, "state": { text: "Post state (draft, posted, deleted)", type: :state, required: false, default: "draft", }, }, }, "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, }, "state": { text: "Post state (draft, posted, deleted)", type: :state, 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", }, "get_users": { text: "Get mock list of users", }, "set_user": { text: "Set mock user", args: { "user_id": { text: "ID of user", type: :int, required: true, }, }, }, "add_user": { text: "Test add new user", args: { "name": { text: "Name of user", type: :text, required: true, }, "active": { text: "Is this user active?", type: :bool, required: false, }, "role": { text: "Role of user", type: :text, required: false, }, "email": { text: "Email address of user", type: :text, required: false, }, "password": { text: "Password of user", type: :text, required: false, }, }, }, "login": { text: "Test user login.", args: { "email": { text: "Email address of user", type: :text, required: true, }, "password": { text: "Password of user", type: :text, required: true, }, }, }, } } TYPE_CHECKS = { text: /.*/, slug: /^[a-z0-9\.-]+$/, int: /^\d+$/, int_list: /^\d+(?:,\d+)*$/, state: /^(?:draft|posted|deleted)$/, bool: /^t|f$/, # 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 = params.fetch(arg_name, arg_data[:default]?) as String? 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