Skip to content
Snippets Groups Projects
Commit 75bbe276 authored by DAVID Axel's avatar DAVID Axel
Browse files

feat: :sparkles: Add V2 API :sparkles:

parent 8a7d62b7
Branches
Tags
No related merge requests found
Showing
with 695 additions and 117 deletions
...@@ -20,10 +20,12 @@ from blacksheep import Application, Response ...@@ -20,10 +20,12 @@ from blacksheep import Application, Response
from blacksheep.server.env import is_development from blacksheep.server.env import is_development
from blacksheep.server.responses import redirect from blacksheep.server.responses import redirect
from vigenere_api.version import get_version from vigenere_api.version import get_version, Version
from .v1.controllers import CaesarController as V1CaesarController from .v1.controllers import CaesarController as V1CaesarController
from .v1.openapi_docs import docs as v1_docs from .v1.openapi_docs import docs as v1_docs
from .v2.controllers import CaesarController as V2CaesarController, VigenereController
from .v2.openapi_docs import docs as v2_docs
application = Application() application = Application()
...@@ -40,12 +42,15 @@ if is_development(): # pragma: no cover ...@@ -40,12 +42,15 @@ if is_development(): # pragma: no cover
application.debug = True application.debug = True
application.show_error_details = True application.show_error_details = True
application.register_controllers([V1CaesarController]) application.register_controllers(
[V1CaesarController, V2CaesarController, VigenereController],
)
v1_docs.bind_app(application) v1_docs.bind_app(application)
v2_docs.bind_app(application)
get = application.router.get get = application.router.get
version = get_version() app_version: Version = get_version()
@v1_docs(ignored=True) @v1_docs(ignored=True)
...@@ -61,7 +66,7 @@ async def index() -> Response: ...@@ -61,7 +66,7 @@ async def index() -> Response:
redirect redirect
Response Response
""" """
return redirect(f"/api/v{version.major}") return redirect(f"/api/v{app_version.major}")
def __fallback() -> str: def __fallback() -> str:
......
...@@ -18,6 +18,13 @@ ...@@ -18,6 +18,13 @@
from .controller import Controller from .controller import Controller
from .open_api_handler import VigenereAPIOpenAPIHandler from .open_api_handler import VigenereAPIOpenAPIHandler
from .operation_docs import Algorithm, ControllerDocs, Operation
__all__ = ["VigenereAPIOpenAPIHandler", "Controller"] __all__ = [
"VigenereAPIOpenAPIHandler",
"Controller",
"ControllerDocs",
"Operation",
"Algorithm",
]
...@@ -73,3 +73,44 @@ class PathTypeError(VigenereAPITypeError): ...@@ -73,3 +73,44 @@ class PathTypeError(VigenereAPITypeError):
def __init__(self, path: Any) -> None: def __init__(self, path: Any) -> None:
"""Create a new PathTypeError.""" """Create a new PathTypeError."""
super().__init__(path, "path", "a string") super().__init__(path, "path", "a string")
@final
class OperationTypeError(VigenereAPITypeError):
"""Thrown if 'operation' is not an Operation object."""
def __init__(self, operation: Any) -> None:
"""Create a new OperationTypeError."""
super().__init__(operation, "operation", "an Operation object")
@final
class AlgorithmTypeError(VigenereAPITypeError):
"""Thrown if 'algorithm' is not an Algorithm object."""
def __init__(self, algorithm: Any) -> None:
"""Create a new AlgorithmTypeError."""
super().__init__(algorithm, "algorithm", "an Algorithm object")
@final
class ExamplesTypeError(VigenereAPITypeError):
"""Thrown if 'examples' is not a Sequence of CaesarData or VigenereData."""
def __init__(self, data: Any, name: str) -> None:
"""Create a new ExamplesTypeError."""
super().__init__(data, name, "a Sequence of CaesarData or VigenereData")
@final
class ExampleTypeError(TypeError):
"""Thrown if an example in 'data_examples' is not a CaesarData or VigenereData."""
def __init__(self, example: Any, name: str) -> None:
"""Create a new ExampleTypeError."""
cls_name = type(example).__qualname__
super().__init__(
f"An example is a '{cls_name}' in {name}."
+ " Please give a Sequence of CaesarData or VigenereData.",
)
...@@ -20,10 +20,11 @@ from typing import final, Final ...@@ -20,10 +20,11 @@ from typing import final, Final
from blacksheep.server.openapi.ui import ReDocUIProvider from blacksheep.server.openapi.ui import ReDocUIProvider
from blacksheep.server.openapi.v3 import OpenAPIHandler from blacksheep.server.openapi.v3 import OpenAPIHandler
from openapidocs.common import Format from openapidocs.common import Format
from openapidocs.v3 import Contact, ExternalDocs, Info, License, OpenAPI, Tag from openapidocs.v3 import Contact, ExternalDocs, Info, License, OpenAPI, Tag
from vigenere_api.version import Version from vigenere_api.version import Version
from .errors import VersionTypeError from .errors import VersionTypeError
from .open_api_route_filter import get_route_filter from .open_api_route_filter import get_route_filter
......
...@@ -21,6 +21,7 @@ from collections.abc import Callable, Collection ...@@ -21,6 +21,7 @@ from collections.abc import Callable, Collection
from blacksheep import Route from blacksheep import Route
from vigenere_api.version import Version from vigenere_api.version import Version
from .errors import ( from .errors import (
ExcludedPathsTypeError, ExcludedPathsTypeError,
ExcludedPathTypeError, ExcludedPathTypeError,
......
# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
# Vigenere-API +
# Copyright (C) 2023 Axel DAVID +
# +
# This program is free software: you can redistribute it and/or modify it under +
# the terms of the GNU General Public License as published by the Free Software +
# Foundation, either version 3 of the License, or (at your option) any later version. +
# +
# This program is distributed in the hope that it will be useful, but WITHOUT ANY +
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +
# A PARTICULAR PURPOSE. See the GNU General Public License for more details. +
# +
# You should have received a copy of the GNU General Public License along with +
# this program. If not, see <https://www.gnu.org/licenses/>. +
# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
"""A controller's documentation."""
from collections.abc import Sequence
from dataclasses import dataclass
from enum import auto, unique
from http import HTTPStatus
from typing import final, Union
from blacksheep.server.openapi.common import (
ContentInfo,
EndpointDocs,
RequestBodyInfo,
ResponseExample,
ResponseInfo,
)
from strenum import LowercaseStrEnum, PascalCaseStrEnum
from vigenere_api.models import CaesarData, VigenereData
from .errors import (
AlgorithmTypeError,
ExamplesTypeError,
ExampleTypeError,
OperationTypeError,
)
@final
@unique
class Operation(LowercaseStrEnum):
"""All Caesar or Vigenere operations."""
CIPHER = auto()
DECIPHER = auto()
@final
@unique
class Algorithm(PascalCaseStrEnum):
"""All algorithms available."""
CAESAR = auto()
VIGENERE = auto()
@dataclass
class ControllerDocs(EndpointDocs):
"""Create the documentation for Caesar algorithm."""
def __init__(
self,
operation: Operation,
algorithm: Algorithm,
data1_examples: Sequence[Union[CaesarData, VigenereData]],
data2_examples: Sequence[Union[CaesarData, VigenereData]],
) -> None:
"""
Create a ControllerDocs.
Parameters
----------
operation : Operation
The operation type.
algorithm : Algorithm
The algorithm type.
data1_examples : Sequence[Union[CaesarData, VigenereData]]
The first set of examples.
data2_examples : Sequence[Union[CaesarData, VigenereData]]
The second set of examples.
Raises
------
OperationTypeError
Thrown if 'operation' is not an Operation object.
AlgorithmTypeError
Thrown if 'algorithm' is not an Algorithm object.
ExamplesTypeError
Thrown if 'data1_examples' is not a Sequence object.
ExamplesTypeError
Thrown if 'data2_examples' is not a Sequence object.
ExampleTypeError
Thrown if 'data1_examples[i]' is not a CaesarData or VigenereData object.
ExampleTypeError
Thrown if 'data2_examples[i]' is not a CaesarData or VigenereData object.
"""
if not isinstance(operation, Operation):
raise OperationTypeError(operation)
if not isinstance(algorithm, Algorithm):
raise AlgorithmTypeError(algorithm)
if not isinstance(data1_examples, Sequence):
raise ExamplesTypeError(data1_examples, "data1_examples")
if not isinstance(data2_examples, Sequence):
raise ExamplesTypeError(data2_examples, "data2_examples")
for example in data1_examples:
if not isinstance(example, (CaesarData, VigenereData)):
raise ExampleTypeError(example, "data1_examples")
for example in data2_examples:
if not isinstance(example, (CaesarData, VigenereData)):
raise ExampleTypeError(example, "data2_examples")
response_examples = [ResponseExample(value=data) for data in data1_examples]
request_examples = {
f"example {i}": data for i, data in enumerate(data2_examples)
}
if operation == Operation.DECIPHER:
response_examples = [ResponseExample(value=data) for data in data2_examples]
request_examples = {
f"example {i}": data for i, data in enumerate(data1_examples)
}
response_type = VigenereData if algorithm == Algorithm.VIGENERE else CaesarData
ok_res = ResponseInfo(
description=f"Success {operation.value} with {algorithm} algorithm.",
content=[
ContentInfo(
type=response_type,
examples=response_examples,
),
],
)
summary_str = (
f"Apply the {algorithm} algorithm to {operation.value} the content."
)
super().__init__(
summary=summary_str,
description=(
f"Use the key with the {algorithm} algorithm"
+ f" to {operation.value} the content."
),
tags=[f"{algorithm}"],
request_body=RequestBodyInfo(
description="Examples of requests body.",
examples=request_examples,
),
responses={
HTTPStatus.OK: ok_res,
HTTPStatus.BAD_REQUEST: "Bad request.",
},
)
...@@ -18,31 +18,12 @@ ...@@ -18,31 +18,12 @@
"""The caesar controller's documentation.""" """The caesar controller's documentation."""
from dataclasses import dataclass from dataclasses import dataclass
from enum import auto, unique
from http import HTTPStatus
from typing import final from typing import final
from blacksheep.server.openapi.common import ( from vigenere_api.api.helpers.operation_docs import Algorithm, ControllerDocs, Operation
ContentInfo,
EndpointDocs,
RequestBodyInfo,
ResponseExample,
ResponseInfo,
)
from strenum import LowercaseStrEnum
from vigenere_api.models import CaesarData from vigenere_api.models import CaesarData
@final
@unique
class CaesarOperation(LowercaseStrEnum):
"""All Caesar operations."""
CIPHER = auto()
DECIPHER = auto()
CAESAR_DATA1 = ( CAESAR_DATA1 = (
CaesarData(content="DeFgHiJkLmNoPqRsTuVwXyZaBc", key=3), CaesarData(content="DeFgHiJkLmNoPqRsTuVwXyZaBc", key=3),
CaesarData(content="DeFgHiJkLmNoPqRsTuVwXyZaBc", key="D"), CaesarData(content="DeFgHiJkLmNoPqRsTuVwXyZaBc", key="D"),
...@@ -57,67 +38,19 @@ CAESAR_DATA2 = ( ...@@ -57,67 +38,19 @@ CAESAR_DATA2 = (
@final @final
@dataclass @dataclass
class CaesarControllerDocs(EndpointDocs): class CaesarControllerDocs(ControllerDocs):
"""Create the documentation for Caesar algorithm.""" """Create the documentation for Caesar algorithm."""
def __init__(self, operation: CaesarOperation) -> None: def __init__(self, operation: Operation) -> None:
""" """
Create a CaesarControllerDocs. Create a CaesarControllerDocs.
Parameters Parameters
---------- ----------
operation : CaesarOperation operation : Operation
""" """
response_examples = [ super().__init__(operation, Algorithm.CAESAR, CAESAR_DATA1, CAESAR_DATA2)
ResponseExample(value=CAESAR_DATA1[0]),
ResponseExample(value=CAESAR_DATA1[1]),
ResponseExample(value=CAESAR_DATA1[2]),
]
request_examples = {
"example 0": CAESAR_DATA2[0],
"example 1": CAESAR_DATA2[1],
"example 2": CAESAR_DATA2[2],
}
if operation == CaesarOperation.DECIPHER:
response_examples = [
ResponseExample(value=CAESAR_DATA2[0]),
ResponseExample(value=CAESAR_DATA2[1]),
ResponseExample(value=CAESAR_DATA2[2]),
]
request_examples = {
"example 0": CAESAR_DATA1[0],
"example 1": CAESAR_DATA1[1],
"example 2": CAESAR_DATA1[2],
}
super().__init__(
summary=(
"Apply the Caesar algorithm to" + f" {operation.value} the content."
),
description=(
"Use the key with the Caesar algorithm to"
+ f" {operation.value} the content."
),
tags=["Caesar"],
request_body=RequestBodyInfo(
description="Examples of requests body.",
examples=request_examples,
),
responses={
HTTPStatus.OK: ResponseInfo(
description=f"Success {operation.value} with Caesar algorithm.",
content=[
ContentInfo(
type=CaesarData,
examples=response_examples,
),
],
),
HTTPStatus.BAD_REQUEST: "Bad request.",
},
)
post_caesar_cipher_docs = CaesarControllerDocs(operation=CaesarOperation.CIPHER) post_caesar_cipher_docs = CaesarControllerDocs(operation=Operation.CIPHER)
post_caesar_decipher_docs = CaesarControllerDocs(operation=CaesarOperation.DECIPHER) post_caesar_decipher_docs = CaesarControllerDocs(operation=Operation.DECIPHER)
# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
# Vigenere-API +
# Copyright (C) 2023 Axel DAVID +
# +
# This program is free software: you can redistribute it and/or modify it under +
# the terms of the GNU General Public License as published by the Free Software +
# Foundation, either version 3 of the License, or (at your option) any later version. +
# +
# This program is distributed in the hope that it will be useful, but WITHOUT ANY +
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +
# A PARTICULAR PURPOSE. See the GNU General Public License for more details. +
# +
# You should have received a copy of the GNU General Public License along with +
# this program. If not, see <https://www.gnu.org/licenses/>. +
# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
"""Package of the second API version."""
# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
# Vigenere-API +
# Copyright (C) 2023 Axel DAVID +
# +
# This program is free software: you can redistribute it and/or modify it under +
# the terms of the GNU General Public License as published by the Free Software +
# Foundation, either version 3 of the License, or (at your option) any later version. +
# +
# This program is distributed in the hope that it will be useful, but WITHOUT ANY +
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +
# A PARTICULAR PURPOSE. See the GNU General Public License for more details. +
# +
# You should have received a copy of the GNU General Public License along with +
# this program. If not, see <https://www.gnu.org/licenses/>. +
# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
"""Controllers in the V2 API."""
from .caesar import CaesarController
from .vigenere import VigenereController
__all__ = ["CaesarController", "VigenereController"]
# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
# Vigenere-API +
# Copyright (C) 2023 Axel DAVID +
# +
# This program is free software: you can redistribute it and/or modify it under +
# the terms of the GNU General Public License as published by the Free Software +
# Foundation, either version 3 of the License, or (at your option) any later version. +
# +
# This program is distributed in the hope that it will be useful, but WITHOUT ANY +
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +
# A PARTICULAR PURPOSE. See the GNU General Public License for more details. +
# +
# You should have received a copy of the GNU General Public License along with +
# this program. If not, see <https://www.gnu.org/licenses/>. +
# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
"""CaesarController package."""
from .caesar import CaesarController
__all__ = ["CaesarController"]
# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
# Vigenere-API +
# Copyright (C) 2023 Axel DAVID +
# +
# This program is free software: you can redistribute it and/or modify it under +
# the terms of the GNU General Public License as published by the Free Software +
# Foundation, either version 3 of the License, or (at your option) any later version. +
# +
# This program is distributed in the hope that it will be useful, but WITHOUT ANY +
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +
# A PARTICULAR PURPOSE. See the GNU General Public License for more details. +
# +
# You should have received a copy of the GNU General Public License along with +
# this program. If not, see <https://www.gnu.org/licenses/>. +
# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
"""The caesar controller."""
from typing import final
from blacksheep import FromJSON, Response
from blacksheep.server.controllers import post
from vigenere_api.api.helpers import Controller
from vigenere_api.api.v1.controllers import CaesarController as V1CaesarController
from vigenere_api.api.v1.controllers.caesar.docs import (
post_caesar_cipher_docs,
post_caesar_decipher_docs,
)
from vigenere_api.api.v2.openapi_docs import docs
from vigenere_api.models import CaesarData
@final
class CaesarController(Controller):
"""
The caesar controller.
This controller calls functions of V1 controller.
Provides routes:
- POST /api/v2/caesar/cipher
- POST /api/v2/caesar/decipher
"""
@classmethod
def version(cls) -> str:
"""
Version of the API.
Returns
-------
version
str
"""
return f"v{docs.version.major}"
@docs(post_caesar_cipher_docs)
@post("cipher")
async def cipher(self, data: FromJSON[CaesarData]) -> Response:
"""
Cipher the input request with Caesar algorithm.
Parameters
----------
data : CaesarData
A CaesarData from JSON from the request body.
Returns
-------
response
Response
"""
return await V1CaesarController.cipher(self, data)
@docs(post_caesar_decipher_docs)
@post("decipher")
async def decipher(self, data: FromJSON[CaesarData]) -> Response:
"""
Decipher the input request with Caesar algorithm.
Parameters
----------
data : CaesarData
A CaesarData from JSON from the request body.
Returns
-------
response
Response
"""
return await V1CaesarController.decipher(self, data)
# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
# Vigenere-API +
# Copyright (C) 2023 Axel DAVID +
# +
# This program is free software: you can redistribute it and/or modify it under +
# the terms of the GNU General Public License as published by the Free Software +
# Foundation, either version 3 of the License, or (at your option) any later version. +
# +
# This program is distributed in the hope that it will be useful, but WITHOUT ANY +
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +
# A PARTICULAR PURPOSE. See the GNU General Public License for more details. +
# +
# You should have received a copy of the GNU General Public License along with +
# this program. If not, see <https://www.gnu.org/licenses/>. +
# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
from blacksheep import FromJSON, Response
from blacksheep.server.controllers import APIController
from vigenere_api.models import CaesarData
class CaesarController(APIController):
async def cipher(self, data: FromJSON[CaesarData]) -> Response: ...
async def decipher(self, data: FromJSON[CaesarData]) -> Response: ...
# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
# Vigenere-API +
# Copyright (C) 2023 Axel DAVID +
# +
# This program is free software: you can redistribute it and/or modify it under +
# the terms of the GNU General Public License as published by the Free Software +
# Foundation, either version 3 of the License, or (at your option) any later version. +
# +
# This program is distributed in the hope that it will be useful, but WITHOUT ANY +
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +
# A PARTICULAR PURPOSE. See the GNU General Public License for more details. +
# +
# You should have received a copy of the GNU General Public License along with +
# this program. If not, see <https://www.gnu.org/licenses/>. +
# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
"""CaesarController package."""
from .vigenere import VigenereController
__all__ = ["VigenereController"]
# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
# Vigenere-API +
# Copyright (C) 2023 Axel DAVID +
# +
# This program is free software: you can redistribute it and/or modify it under +
# the terms of the GNU General Public License as published by the Free Software +
# Foundation, either version 3 of the License, or (at your option) any later version. +
# +
# This program is distributed in the hope that it will be useful, but WITHOUT ANY +
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +
# A PARTICULAR PURPOSE. See the GNU General Public License for more details. +
# +
# You should have received a copy of the GNU General Public License along with +
# this program. If not, see <https://www.gnu.org/licenses/>. +
# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
"""The caesar controller's documentation."""
from dataclasses import dataclass
from typing import final
from vigenere_api.api.helpers import Algorithm, ControllerDocs, Operation
from vigenere_api.models import VigenereData
VIGENERE_DATA1 = (
VigenereData(content="RI ZR VXGM XFLX CWMI", key="pierre"),
VigenereData(content="ABC DAB CDA BCD ABC DAB", key="AbCd"),
VigenereData(content="Ri zr vxgm xflx cwmi!", key="PIERRE"),
VigenereData(content="AbC dab CDA bCd abc dAB", key="abcd"),
)
VIGENERE_DATA2 = (
VigenereData(content="CA VA ETRE TOUT NOIR", key="PIERRE"),
VigenereData(content="AAA AAA AAA AAA AAA AAA", key="abcd"),
VigenereData(content="Ca va etre tout noir!", key="piErrE"),
VigenereData(content="AaA aaa AAA aAa aaa aAA", key="aBCd"),
)
@final
@dataclass
class VigenereControllerDocs(ControllerDocs):
"""Create the documentation for Vigenere algorithm."""
def __init__(self, operation: Operation) -> None:
"""
Create a VigenereControllerDocs.
Parameters
----------
operation : Operation
"""
super().__init__(operation, Algorithm.VIGENERE, VIGENERE_DATA1, VIGENERE_DATA2)
post_vigenere_cipher_docs = VigenereControllerDocs(operation=Operation.CIPHER)
post_vigenere_decipher_docs = VigenereControllerDocs(operation=Operation.DECIPHER)
# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
# Vigenere-API +
# Copyright (C) 2023 Axel DAVID +
# +
# This program is free software: you can redistribute it and/or modify it under +
# the terms of the GNU General Public License as published by the Free Software +
# Foundation, either version 3 of the License, or (at your option) any later version. +
# +
# This program is distributed in the hope that it will be useful, but WITHOUT ANY +
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +
# A PARTICULAR PURPOSE. See the GNU General Public License for more details. +
# +
# You should have received a copy of the GNU General Public License along with +
# this program. If not, see <https://www.gnu.org/licenses/>. +
# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
"""The caesar controller."""
from typing import final
from blacksheep import FromJSON, Response
from blacksheep.server.controllers import post
from vigenere_api.api.helpers import Controller
from vigenere_api.api.v2.openapi_docs import docs
from vigenere_api.models import VigenereData
from .docs import post_vigenere_cipher_docs, post_vigenere_decipher_docs
@final
class VigenereController(Controller):
"""
The vigenere controller.
Provides routes:
- POST /api/v2/vigenere/cipher
- POST /api/v2/vigenere/decipher
"""
@classmethod
def version(cls) -> str:
"""
Version of the API.
Returns
-------
version
str
"""
return f"v{docs.version.major}"
@docs(post_vigenere_cipher_docs)
@post("cipher")
async def cipher(self, data: FromJSON[VigenereData]) -> Response:
"""
Cipher the input request with Vigenere algorithm.
Parameters
----------
data : VigenereData
A VigenereData from JSON from the request body.
Returns
-------
response
Response
"""
return self.json(data.value.cipher())
@docs(post_vigenere_decipher_docs)
@post("decipher")
async def decipher(self, data: FromJSON[VigenereData]) -> Response:
"""
Decipher the input request with Vigenere algorithm.
Parameters
----------
data : VigenereData
A VigenereData from JSON from the request body.
Returns
-------
response
Response
"""
return self.json(data.value.decipher())
# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
# Vigenere-API +
# Copyright (C) 2023 Axel DAVID +
# +
# This program is free software: you can redistribute it and/or modify it under +
# the terms of the GNU General Public License as published by the Free Software +
# Foundation, either version 3 of the License, or (at your option) any later version. +
# +
# This program is distributed in the hope that it will be useful, but WITHOUT ANY +
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +
# A PARTICULAR PURPOSE. See the GNU General Public License for more details. +
# +
# You should have received a copy of the GNU General Public License along with +
# this program. If not, see <https://www.gnu.org/licenses/>. +
# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
from blacksheep import FromJSON, Response
from blacksheep.server.controllers import APIController
from vigenere_api.models import VigenereData
class VigenereController(APIController):
async def cipher(self, data: FromJSON[VigenereData]) -> Response: ...
async def decipher(self, data: FromJSON[VigenereData]) -> Response: ...
# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
# Vigenere-API +
# Copyright (C) 2023 Axel DAVID +
# +
# This program is free software: you can redistribute it and/or modify it under +
# the terms of the GNU General Public License as published by the Free Software +
# Foundation, either version 3 of the License, or (at your option) any later version. +
# +
# This program is distributed in the hope that it will be useful, but WITHOUT ANY +
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +
# A PARTICULAR PURPOSE. See the GNU General Public License for more details. +
# +
# You should have received a copy of the GNU General Public License along with +
# this program. If not, see <https://www.gnu.org/licenses/>. +
# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
"""Common OpenAPI docs."""
from vigenere_api.api.helpers import VigenereAPIOpenAPIHandler
from vigenere_api.version import Version
docs = VigenereAPIOpenAPIHandler(Version(major=2, minor=0, patch=0))
# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
# Vigenere-API +
# Copyright (C) 2023 Axel DAVID +
# +
# This program is free software: you can redistribute it and/or modify it under +
# the terms of the GNU General Public License as published by the Free Software +
# Foundation, either version 3 of the License, or (at your option) any later version. +
# +
# This program is distributed in the hope that it will be useful, but WITHOUT ANY +
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +
# A PARTICULAR PURPOSE. See the GNU General Public License for more details. +
# +
# You should have received a copy of the GNU General Public License along with +
# this program. If not, see <https://www.gnu.org/licenses/>. +
# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
"""Base model."""
from __future__ import annotations
from pydantic import StrictStr, validator
from vigenere_api.helpers import Model
from .errors import ContentTypeError, EmptyContentError
class BaseData(Model):
"""Base data to verify the content."""
content: StrictStr
"""The content to be ciphered or deciphered."""
@validator("content", pre=True)
def validate_content(cls, content: str) -> str:
"""
Check if the affectation to content respects contraints.
Parameters
----------
content : str
The new content.
Raises
------
ContentTypeError
Thrown if 'content' is not a string.
EmptyContentError
Thrown if 'content' is an empty string.
Returns
-------
content
str
"""
if not isinstance(content, str):
raise ContentTypeError(content)
if len(content) == 0:
raise EmptyContentError
return content
...@@ -22,13 +22,11 @@ from typing import final, Union ...@@ -22,13 +22,11 @@ from typing import final, Union
from pydantic import StrictInt, StrictStr, validator from pydantic import StrictInt, StrictStr, validator
from vigenere_api.helpers import Model from .base_data import BaseData
from .errors import ( from .errors import (
AlgorithmExpectedKeyType, AlgorithmExpectedKeyType,
AlgorithmKeyTypeError, AlgorithmKeyTypeError,
AlgorithmTextTypeError, AlgorithmTextTypeError,
ContentTypeError,
EmptyContentError,
) )
from .helpers import convert_key, move_char from .helpers import convert_key, move_char
from .helpers.errors import ( from .helpers.errors import (
...@@ -39,11 +37,12 @@ from .helpers.errors import ( ...@@ -39,11 +37,12 @@ from .helpers.errors import (
TooLongKeyError, TooLongKeyError,
) )
Key = Union[StrictInt, StrictStr] Key = Union[StrictInt, StrictStr]
@final @final
class CaesarData(Model): class CaesarData(BaseData):
""" """
Caesar data to cipher the content or decipher. Caesar data to cipher the content or decipher.
...@@ -62,9 +61,6 @@ class CaesarData(Model): ...@@ -62,9 +61,6 @@ class CaesarData(Model):
>>> assert caesar_data.key == ciphered_data.key == deciphered_data.key == 1 >>> assert caesar_data.key == ciphered_data.key == deciphered_data.key == 1
""" """
content: StrictStr
"""The content to be ciphered or deciphered."""
key: Key key: Key
"""The key to cipher or decipher the content.""" """The key to cipher or decipher the content."""
...@@ -153,36 +149,6 @@ class CaesarData(Model): ...@@ -153,36 +149,6 @@ class CaesarData(Model):
return convert_key(self.key) return convert_key(self.key)
@validator("content", pre=True)
def validate_content(cls, content: str) -> str:
"""
Check if the affectation to content respects contraints.
Parameters
----------
content : str
The new content.
Raises
------
ContentTypeError
Thrown if 'content' is not a string.
EmptyContentError
Thrown if 'content' is an empty string.
Returns
-------
content
str
"""
if not isinstance(content, str):
raise ContentTypeError(content)
if len(content) == 0:
raise EmptyContentError
return content
@validator("key", pre=True) @validator("key", pre=True)
def validate_key(cls, key: Key) -> Key: def validate_key(cls, key: Key) -> Key:
""" """
......
...@@ -105,4 +105,11 @@ class AlgorithmOperationTypeError(VigenereAPITypeError): ...@@ -105,4 +105,11 @@ class AlgorithmOperationTypeError(VigenereAPITypeError):
"""Thrown if the operation is not a VigenereOperation object.""" """Thrown if the operation is not a VigenereOperation object."""
def __init__(self, operation: Any) -> None: def __init__(self, operation: Any) -> None:
"""
Create an AlgorithmOperationTypeError with the operation.
Parameters
----------
operation : Any
"""
super().__init__(operation, "operation", "a VigenereOperation object") super().__init__(operation, "operation", "a VigenereOperation object")
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment