class IssueSchema(Schema): id = Integer() user = Nested(UserSchema()) user_id = Integer() user_url = Url(relative=True) bike = Nested(BikeSchema(), allow_none=True) bike_identifier = BytesField(as_string=True, allow_none=True) bike_url = Url(relative=True, allow_none=True) opened_at = DateTime() closed_at = DateTime() description = String(required=True) resolution = String(allow_none=True) status = EnumField(IssueStatus, default=IssueStatus.OPEN) @validates_schema def assert_url_included_with_foreign_key(self, data, **kwargs): """ Asserts that when a user_id or bike_id is sent that a user_url or bike_url is sent with it. """ if "user_id" in data and "user_url" not in data: raise ValidationError( "User ID was included, but User URL was not.") if "bike_id" in data and "bike_url" not in data: raise ValidationError( "Bike ID was included, but Bike URL was not.")
class RecordIdentifier(StrictKeysMixin): nuslOAI = OAI() nrcrHandle = Url() nrcrOAI = OAI() originalRecord = Url() originalRecordOAI = OAI() catalogueSysNo = SanitizedUnicode()
class CollectionCreateSchema(Schema): label = String(validate=Length(min=2, max=500), required=True) foreign_id = String(missing=None) casefile = Boolean(missing=None) summary = String(allow_none=True) publisher = String(allow_none=True) publisher_url = Url(allow_none=True) data_url = Url(allow_none=True) info_url = Url(allow_none=True) countries = List(Country()) languages = List(Language()) category = Category(missing=None)
class RentalSchema(Schema): id = Integer(required=True) user = Nested(UserSchema()) user_id = Integer() user_url = Url(relative=True) bike = Nested(BikeSchema()) bike_identifier = BytesField(as_string=True) bike_url = Url(relative=True) events = Nested(RentalUpdateSchema(), many=True) start_time = DateTime(required=True) end_time = DateTime() cancel_time = DateTime() is_active = Boolean(required=True) price = Float() distance = Float() @validates_schema def assert_end_time_with_price(self, data, **kwargs): """ Asserts that when a rental is complete both the price and end time are included. """ if "price" in data and "end_time" not in data: raise ValidationError( "If the price is included, you must also include the end time." ) elif "price" not in data and "end_time" in data: raise ValidationError( "If the end time is included, you must also include the price." ) if "price" in data and "estimated_price" in data: raise ValidationError( "Rental should have one of either price or estimated_price.") @validates_schema def assert_url_included_with_foreign_key(self, data, **kwargs): """ Asserts that when a user_id or bike_id is sent that a user_url or bike_url is sent with it. """ if "user_id" in data and "user_url" not in data: raise ValidationError( "User ID was included, but User URL was not.") if "bike_id" in data and "bike_url" not in data: raise ValidationError( "Bike ID was included, but Bike URL was not.")
class InstitutionsMixin: relatedID = Nested(RelatedIDSchema) aliases = List(SanitizedUnicode()) ico = SanitizedUnicode() url = Url() provider = Boolean(missing=False) formerNames = List(SanitizedUnicode())
class WebPageSchema(Schema): url = Url(required=True, allow_none=False) html = String(required=True) @post_load() def make_web_page(self, data): return WebPage(**data)
class UserPaymentView(BaseView): """ Allows a user to get or replace their payment details. """ url = f"/users/{{id:{USER_IDENTIFIER_REGEX}}}/payment" with_user = match_getter(get_user, 'user', user_id='id') @with_user @docs(summary="Check For Existence Of Payment Details") @returns(None) async def get(self, user: User): if user.can_pay: raise web.HTTPOk else: raise web.HTTPNoContent @with_user @docs(summary="Add Or Replace Payment Details") @expects(PaymentSourceSchema()) async def put(self, user: User): if user.can_pay: await self.payment_manager.update_customer( user, self.request["data"]["token"]) else: await self.payment_manager.create_customer( user, self.request["data"]["token"]) raise web.HTTPOk @with_user @docs(summary="Delete Payment Details") @returns( active_rental=JSendSchema.of(rental=RentalSchema(), message=String(), url=Url(relative=True)), no_details=(None, web.HTTPNotFound), deleted=(None, web.HTTPNoContent), ) async def delete(self, user: User): rental = await self.rental_manager.active_rental(user) if rental is not None: return "active_rental", { "status": JSendStatus.FAIL, "data": { "message": "You cannot delete your payment details with an active rental.", "url": self.request.app.router["rental"].url_for( id=str(rental.id)).path } } elif not user.can_pay: return "no_details", None else: await self.payment_manager.delete_customer(user) return "deleted", None
class CollectionSchema(BaseSchema): EXPAND = [ ('creator', Role, 'creator', RoleReferenceSchema, False), ] label = String(validate=Length(min=2, max=500), required=True) foreign_id = String(missing=None) kind = String(dump_only=True) casefile = Boolean(missing=None) summary = String(allow_none=True) publisher = String(allow_none=True) publisher_url = Url(allow_none=True) data_url = Url(allow_none=True) info_url = Url(allow_none=True) countries = List(Country()) languages = List(Language()) secret = Boolean(dump_only=True) category = Category(missing=Collection.DEFAULT) creator_id = String(allow_none=True) creator = Nested(RoleReferenceSchema(), dump_only=True) team = List(Nested(RoleReferenceSchema()), dump_only=True) count = Integer(dump_only=True) schemata = Dict(dump_only=True, default={}) @pre_load def flatten_collection(self, data): flatten_id(data, 'creator_id', 'creator') @pre_dump def visibility(self, data): if not is_mapping(data): return roles = [int(r) for r in data.get('roles', [])] public = Role.public_roles() data['secret'] = len(public.intersection(roles)) == 0 @post_dump def hypermedia(self, data): pk = str(data.get('id')) data['links'] = { 'self': url_for('collections_api.view', id=pk), 'ui': collection_url(pk) } data['writeable'] = request.authz.can_write(pk) return data
class ReservationSchema(CreateReservationSchema): id = Integer() made_at = DateTime() ended_at = DateTime() status = EnumField(ReservationOutcome, default=ReservationOutcome.OPEN) user = Nested(UserSchema()) user_id = Integer() user_url = Url(relative=True) pickup = Nested(PickupPointSchema()) pickup_id = Integer() pickup_url = Url(relative=True) rental = Nested(RentalSchema()) rental_io = Integer() rental_url = Url(relative=True)
class NewInstanceRequest(SPSchema): """Validator for POST /rpc/client requests.""" # Deserialization fields. chain_url = Url(required=True, load_only=True) privkey = BytesField(required=True, load_only=True) gas_price_strategy = String(required=False, load_only=True, missing="fast") # Serialization fields. rpc_client_id = String(required=True, dump_only=True)
class CollectionSchema(BaseSchema): EXPAND = [ ('creator', Role, 'creator', RoleReferenceSchema, False), ] label = String(validate=Length(min=2, max=500), required=True) foreign_id = String(missing=None) kind = String(dump_only=True) casefile = Boolean(missing=None) summary = String(allow_none=True) publisher = String(allow_none=True) publisher_url = Url(allow_none=True) data_url = Url(allow_none=True) info_url = Url(allow_none=True) countries = List(Country()) languages = List(Language()) secret = Boolean(dump_only=True) category = Category(missing=Collection.DEFAULT) creator_id = String(allow_none=True) creator = Nested(RoleReferenceSchema(), dump_only=True) team = List(Nested(RoleReferenceSchema()), dump_only=True) count = Integer(dump_only=True) schemata = Dict(dump_only=True) @pre_load def flatten_collection(self, data): flatten_id(data, 'creator_id', 'creator') @post_dump def hypermedia(self, data): pk = str(data.get('id')) data['links'] = { 'self': url_for('collections_api.view', id=pk), 'xref': url_for('xref_api.index', id=pk), 'xref_csv': url_for('xref_api.csv_export', id=pk, _authorize=True), 'ui': collection_url(pk) } data['writeable'] = request.authz.can(pk, request.authz.WRITE) return data
class CreateClientSchema(SPSchema): """POST /rpc/client load-only parameters: - chain_url (:class:`Url`) - privkey (:class:`BytesField`) - gas_price (str) dump-only parameters: - client_id (:class:`RPCClientID`) """ # Deserialization fields. chain_url = Url(required=True, load_only=True) privkey = BytesField(required=True, load_only=True) gas_price = GasPrice(required=False, load_only=True, missing="FAST") # Serialization fields. client_id = RPCClientID(required=True, dump_only=True)
class RightsMixin: icon = Url() related = Nested(RightsRelated)
class UserEndCurrentRentalView(BaseView): """""" url = f"/users/{{id:{USER_IDENTIFIER_REGEX}}}/rentals/current/{{action}}" name = "user_end_current_rental" with_user = match_getter(get_user, 'user', user_id='id') actions = ("cancel", "complete") @with_user @docs(summary="End Rental For User") @requires(UserMatchesToken() | UserIsAdmin()) @returns( no_rental=(JSendSchema(), web.HTTPNotFound), invalid_action=(JSendSchema(), web.HTTPNotFound), rental_completed=JSendSchema.of(rental=RentalSchema(), action=String(), receipt_url=Url(allow_none=True)), ) async def patch(self, user: User): """ Ends a rental for a user, in one of two ways: - ``PATCH /users/me/rentals/current/cancel`` cancels the rental - ``PATCH /users/me/rentals/current/complete`` completes the rental """ if not self.rental_manager.has_active_rental(user): return "no_rental", { "status": JSendStatus.FAIL, "data": { "message": "You have no current rental." } } end_type = self.request.match_info["action"] if end_type not in self.actions: return "invalid_action", { "status": JSendStatus.FAIL, "data": { "message": f"Invalid action. Pick between {', '.join(self.actions)}", "actions": self.actions } } if end_type == "complete": rental, receipt_url = await self.rental_manager.finish(user) elif end_type == "cancel": rental = await self.rental_manager.cancel(user) receipt_url = None else: raise Exception return "rental_completed", { "status": JSendStatus.SUCCESS, "data": { "rental": await rental.serialize(self.rental_manager, self.bike_connection_manager, self.reservation_manager, self.request.app.router), "action": "canceled" if end_type == "cancel" else "completed", "receipt_url": receipt_url, } }
class CurrentReservationSchema(ReservationSchema): url = Url(relative=True, required=True)
class Links(Schema): self = Url()
class CommonMetadataSchemaV2(InvenioRecordMetadataSchemaV1Mixin, FSMRecordSchemaMixin, OARepoCommunitiesMixin, StrictKeysMixin): """Schema for the record metadata.""" abstract = MultilingualStringV2() accessibility = MultilingualStringV2() accessRights = TaxonomyField(mixins=[TitledMixin, AccessRightsMixin], required=True) creator = List(Nested(PersonSchema), required=True) contributor = List(Nested(ContributorSchema)) dateIssued = NRDate(required=True) dateModified = NRDate() resourceType = TaxonomyField(mixins=[TitledMixin], required=True) extent = List(SanitizedUnicode()) # TODO: pokud nemáme extent, spočítat z PDF - asi nepůjde externalLocation = Url() control_number = SanitizedUnicode(required=True) recordIdentifiers = Nested(RecordIdentifier) workIdentifiers = Nested(WorkIdentifersSchema) isGL = Boolean() language = TaxonomyField(mixins=[TitledMixin], required=True) note = List(SanitizedUnicode()) fundingReference = List(Nested(FundingReferenceSchema)) provider = TaxonomyField(mixins=[TitledMixin, InstitutionsMixin], required=True) entities = TaxonomyField(mixins=[TitledMixin, InstitutionsMixin], many=True) publicationPlace = Nested(PublicationPlaceSchema) publisher = List(SanitizedUnicode()) relatedItem = List(Nested(RelatedItemSchema)) rights = TaxonomyField(mixins=[TitledMixin, RightsMixin], many=True) series = List(Nested(SeriesSchema)) subject = TaxonomyField(mixins=[TitledMixin, SubjectMixin, PSHMixin, CZMeshMixin, MedvikMixin], many=True) keywords = List(MultilingualStringV2()) title = List(MultilingualStringV2(required=True), required=True, validate=Length(min=1)) titleAlternate = List(MultilingualStringV2()) rulesExceptions = List(Nested(RulesExceptionsSchema)) @pre_load def check_keyword(self, data, **kwargs): keywords = data.get("keywords", []) if isinstance(keywords, dict): if "error" in keywords: raise ValidationError(keywords["error"]) return data @post_load def check_language(self, data, **kwargs): language = data.get("language") if not language: raise ValidationError("Language is required field", field_name="language") return data @post_load def validate_keywords_subjects(self, data, **kwargs): subject = [x for x in data.get("subject", []) if not x["is_ancestor"]] keywords = data.get("keywords", []) if len(keywords) + len(subject) < 3: raise ValidationError("At least three subjects or keyword are required", field_name="keywords") return data @post_load def copy_to_entities(self, data, **kwargs): entities = data.get("entities") if not entities: data["entities"] = data["provider"] return data @post_load def rules_exceptions(self, data, **kwargs): if "rulesExceptions" in data: raise ValidationError(f"Some rules raises exception: {data['rulesExceptions']}") return data