class EntryLockResource(Resource): @marshal_with(fields.entry_lock, envelope="lock") def get(self, entry_id, logbook_id=None): "Check for a lock" entry = Entry.get(Entry.id == entry_id) lock = entry.get_lock(request.environ["REMOTE_ADDR"]) if lock: return lock raise EntryLock.DoesNotExist @use_args({"steal": Boolean(missing=False)}) @marshal_with(fields.entry_lock, envelope="lock") def post(self, args, entry_id, logbook_id=None): "Acquire (optionally stealing) a lock" entry = Entry.get(Entry.id == entry_id) return entry.get_lock(ip=request.environ["REMOTE_ADDR"], acquire=True, steal=args["steal"]) @use_args({"lock_id": Integer()}) @marshal_with(fields.entry_lock, envelope="lock") def delete(self, args, entry_id=None, logbook_id=None): "Cancel a lock" if "lock_id" in args: lock = EntryLock.get(EntryLock.id == args["lock_id"]) else: entry = Entry.get(Entry.id == entry_id) lock = entry.get_lock() lock.cancel(request.environ["REMOTE_ADDR"]) return lock
def __init__(self) -> None: super().__init__() self.arg_schema = dict( page=Str(missing=None, description="Page"), per_page=Int(missing=20, description="Number to show"), all=Boolean(missing=False, description="Return all results."), ) self.fields = {} self.basic_info = {} self.schema = None
class OpenSearchEndpoint(HTTPEndpoint): args_schema = dict( page=Str(missing=None, description="Page"), per_page=Int(missing=20, description="Number to show"), all=Boolean(missing=False, description="Return all results."), ) def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) async def get(self, request): db = app_context().database query_params = request.query_params if "query" not in query_params or "model" not in query_params: return JSONResponse({ "Status": "Success", "Message": "Provide a string as a query parameter or model", "example": "/api/v2/search?query=lava&model=sample", }) params = {"query": query_params["query"]} model = query_params["model"] models = { "sample": search_sample, "project": search_project, "session": search_session, } if model == "all": sql_fn = search_total query_res = db.exec_sql_query(fn=sql_fn, params=params) json_res = [dict(model=x, data=y) for x, y in query_res] json_res.reverse() return JSONResponse(json_res) else: for key, value in models.items(): if model == key: sql_fn = value schema = getattr(db.interface, key)(many=True) query_res = db.exec_sql_query(fn=sql_fn, params=params) json_res = [dict(r) for r in query_res] return APIResponse(json_res, total_count=len(json_res), schema=schema)
def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.meta = self.Meta() if getattr(self.meta, "table") is None: raise ValueError( f"Meta value '{k}' must be provided for ViewAPIEndpoint") self._model_name = classname_for_table(self.meta.table) log.info(self._model_name) self.args_schema = dict(page=Str(missing=None), per_page=Int(missing=20), all=Boolean(missing=False))
def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.meta = self.Meta() for k in ("database", "schema"): if getattr(self.meta, k) is None: raise ValueError( f"Meta value '{k}' must be provided for ModelAPIEndpoint") schema = self.meta.schema self._model_name = classname_for_table(schema.opts.model.__table__) log.info(self._model_name) d = "related models to nest within response [allowed_nests]" e = "?nest=session,project" des = create_params(d, e) self.instance_schema = dict( nest=NestedModelField(Str(), missing=[], description=des)) des_page = create_params("number of results per page", "?page=>i:5039") des_per_page = create_params("number of results per page", "?per_page=15") des_all = create_params("return all results", "?all=true") self.args_schema = dict( **self.instance_schema, page=Str(missing=None, description=des_page), per_page=Int(missing=20, description=des_per_page), all=Boolean(missing=False, description=des_all), ) self._filters = [] self.register_filter(OpenSearchFilter) self.register_filter(AuthorityFilter) self.register_filter(FieldExistsFilter) self.register_filter(FieldNotExistsFilter) self.register_filter(EmbargoFilter) self.register_filter(DateFilter) self.register_filter(DOIFilter) self.register_filter(CoordinateFilter) self.register_filter(GeometryFilter) self.register_filter(TextSearchFilter) self.register_filter(AgeRangeFilter) self.register_filter(IdListFilter) self.register_filter(TagsFilter)
class DataFileListEndpoint(HTTPEndpoint): """A simple demonstration endpoint for paginating a select statement. Extremely quick, but somewhat hand-constructed.""" args_schema = dict( page=Str(missing=None, description="Page"), per_page=Int(missing=20, description="Number to show"), all=Boolean(missing=False, description="Return all results."), ) def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) db = get_database() self.schema = db.interface.data_file self.model = db.model.data_file self._filters = [] self.register_filter(OpenSearchFilter) self.register_filter(AuthorityFilter) self.register_filter(FieldExistsFilter) self.register_filter(FieldNotExistsFilter) self.register_filter(EmbargoFilter) self.register_filter(DateFilter) self.register_filter(TextSearchFilter) self.register_filter(AgeRangeFilter) self.register_filter(IdListFilter) self.register_filter(TagsFilter) def register_filter(self, _filter: BaseFilter): """Register a filter specification to control parametrization of the model query""" f = _filter(self.model, schema=self.schema) if not f.should_apply(): return if params := getattr(f, "params"): self.args_schema.update(**params) self._filters.append(f)
@advantage_checks(check_list=["need_user"]) @use_kwargs(post_payment_method, location="json") def post_payment_method(**kwargs): api_url = kwargs.get("api_url") token = kwargs.get("token") account_id = kwargs.get("account_id") payment_method_id = kwargs.get("payment_method_id") advantage = UAContractsAPI(session, token, api_url=api_url) return advantage.put_payment_method(account_id, payment_method_id) @advantage_checks(check_list=["need_user"]) @use_kwargs({"should_auto_renew": Boolean()}, location="json") def post_auto_renewal_settings(**kwargs): api_url = kwargs.get("api_url") token = kwargs.get("token") should_auto_renew = kwargs.get("should_auto_renew", False) advantage = UAContractsAPI(session, token, api_url=api_url) accounts = advantage.get_accounts() for account in accounts: monthly_subscriptions = advantage.get_account_subscriptions( account_id=account["id"], marketplace="canonical-ua", filters={"status": "active", "period": "monthly"}, )
class EntryResource(Resource): "Handle requests for a single entry" @use_args({"thread": Boolean(missing=False)}) @marshal_with(fields.entry_full, envelope="entry") def get(self, args, entry_id, logbook_id=None, revision_n=None): entry = Entry.get(Entry.id == entry_id) if revision_n is not None: return entry.get_revision(revision_n) if args["thread"]: return entry._thread return entry @send_signal(new_entry) @use_args(entry_args) @marshal_with(fields.entry_full, envelope="entry") def post(self, args, logbook_id, entry_id=None): "Creating a new entry" logbook = Logbook.get(Logbook.id == logbook_id) # TODO: clean up if entry_id is not None: # we're creating a followup to an existing entry args["follows"] = entry_id if args.get("content"): content_type = args["content_type"] if content_type.startswith("text/html"): # extract any inline images as attachments args["content"], inline_attachments = handle_img_tags( args["content"], timestamp=args.get("created_at")) else: inline_attachments = [] else: inline_attachments = [] args["logbook"] = logbook # make sure the attributes are of proper types try: args["attributes"] = logbook.check_attributes( args.get("attributes", {})) except ValueError as e: abort(422, messages={"attributes": [str(e)]}) if args.get("follows_id"): # don't allow pinning followups, that makes no sense args["pinned"] = False entry = Entry.create(**args) for attachment in inline_attachments: attachment.entry = entry attachment.save() return entry @send_signal(edit_entry) @use_args(entry_args) @marshal_with(fields.entry_full, envelope="entry") def put(self, args, entry_id, logbook_id=None): "update entry" entry_id = entry_id or args["id"] entry = Entry.get(Entry.id == entry_id) # to prevent overwiting someone else's changes we require the # client to supply the "revision_n" field of the entry they # are editing. If this does not match the current entry in the # db, it means someone has changed it inbetween and we abort. if "revision_n" not in args: abort(400, message="Missing 'revision_n' field!") if args["revision_n"] != entry.revision_n: abort( 409, message= ("Conflict: Entry {} has been edited since you last loaded it!" .format(entry_id))) # check for a lock on the entry if entry.lock: if entry.lock.owned_by_ip == request.remote_addr: entry.lock.cancel(request.remote_addr) else: abort( 409, message=("Conflict: Entry {} is locked by IP {} since {}". format(entry_id, entry.lock.owned_by_ip, entry.lock.created_at))) if args.get("content"): content_type = args.get("content_type", entry.content_type) if content_type.startswith("text/html"): args["content"], inline_attachments = handle_img_tags( args["content"]) else: inline_attachments = [] else: inline_attachments = [] entry = Entry.get(Entry.id == entry_id) change = entry.make_change(**args) entry.save() change.save() for attachment in inline_attachments: attachment.entry = entry attachment.save() return entry
"name": Str(), "description": Str(allow_none=True), "template": Str(allow_none=True), "attributes": List( Nested({ "name": Str(), "type": Str(validate=lambda t: t in ["text", "number", "boolean", "option", "multioption"]), "required": Boolean(), "options": List(Str()) })), "metadata": Dict(), "archived": Boolean(missing=False) } class LogbooksResource(Resource): "Handle requests for logbooks" @use_args({"parent": Integer()})
List(Nested({ "name": Str(), "login": Str(allow_none=True), "email": Email(allow_none=True) }), validate=lambda a: len(a) > 0), "created_at": LocalDateTime(), "last_changed_at": LocalDateTime(allow_none=True), "follows_id": Integer(allow_none=True), "attributes": Dict(), "archived": Boolean(), "metadata": Dict(), "priority": Integer(missing=0), "revision_n": Integer() } class EntryResource(Resource): "Handle requests for a single entry" @use_args({"thread": Boolean(missing=False)}) @marshal_with(fields.entry_full, envelope="entry")
logbook_args = { "parent_id": Integer(allow_none=True), "name": Str(), "description": Str(allow_none=True), "template": Str(allow_none=True), "attributes": List(Nested({ "name": Str(), "type": Str( validate=lambda t: t in ["text", "number", "boolean", "option", "multioption"]), "required": Boolean(), "options": List(Str(), missing=None) })), "metadata": Dict(), "archived": Boolean(missing=False) } class LogbooksResource(Resource): "Handle requests for logbooks" @use_args({"parent": Integer()}) @marshal_with(fields.logbook, envelope="logbook") def get(self, args, logbook_id=None, revision_n=None):
class EntitlementSchema(Schema): type = String(required=True) is_enabled = Boolean(required=True)
line1 = String() postal_code = String() state = String() class TaxIdSchema(Schema): type = String() value = String() post_advantage_subscriptions = { "account_id": String(required=True), "period": String(enum=["monthly", "yearly"], required=True), "previous_purchase_id": String(required=True), "products": List(Nested(ProductSchema), required=True), "resizing": Boolean(), "trialling": Boolean(), } cancel_advantage_subscriptions = { "account_id": String(required=True), "previous_purchase_id": String(required=True), "product_listing_id": String(required=True), } post_anonymised_customer_info = { "account_id": String(required=True), "name": String(required=True), "address": Nested(AddressSchema, required=True), "tax_id": Nested(TaxIdSchema, allow_none=True), }
String(), "marketplace": String( validate=validate.OneOf(["canonical-ua", "canonical-cube", "blender"]), required=True, ), "action": String(validate=validate.OneOf(["purchase", "resize", "trial", "offer"])), } post_advantage_subscriptions = { "account_id": String(required=True), "period": String(enum=["monthly", "yearly"], required=True), "previous_purchase_id": String(required=True), "products": List(Nested(ProductSchema), required=True), "resizing": Boolean(), "marketplace": String(), "trialling": Boolean(), } cancel_advantage_subscriptions = { "account_id": String(required=True), "previous_purchase_id": String(required=True), "product_listing_id": String(required=True), "marketplace": String( validate=validate.OneOf(["canonical-ua", "canonical-cube", "blender"]), required=True,
class SubscriptionRenewalSchema(Schema): subscription_id = String() should_auto_renew = Boolean()
List(Nested({ "name": Str(), "login": Str(allow_none=True), "email": Email(allow_none=True) }), validate=lambda a: len(a) > 0), "created_at": LocalDateTime(), "last_changed_at": LocalDateTime(allow_none=True), "follows_id": Integer(allow_none=True), "attributes": Dict(), "archived": Boolean(), "no_change_time": Boolean(), "metadata": Dict(), "priority": Integer(missing=0), "revision_n": Integer(), } class EntryResource(Resource): "Handle requests for a single entry"
line1 = String() postal_code = String() state = String() class TaxIdSchema(Schema): type = String() value = String() post_advantage_subscriptions = { "account_id": String(required=True), "period": String(enum=["monthly", "yearly"], required=True), "previous_purchase_id": String(required=True), "products": List(Nested(ProductSchema), required=True), "resizing": Boolean(), } cancel_advantage_subscriptions = { "account_id": String(required=True), "previous_purchase_id": String(required=True), "product_listing_id": String(required=True), } post_anonymised_customer_info = { "account_id": String(required=True), "address": Nested(AddressSchema, required=True), "tax_id": Nested(TaxIdSchema, allow_none=True), } post_payment_method = {
def params(self): d = "filter by embargoed or not, (false = private data, true = public data, empty = all data)" e = ["?public=true", "?public=false"] des = create_params(d, e) return {self.key: Boolean(description=des)}