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. """ import sanic import logging from .helpers import url_validator bp = sanic.Blueprint('API-Routes') log = logging.getLogger(__name__) @bp.route("/ip/redirect", methods=["GET"]) async def ip_redirect_tracker(request): try: url = request.args["url"] except KeyError: try: url = request.json.get("url") except (AttributeError, KeyError): error = """Please specify one or more IP Addresses under the "ip" query parameter (multiple or space separated) or as a json body under the "ip" (single) or "addresses" (array) keys.""" return sanic.response.json({"error": error}, status=400)
"""/api""" import sanic from sanic_jwt import decorators as jwtdec from . import uid_get root = sanic.Blueprint('attrs_api', url_prefix='') @root.get('/attrs') @uid_get('perms', 'location') @jwtdec.protected() async def serve_attrs(rqst, perms, location): """ Catch-all combination of location-related attributes. """ resp = { 'types': await location.media_types(), 'genres': await location.genres(), 'color': location.color, } resp['names'] = { 'perms': [ None, # -- line 42 -- 'Manage accounts (edit names, usernames and passwords)', 'Manage media (add items, edit metadata)', 'Manage roles (edit permissions and names)', None, # -- line 43 -- 'Generate & view reports', 'Return items', ],
from json import dumps from os.path import exists, join import sanic import sqlalchemy from sqlalchemy.future import select from xss_receiver import constants from xss_receiver import system_config, publish_subscribe from xss_receiver.constants import ALLOWED_METHODS from xss_receiver.mailer import send_mail from xss_receiver.models import HttpRule, HttpAccessLog from xss_receiver.publish_subscribe import PublishMessage from xss_receiver.utils import process_headers, random_string, fix_upper_case, write_file, filter_list, render_dynamic_template, read_file, generate_dynamic_template_globals, add_system_log, secure_filename_with_directory index_controller = sanic.Blueprint('index_controller', __name__) @index_controller.route('/', methods=ALLOWED_METHODS) @index_controller.route('/<path:path>', methods=ALLOWED_METHODS) @process_headers async def mapping(request: sanic.Request, path=''): path = request.path result: sqlalchemy.engine.result.ChunkedIteratorResult result = await request.ctx.db_session.execute( select(HttpRule).where(HttpRule.path == path)) rule = result.scalar() if rule is None: return sanic.response.html('', 404)
import sanic from sanic.log import logger from sanic.response import json, text from . import secrets from .slacker import Slacker # attach additional api routes to 'routing' routing = sanic.Blueprint('slack-bot-extras') # To create a new app go to https://api.slack.com/apps?new_app=1 # Manager your apps: # https://api.slack.com/apps # Manage slash commands in an app: # https://api.slack.com/apps/:id/slash-commands bot = Slacker( token=secrets.slack_api_token, signing_secret=secrets.slack_signing_secret, ) # this would be called by the `/hello` slash command. # # the url will be <openfaas_gateway>/function/<function_name>/hello @bot.slash_cmd("hello") async def hello(request: sanic.request.Request): logger.debug(f"handling request: {request}") # sample form payload # { # 'token': ['...'], # 'team_id': ['...'],
# -*- coding: utf-8 -*- import spmapi.utils.tools as tools import spmapi.schemas.formula import sanic bp = sanic.Blueprint(name='formulas', version=1) formulas = spmapi.schemas.formula.Formula(many=True) @bp.post('/formulas') async def upload_formula(request): if not request.files: return sanic.response.json({'error': 'No files uploaded'}, status=400) for name, archive in request.files.items(): await tools.upload(name=name, spmfile=archive[0]) return sanic.response.json({'message': 'success'}, status=200) @bp.get('/formulas') async def list_formula(request): name = request.form.get('name') result = await tools.list_formulas(name) return sanic.response.json( { 'message': 'success', 'formulas': formulas.dump(result).data },
# Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import logging import sanic from sanic import response from cnapps import exceptions LOGGER = logging.getLogger(__name__) REST = sanic.Blueprint("errors") def debug_error(error): message = [str(x) for x in error.args] if not message: message = error.message LOGGER.debug("Error: %s", message) def make_error_response(error_type, message, status_code, description=None): content = { "success": False, "error": { "type": error_type, "message": message,
import sanic from asyncpg.exceptions import UniqueViolationError from sanic_jwt import decorators as jwtdec from . import uid_get, rqst_get from . import MediaType types = sanic.Blueprint('location_media_types', url_prefix='/types') @types.get('/') @uid_get('location') @jwtdec.protected() async def get_location_media_types(rqst, location): """ Serves all media types (as serialized dicts) defined on a location. """ return sanic.response.json({'types': await location.media_types()}, status=200) @types.get('/info') @uid_get('location') @rqst_get('name') @jwtdec.protected() async def get_media_type_info(rqst, location, *, name): """ Serves attrs of a requested media type given its name. """ mtype = await MediaType(name, location, rqst.app) return sanic.response.json({'type': mtype.to_dict()}, status=200)
{ 'id': 42, 'name': 'fantasy' 'created_at': 1502680672, 'updated_at': 1502680672 } Raises: :class:`NotFound<sanic:sanic.exceptions.NotFound>`: The media_genre does not exist. """ async with request.app.pool.acquire() as conn: rows = await conn.fetch( """ SELECT g.id, g.name, g.created_at, g.updated_at FROM ysr.genre g INNER JOIN ysr.media_genre mg ON mg.gid = g.id WHERE mg.mid=$1 AND mg.gid=$2 """, mid, gid) try: return sanic.response.json(dict(rows[0])) except IndexError: raise sanic.exceptions.NotFound( 'no genre with id {} on media {}'.format(gid, mid)) media = sanic.Blueprint('media', url_prefix='/media') media.add_route(MediaList.as_view(), '/') media.add_route(Media.as_view(), '/<mid:int>') media.add_route(MediaGenreList.as_view(), '/<mid:int>/genre') media.add_route(MediaGenre.as_view(), '/<mid:int>/genre/<gid:int>')
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import logging import sanic from sanic.response import json from sanic_openapi import doc from cnapps.api import commons from cnapps import version LOGGER = logging.getLogger(__name__) bp = sanic.Blueprint("version", url_prefix='/version') @bp.route("", methods=["GET"]) @doc.summary("Application version API") @doc.produces({"version": str}) async def version_status(request): """Display application version. Returns: A HTTP response in JSON (application/json content-type) """ LOGGER.info("Get version") return commons.make_webservice_response({"version": version.RELEASE})
import sanic bp_version1 = sanic.Blueprint('version1', url_prefix='/v1') bp_version2 = sanic.Blueprint('version2', url_prefix='/v2') @bp_version1.route('/generate') async def generate(request): return sanic.response.text('OK from version 1') @bp_version2.route('/generate') async def generate(request): return sanic.response.text('OK from version 2') if __name__ == '__main__': app = sanic.Sanic() app.blueprint(bp_version1) app.blueprint(bp_version2) app.run(host='0.0.0.0', port=8080)
import sanic from sanic_jwt import decorators as jwtdec from . import uid_get, rqst_get from . import MediaType root = sanic.Blueprint('location_media_api', url_prefix='') @root.get('/') @uid_get('location') @rqst_get('cont') @jwtdec.protected() async def all_location_items(rqst, location, *, cont): """ Serves all media items, in groups of 5 (paginated according to 'cont', i.e. what page to continue from). """ return sanic.response.json({'items': await location.items(cont=int(cont))}, status=200) @root.get('/search') @rqst_get('title', 'genre', 'media_type', 'author', 'cont') @uid_get('location') @jwtdec.protected() async def search_location_media(rqst, location, *, title, genre, media_type, author, cont): """ Implements item search functionality, serving a list of items that match the given search query.
"""/stock/buttons""" import sanic import sanic_jwt as jwt from sanic_jwt import decorators as jwtdec from . import uid_get, rqst_get from . import Location, Role, MediaType, MediaItem, User btn = sanic.Blueprint('button_stock', url_prefix='/buttons') @btn.get('/main-header') async def expose_header_buttons(rqst): """ Essentially a static resource; don't think I have anything to add. Keeping it here, though, so I can change it ... if I ever want to. Serves header buttons (via the angular webapp's HeadButtonService) to display at the top of every page. Requires nothing from client, as it's static. """ buttons = [{"text": 'home'}, {"text": 'help'}, {"text": 'about'}] # dest on home should not be necessary, but for some reason Angular # isn't picking up the redirect I've tried to place on the router # from '/home' to '/'... so instead it says # "Cannot match routes. url segment: home" return sanic.response.json({'buttons': buttons}, status=200) @btn.get('/home-sidebar') @rqst_get('user') @jwtdec.protected()
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import logging import time import sanic from sanic import response import prometheus_client from prometheus_client import core from prometheus_client import exposition LOGGER = logging.getLogger(__name__) REST = sanic.Blueprint("prometheus") GLOBAL_STATUS = prometheus_client.Gauge( "cnapps_sanic_up", "Was the last query of cnapps successful", ["service"]) REQUEST_LATENCY = prometheus_client.Histogram( "cnapps_sanic_request_latency_seconds", "Request Latency", ["method", "endpoint"], ) REQUEST_COUNT = prometheus_client.Gauge( "cnapps_sanic_request_count", "Request Count", ["method", "endpoint", "status_code"], )
'tuid': 14, 'mid': 3, 'value': 3.7, 'created_at': 1502680672, 'updated_at': 1502680672 } Raises: :class:`NotFound<sanic:sanic.exceptions.NotFound>`: The recommendation does not exist. TODO: Raise exception when no patch body is provided. """ current = await self.get(request, rid) value = self.get_field(request, 'value', default=current['value']) async with request.app.pool.acquire() as conn: await conn.execute( """ UPDATE ysr.recommendation SET value=$1 WHERE id=$2 """, value, rid) return await self.get(request, rid) recommendation = sanic.Blueprint('recommendation', url_prefix='/recommendation') recommendation.add_route(RecommendationList.as_view(), '/') recommendation.add_route(Recommendation.as_view(), '/<rid:int>')
import os import json os.sys.path.append( "/home/ubuntu/ws/go/src/github.com/ontio/ontology-python-compiler") import sanic import tempfile import functools import subprocess from ontology.compiler import Compiler tmp_exts = (".abi.json", ".debug.json", ".Func.Map", ".avm", ".avm.str", ".warning") app = sanic.Sanic(__name__) api = sanic.Blueprint("api", url_prefix="/api") v2_0 = sanic.Blueprint("v2.0", url_prefix="/v2.0") app_v2_0_list = api.group(v2_0, url_prefix=api.url_prefix) def read_value(data: dict, path, key: str): if key in ["abi", "debug", "funcmap", "opcode"]: with open(path, "r") as fp: content = fp.read() try: data[key] = json.dumps(json.loads(content)) except json.JSONDecodeError: data[key] = content elif key in ["avm"]: with open(path, "rb") as fp: data[key] = "{}".format(fp.read())
"""/api/role-attrs""" import sanic from sanic_jwt import decorators as jwtdec from . import uid_get, rqst_get from . import Role roles = sanic.Blueprint('roles_api', url_prefix='/roles') @roles.get('/me') @uid_get() @jwtdec.protected() async def provide_me_attrs(rqst, user): """ Provides all attributes - permissions, limits, and lock thresholds - for current user. Requires current session's Role ID from client. """ # resp = {'rid': user.role.rid, 'perms': user.perms, 'limits': user.limits, 'locks': user.locks} resp = {i: getattr(user, i) for i in ('perms', 'limits', 'locks')} return sanic.response.json(resp, status=200) @roles.get('/me/<attr:(perms|limits|locks)>') @uid_get() @jwtdec.protected() async def provide_specific_me_attr(rqst, user, *, attr): """ Provides a specific attribute (of perms/limits/locks) for requesting role.
return deco def unauthorized_handler(self, func: Callable) -> Callable: if asyncio.iscoroutinefunction(func) is False: raise ValueError('Function must be a coroutine') self.unauthorized_handler_ = func @wraps(func) def deco(*args: Any, **kwargs: Any): return func(*args, **kwargs) return deco auth = LoginManager() bp = sanic.Blueprint('app') @auth.unauthorized_handler async def login(request: Request, *args: Any, **kwargs: Any) -> HTTPResponse: app = request.app return await app.render_template('login.jinja') @bp.route('/readme', methods=['GET']) @auth.login_required async def readme(request: Request) -> HTTPResponse: app = request.app if app.bot.config['lang'] == 'ja': return await res.file('README.md') elif app.bot.config['lang'] == 'en':
"""/api/member""" import sanic from sanic_jwt import decorators as jwtdec from . import uid_get, rqst_get from . import User mbr = sanic.Blueprint('member_api', url_prefix='/member') @mbr.post('/self') @rqst_get('user', 'fullname', 'newpass', 'curpass') @jwtdec.protected() async def edit_self(rqst, user, *, fullname, newpass, curpass): """Full name; new password; current password to verify""" if not await user.verify_pw(curpass): return sanic.exceptions.abort(403, "Incorrectly-entered password. Please try again.") await user.edit_self(name=fullname, pw=newpass) return sanic.response.raw(b'', status=204) @mbr.get('/notifications') @rqst_get('location', 'username') @jwtdec.protected() async def get_notifs(rqst, location, *, username): """ Serves user's notifications -- overdue items, readied holds, etc. """ user = await User.from_identifiers(username, location, app=rqst.app) return sanic.response.json(await user.notifs(), status=200)
import sanic system = sanic.Blueprint('system') @system.route('/ping', methods=['GET', 'HEAD']) async def ping(_request): """Simple healthcheck.""" return sanic.response.text('pong')
format:: { 'id': 42, 'name': 'not-fantasy' 'created_at': 1502680672, 'updated_at': 1502680672 } Raises: :class:`NotFound<sanic:sanic.exceptions.NotFound>`: The genre does not exist. TODO: Raise exception when no patch body is provided. """ current = await self.get(request, gid) name = self.get_field(request, 'name', default=current['name']) async with request.app.pool.acquire() as conn: await conn.execute('UPDATE ysr.genre SET name=$1 WHERE id=$2', name, gid) return await self.get(request, gid) genre = sanic.Blueprint('genre', url_prefix='/genre') genre.add_route(GenreList.as_view(), '/') genre.add_route(Genre.as_view(), '/<gid:int>')
"""/location/members""" import asyncpg import io import sanic from sanic_jwt import decorators as jwtdec from . import uid_get, rqst_get from . import User mbrs = sanic.Blueprint('location_members_api', url_prefix='/members') @mbrs.get('/') @rqst_get('cont') @uid_get('location') @jwtdec.protected() async def serve_location_members(rqst, location, *, cont: 'where to continue search from'): """ Serves all a location's members, in page determined by cont. (Output is not paginated in the actual application) """ return sanic.response.json(await location.members(cont=int(cont))) @mbrs.get('/info') @uid_get('perms') @rqst_get('check') @jwtdec.protected() async def serve_specific_member(rqst, perms, *, check: 'member to check'):
import asyncio from sanic import exceptions from sanic import response import sanic from discode_server.utils import baseconv from discode_server.utils import limiter from discode_server.utils import templates from discode_server import db from discode_server import forms bp = sanic.Blueprint('paste') @bp.listener('after_server_start') async def delete_expired(app, loop): while True: async with app.config.DB.acquire() as conn: await db.delete_expired(conn) await asyncio.sleep(60 * 60) @bp.get('/') async def index(request): paste_form = forms.NewPasteForm() return templates.render('index.html', paste_form=paste_form) @bp.post('/') @limiter.limiter("6/minute")
{ 'id': 42, 'uid': 12, 'mid': 3, 'value': 3.7, 'created_at': 1502680672, 'updated_at': 1502680672 } Raises: :class:`NotFound<sanic:sanic.exceptions.NotFound>`: The rating does not exist. TODO: Raise exception when no patch body is provided. """ current = await self.get(request, rid) value = self.get_field(request, 'value', default=current['value']) async with request.app.pool.acquire() as conn: await conn.execute('UPDATE ysr.rating SET value=$1 WHERE id=$2', value, rid) return await self.get(request, rid) rating = sanic.Blueprint('rating', url_prefix='/rating') rating.add_route(RatingList.as_view(), '/') rating.add_route(Rating.as_view(), '/<rid:int>')
def bp(self) -> sanic.Blueprint: bp = sanic.Blueprint("websub") @bp.route("/hb/<hex_id>") async def heartbeat(request: Request, hex_id: str) -> sanic.response.HTTPResponse: return text(hex_id, status=200 if hex_id in self.heartbeat_hashes else 404) @bp.route("/push-callback/<hex_id>", methods=["GET", "POST"]) async def callback(request: Request, hex_id: str) -> sanic.response.HTTPResponse: topic = request.args.get("hub.topic") mode = request.args.get("hub.mode") if mode == "subscribe": sub = self.subscriptions.get(topic) if sub is None: logger.warning( f"Unexpected subscription for {topic} on {hex_id}") return text("Unexpected subscription", status=400) else: lease_s = request.args.get('hub.lease_seconds') if not lease_s: logger.error( f"Lease is not resolved for sub {sub}: {lease_s!r}" ) return text("No lease", status=400) sub.verified_at = datetime.datetime.now() sub.lease = datetime.timedelta(seconds=int(lease_s)) logger.info( f"Subscription verified for {sub}, lease is {sub.lease}" ) if hex_id != sub.hex_id: logger.warning( f"Subscription hex does not match path hex: {sub.hex_id} != {hex_id}" ) return text(request.args.get("hub.challenge")) elif mode == "unsubscribe": sub = self.subscriptions.get(topic) if sub is None: logger.warning( f"Unexpected unsubscribe for {topic} on {hex_id}") return text("Unexpected unsubscribe", status=400) else: logger.info( f"Unsubscribe confirmed for {topic} on {hex_id}") if hex_id != sub.hex_id: logger.warning( f"Subscription hex does not match path hex: {sub.hex_id} != {hex_id}" ) return text(request.args.get("hub.challenge")) elif mode == "denied": logger.warning( f"Subscription denied for {topic}, reason was {request.args.get('hub.reason')}" ) return sanic.response.HTTPResponse() # TODO: Don't do anything for now, should probably mark the subscription. else: sub = self.get_sub_by_hex(hex_id) if sub is None: logger.warning( "Got unknown message for unknown subscription:") logger.warning(f"{hex_id}: {request}") return text("Unknown subscription", status=400) else: logger.info(f"Update for {sub}") await self.broadcast(sub, request) return sanic.response.HTTPResponse() return bp
import datetime import os import random import string from functools import partial, wraps from typing import Any, Callable, Optional import sanic from jinja2 import Environment, FileSystemLoader from sanic.request import Request from sanic.response import HTTPResponse, html from .localize import LocalizedText bp = sanic.Blueprint(__name__) @bp.route("/",methods=["GET"]) async def main(self, request: Request) -> HTTPResponse: return await request.app.render_template("index.html",{"self": request.app}) class LoginManager: def __init__(self, bot: 'Bot') -> None: self.id_len = 64 self.expires_in = datetime.timedelta(minutes=10) self.expires = {} self.cookie_key = "X-SessionId" self.unauthorized_handler_ = sanic.response.html("Unauthorized") def generate_id(self, request: Request) -> str:
import sanic, time a_list = [] app = sanic.Blueprint(__name__, url_prefix="/api/a") @app.route('/', methods=['POST']) async def add_a(request): a_list.append('a-' + time.asctime()) return sanic.response.text('') @app.route('/', methods=['GET']) async def get_a(request): return sanic.response.json(a_list)
{ 'id': 42, 'uid': 12, 'mid': 3, 'url': 'https://example.com/page-4' 'created_at': 1502680672, 'updated_at': 1502680672 } Raises: :class:`NotFound<sanic:sanic.exceptions.NotFound>`: The bookmark does not exist. TODO: Raise exception when no patch body is provided. """ current = await self.get(request, bid) url = self.get_field(request, 'url', default=current['url']) async with request.app.pool.acquire() as conn: await conn.execute('UPDATE ysr.bookmark SET url=$1 WHERE id=$2', url, bid) return await self.get(request, bid) bookmark = sanic.Blueprint('bookmark', url_prefix='/bookmark') bookmark.add_route(BookmarkList.as_view(), '/') bookmark.add_route(Bookmark.as_view(), '/<bid:int>')
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. """ import logging import sanic from sanic import request from twitchio.ext.webhooks.utils import remove_duplicates, verify_payload, Topic from twitchio.ext.webhooks.dispatcher import WebhookEventDispatcher log = logging.getLogger(__name__) dispatcher = WebhookEventDispatcher._registered_dispatcher bp = sanic.Blueprint("Twitchio Webhooks", url_prefix="/webhooks") @bp.route('/streams', ['GET']) async def handle_stream_changed_get(request: request.Request): """Route receiving the challenge requests for the topic StreamChanged Parameters ---------- request: sanic.request.Request The challenge request received from Twitch """ return dispatcher().accept_subscription(request, Topic.stream_changed) @bp.route('/streams', ['POST'])
Raises: :class:`NotFound<sanic:sanic.exceptions.NotFound>`: The user does not exist. TODO: Raise exception when no patch body is provided. """ current = await self.get(request, uid) name = self.get_field(request, 'name', default=current['name']) async with request.app.pool.acquire() as conn: await conn.execute('UPDATE ysr.user SET name=$1 WHERE id=$2', name, uid) return await self.get(request, uid) user = sanic.Blueprint('user', url_prefix='/user') user.add_route(UserList.as_view(), '/') user.add_route(User.as_view(), '/<uid:int>') # TODO: # /user/<uid>/rating # /user/<uid>/rating/<rtid> # /user/<uid>/bookmark # /user/<uid>/bookmark/<bmid> # /user/<uid>/recommendation-send # /user/<uid>/recommendation-send/<rid> # /user/<uid>/recommendation-receive # /user/<uid>/recommendation-receive/<rid>
# Note, this is the only one of these route-handler files that uses # straight Postgres instead of outsourcing it to the classes in typedef. import sanic from . import rqst_get help = sanic.Blueprint('api_help', url_prefix='/help') @help.get('/titles') async def serve_help_titles(rqst): """ These can be cached because they won't change """ titles = await rqst.app.pg_pool.fetch( '''SELECT id, title FROM help WHERE true''') return sanic.response.json( {'articles': [{ 'id': i['id'], 'title': i['title'] } for i in titles]}, status=200) @help.get('/content') @rqst_get('ID') async def serve_help_article(rqst, *, ID): """ These should never be cached. """ title, content = await rqst.app.pg_pool.fetchrow(