mirror of
https://github.com/alexgo-io/stacks-puppet-node.git
synced 2026-05-25 00:33:20 +08:00
fixed /v1/search endpoint -- now it forwards to the searcher blueprint if enabled, or makes request to search.blockstack
This commit is contained in:
@@ -2,6 +2,9 @@
|
||||
|
||||
## Ping the node
|
||||
|
||||
#### grouping:
|
||||
Dashboard Endpoints
|
||||
|
||||
#### anchor_tag:
|
||||
node_ping
|
||||
|
||||
@@ -32,6 +35,12 @@ _end_
|
||||
|
||||
## Get name info
|
||||
|
||||
#### grouping:
|
||||
Naming API
|
||||
|
||||
#### subgrouping:
|
||||
Names
|
||||
|
||||
#### anchor_tag:
|
||||
naming_name_info
|
||||
|
||||
@@ -68,6 +77,12 @@ _end_
|
||||
|
||||
## Get name history
|
||||
|
||||
#### grouping:
|
||||
Naming API
|
||||
|
||||
#### subgrouping:
|
||||
Names
|
||||
|
||||
#### anchor_tag:
|
||||
naming_name_history
|
||||
|
||||
@@ -116,6 +131,12 @@ _end_
|
||||
|
||||
## Get names owned
|
||||
|
||||
#### grouping:
|
||||
Naming API
|
||||
|
||||
#### subgrouping:
|
||||
Names
|
||||
|
||||
#### anchor_tag:
|
||||
names_owned
|
||||
|
||||
@@ -148,6 +169,12 @@ _end_
|
||||
|
||||
## Get all namespaces
|
||||
|
||||
#### grouping:
|
||||
Naming API
|
||||
|
||||
#### subgrouping:
|
||||
Names
|
||||
|
||||
#### anchor_tag:
|
||||
namespaces_all
|
||||
|
||||
@@ -180,6 +207,12 @@ _end_
|
||||
|
||||
## Get name price
|
||||
|
||||
#### grouping:
|
||||
Naming API
|
||||
|
||||
#### subgrouping:
|
||||
Prices
|
||||
|
||||
#### anchor_tag:
|
||||
price_name
|
||||
|
||||
@@ -231,6 +264,12 @@ _end_
|
||||
|
||||
## Get consensus hash
|
||||
|
||||
#### grouping:
|
||||
Naming API
|
||||
|
||||
#### subgrouping:
|
||||
Blockchains
|
||||
|
||||
#### anchor_tag:
|
||||
blockchains_consensus
|
||||
|
||||
@@ -262,6 +301,12 @@ _end_
|
||||
|
||||
## Get profile
|
||||
|
||||
#### grouping:
|
||||
Identity API
|
||||
|
||||
#### subgrouping:
|
||||
Profiles
|
||||
|
||||
#### anchor_tag:
|
||||
identity_get
|
||||
|
||||
@@ -328,6 +373,12 @@ _end_
|
||||
|
||||
## Create profile
|
||||
|
||||
#### grouping:
|
||||
Identity API
|
||||
|
||||
#### subgrouping:
|
||||
Profiles
|
||||
|
||||
#### anchor_tag:
|
||||
identity_create
|
||||
|
||||
@@ -362,6 +413,12 @@ _end_
|
||||
|
||||
## Update profile
|
||||
|
||||
#### grouping:
|
||||
Identity API
|
||||
|
||||
#### subgrouping:
|
||||
Profiles
|
||||
|
||||
#### anchor_tag:
|
||||
identity_update
|
||||
|
||||
@@ -397,6 +454,12 @@ _end_
|
||||
|
||||
## Search users
|
||||
|
||||
#### grouping:
|
||||
Identity API
|
||||
|
||||
#### subgrouping:
|
||||
Profiles
|
||||
|
||||
#### anchor_tag:
|
||||
search_users
|
||||
|
||||
|
||||
@@ -28,9 +28,6 @@ import re
|
||||
|
||||
DEBUG = True
|
||||
|
||||
if(DEBUG):
|
||||
os.environ["BLOCKSTACK_DEBUG"] = "1"
|
||||
|
||||
DEFAULT_PORT = 5000
|
||||
DEFAULT_HOST = '0.0.0.0'
|
||||
|
||||
|
||||
@@ -26,7 +26,6 @@ This file is part of Blockstack Core.
|
||||
import re
|
||||
import json
|
||||
import collections
|
||||
import pylibmc
|
||||
import logging
|
||||
import xmlrpclib
|
||||
|
||||
@@ -46,11 +45,10 @@ from blockstack_zones import parse_zone_file
|
||||
|
||||
from blockstack_client.proxy import get_name_blockchain_record
|
||||
|
||||
from api.utils import cache_control
|
||||
from api.utils import cache_control, get_mc_client
|
||||
|
||||
from .config import DEBUG
|
||||
from .config import DEFAULT_HOST, MEMCACHED_SERVERS, MEMCACHED_USERNAME
|
||||
from .config import MEMCACHED_PASSWORD, MEMCACHED_TIMEOUT, MEMCACHED_ENABLED
|
||||
from .config import DEFAULT_HOST, MEMCACHED_TIMEOUT, MEMCACHED_ENABLED
|
||||
from .config import USERSTATS_TIMEOUT
|
||||
from .config import VALID_BLOCKS, RECENT_BLOCKS
|
||||
from .config import BLOCKSTACKD_IP, BLOCKSTACKD_PORT
|
||||
@@ -71,22 +69,8 @@ if DEBUG:
|
||||
else:
|
||||
log.setLevel(level=logging.INFO)
|
||||
|
||||
|
||||
def get_mc_client():
|
||||
""" Return a new connection to memcached
|
||||
"""
|
||||
|
||||
mc = pylibmc.Client(MEMCACHED_SERVERS, binary=True,
|
||||
username=MEMCACHED_USERNAME,
|
||||
password=MEMCACHED_PASSWORD,
|
||||
behaviors={"no_block": True,
|
||||
"connect_timeout": 200})
|
||||
|
||||
return mc
|
||||
|
||||
mc = get_mc_client()
|
||||
|
||||
|
||||
def validName(name):
|
||||
""" Return True if valid name
|
||||
"""
|
||||
|
||||
@@ -26,7 +26,6 @@ This file is part of Search.
|
||||
import sys
|
||||
import json
|
||||
import threading
|
||||
import pylibmc
|
||||
|
||||
from time import time
|
||||
from flask import request, jsonify, make_response, render_template, Blueprint
|
||||
@@ -44,7 +43,7 @@ from .attributes_index import search_proofs, validProofQuery
|
||||
|
||||
searcher = Blueprint('searcher', __name__, url_prefix='')
|
||||
|
||||
from api.resolver import get_mc_client
|
||||
from api.utils import get_mc_client
|
||||
|
||||
mc = get_mc_client()
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ from flask_crossdomain import crossdomain
|
||||
from .parameters import parameters_required
|
||||
from .utils import get_api_calls
|
||||
from .config import PUBLIC_NODE, PUBLIC_NODE_URL, BASE_API_URL
|
||||
from .config import SEARCH_NODE_URL
|
||||
from .config import SEARCH_NODE_URL, SEARCH_API_ENDPOINT_ENABLED
|
||||
|
||||
# hack around absolute paths
|
||||
current_dir = os.path.abspath(os.path.dirname(__file__))
|
||||
@@ -94,13 +94,17 @@ def api_names(name):
|
||||
@parameters_required(parameters=['query'])
|
||||
@crossdomain(origin='*')
|
||||
def search_people():
|
||||
query = request.values['query']
|
||||
|
||||
search_url = SEARCH_URL + '/search'
|
||||
if SEARCH_API_ENDPOINT_ENABLED:
|
||||
client = app.test_client()
|
||||
return client.get('/search?query={}'.format(query),
|
||||
headers=list(request.headers))
|
||||
|
||||
name = request.values['query']
|
||||
search_url = SEARCH_NODE_URL + '/search'
|
||||
|
||||
try:
|
||||
resp = requests.get(url=search_url, params={'query': name})
|
||||
resp = requests.get(url=search_url, params={'query': query})
|
||||
except (RequestsConnectionError, RequestsTimeout) as e:
|
||||
raise InternalProcessingError()
|
||||
|
||||
|
||||
@@ -159,6 +159,37 @@ class NamepriceTest(unittest.TestCase):
|
||||
self.assertIn('total_tx_fees', json_keys)
|
||||
self.assertIn('update_tx_fee', json_keys)
|
||||
|
||||
|
||||
class SearchAPITest(unittest.TestCase):
|
||||
def search_url(self, q):
|
||||
return "/v1/search?query={}".format(q)
|
||||
|
||||
def test_forward_to_search_server(self):
|
||||
u = "muneeb"
|
||||
original = api.config.SEARCH_API_ENDPOINT_ENABLED
|
||||
api.config.SEARCH_API_ENDPOINT_ENABLED = False
|
||||
|
||||
data = test_get_request(self, self.search_url(u),
|
||||
headers = {}, status_code=200)
|
||||
|
||||
self.assertTrue(len(data['results']) > 0)
|
||||
self.assertIn(u, data['results'][0]['username'])
|
||||
self.assertIn("profile", data['results'][0].keys())
|
||||
|
||||
api.config.SEARCH_API_ENDPOINT_ENABLED = original
|
||||
|
||||
def test_search_server(self):
|
||||
u = "muneeb"
|
||||
if not api.config.SEARCH_API_ENDPOINT_ENABLED:
|
||||
print "skipping search server test"
|
||||
return
|
||||
data = test_get_request(self, self.search_url(u),
|
||||
headers = {}, status_code=200)
|
||||
|
||||
self.assertTrue(len(data['results']) > 0)
|
||||
self.assertIn(u, data['results'][0]['username'])
|
||||
self.assertIn("profile", data['results'][0].keys())
|
||||
|
||||
class ConsensusTest(unittest.TestCase):
|
||||
def test_id_space(self):
|
||||
data = test_get_request(self, "/v1/blockchains/bitcoin/consensus",
|
||||
@@ -168,7 +199,7 @@ class ConsensusTest(unittest.TestCase):
|
||||
|
||||
def test_main(args = []):
|
||||
test_classes = [PingTest, LookupUsersTest, NamespaceTest, ConsensusTest,
|
||||
NamepriceTest, NamesOwnedTest, NameHistoryTest]
|
||||
NamepriceTest, NamesOwnedTest, NameHistoryTest, SearchAPITest]
|
||||
test_classes += [ResolverTestCase]
|
||||
if api.config.SEARCH_API_ENDPOINT_ENABLED:
|
||||
test_classes += [SearchTestCase]
|
||||
@@ -179,7 +210,10 @@ def test_main(args = []):
|
||||
|
||||
|
||||
with test_support.captured_stdout() as out:
|
||||
test_support.run_unittest(PingTest)
|
||||
try:
|
||||
test_support.run_unittest(PingTest)
|
||||
except Exception as e:
|
||||
print(e)
|
||||
out = out.getvalue()
|
||||
if out[-3:-1] != "OK":
|
||||
print(out)
|
||||
|
||||
64
api/utils.py
64
api/utils.py
@@ -26,9 +26,11 @@ This file is part of Blockstack Core.
|
||||
import re
|
||||
import json
|
||||
from .config import MAX_PROFILE_LIMIT
|
||||
from .config import MEMCACHED_ENABLED, MEMCACHED_SERVERS, MEMCACHED_USERNAME, MEMCACHED_PASSWORD
|
||||
|
||||
from flask import make_response
|
||||
from functools import wraps
|
||||
from collections import OrderedDict
|
||||
|
||||
def cache_control(timeout):
|
||||
def decorator(f):
|
||||
@@ -40,6 +42,22 @@ def cache_control(timeout):
|
||||
return decorated_f
|
||||
return decorator
|
||||
|
||||
def get_mc_client():
|
||||
""" Return a new connection to memcached
|
||||
"""
|
||||
if not MEMCACHED_ENABLED:
|
||||
return False
|
||||
|
||||
import pylibmc
|
||||
|
||||
mc = pylibmc.Client(MEMCACHED_SERVERS, binary=True,
|
||||
username=MEMCACHED_USERNAME,
|
||||
password=MEMCACHED_PASSWORD,
|
||||
behaviors={"no_block": True,
|
||||
"connect_timeout": 200})
|
||||
return mc
|
||||
|
||||
|
||||
def build_api_call_object(text):
|
||||
api_call = {}
|
||||
|
||||
@@ -62,6 +80,52 @@ def build_api_call_object(text):
|
||||
|
||||
return api_call
|
||||
|
||||
class MarkdownGroup:
|
||||
def __init__(self):
|
||||
self.notes = False
|
||||
self.subgroups = OrderedDict()
|
||||
def add_to_group(self, obj, subgroup):
|
||||
if not subgroup in self.subgroups:
|
||||
self.subgroups[subgroup] = []
|
||||
self.subgroups[subgroup].append(obj)
|
||||
|
||||
def write_markdown_spec(f_out, api_calls):
|
||||
groups = OrderedDict()
|
||||
|
||||
for api_obj in api_calls:
|
||||
obj = {}
|
||||
obj["Method"] = api_obj["title"]
|
||||
obj["API Call"] = "{} {}".format(api_obj["method"],
|
||||
api_obj["path_template"])
|
||||
obj["Grouping"] = api_obj["grouping"]
|
||||
obj["Notes"] = api_obj["notes"] if "notes" in api_obj else ""
|
||||
obj["API Family"] = api_obj["family"] if "family" in api_obj else "-"
|
||||
obj["Subgroup"] = api_obj["subgroup"] if "subgroup" in api_obj else ""
|
||||
|
||||
if obj["Grouping"] not in groups:
|
||||
groups[obj["Grouping"]] = MarkdownGroup()
|
||||
groups[obj["Grouping"]].add_to_group(obj, obj["Subgroup"])
|
||||
|
||||
if "grouping_note" in api_obj:
|
||||
groups[obj["Grouping"]].notes = api_obj["grouping_note"]
|
||||
|
||||
row_headers = ["Method", "API Call", "API Family", "Notes"]
|
||||
|
||||
|
||||
f_out.write("# Blockstack Specifications\n\n")
|
||||
for gname, g in groups.items():
|
||||
f_out.write("## {}\n\n".format(gname))
|
||||
for sg_name, sg in g.subgroups.items():
|
||||
if len(sg_name) > 0:
|
||||
f_out.write("### {}\n\n".format(sg_name))
|
||||
f_out.write("| {} |\n".format(" | ".join(row_headers)))
|
||||
f_out.write("| {} |\n".format(" | ".join(["----" for i in row_headers])))
|
||||
for item in sg:
|
||||
f_out.write("| {} |\n".format(" | ".join(
|
||||
[item[k] for k in row_headers])))
|
||||
f_out.write("\n\n")
|
||||
if g.notes:
|
||||
f_out.write("#### {}\n\n".format(g.notes))
|
||||
|
||||
def get_api_calls(filename):
|
||||
api_calls = []
|
||||
|
||||
Reference in New Issue
Block a user