commit 3b7676de671c9b78250f05ff95c03f4174985464 Author: Stefano Pigozzi Date: Sun Jun 21 16:38:25 2020 +0200 Initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..353da69f --- /dev/null +++ b/.gitignore @@ -0,0 +1,13 @@ +# Royalnet ignores +config*.toml +downloads/ + + +# Python ignores +**/__pycache__/ +dist/ +*.egg-info/ +**/*.pyc + +# PyCharm ignores +.idea/ diff --git a/README.md b/README.md new file mode 100644 index 00000000..a988ebbf --- /dev/null +++ b/README.md @@ -0,0 +1,5 @@ +# `examplepack` + +This is an example Pack for [Royalnet](https://github.com/Steffo99/royalnet)! + +> To be updated with more info on how to create your own pack. \ No newline at end of file diff --git a/examplepack/commands/__init__.py b/examplepack/commands/__init__.py new file mode 100644 index 00000000..c9ffb60c --- /dev/null +++ b/examplepack/commands/__init__.py @@ -0,0 +1,12 @@ +# Imports go here! +# TODO: If you create a new command, remember to import it here... +# from .example import ExampleCommand + +# Enter the commands of your Pack here! +# TODO: and add it to the list here! +available_commands = [ + # ExampleCommand, +] + +# Don't change this, it should automatically generate __all__ +__all__ = [command.__name__ for command in available_commands] diff --git a/examplepack/commands/example.py b/examplepack/commands/example.py new file mode 100644 index 00000000..f98652ba --- /dev/null +++ b/examplepack/commands/example.py @@ -0,0 +1,12 @@ +from typing import * +from royalnet.commands import * +from royalnet.utils import * + + +class ExampleCommand(Command): + name: str = "example" + + description: str = "Say Hello to the world!" + + async def run(self, args: CommandArgs, data: CommandData) -> None: + await data.reply("Hello world!") diff --git a/examplepack/events/__init__.py b/examplepack/events/__init__.py new file mode 100644 index 00000000..8bafb696 --- /dev/null +++ b/examplepack/events/__init__.py @@ -0,0 +1,12 @@ +# Imports go here! +# TODO: If you create a new event, remember to import it here... +# from .example import ExampleEvent + +# Enter the commands of your Pack here! +# TODO: and add it to the list here! +available_events = [ + # ExampleEvent, +] + +# Don't change this, it should automatically generate __all__ +__all__ = [command.__name__ for command in available_events] diff --git a/examplepack/events/example.py b/examplepack/events/example.py new file mode 100644 index 00000000..866abc7a --- /dev/null +++ b/examplepack/events/example.py @@ -0,0 +1,10 @@ +from typing import * +from royalnet.commands import * +from royalnet.utils import * + + +class ExampleEvent(Event): + name = "example" + + async def run(self, **kwargs) -> dict: + return {"hello": "world"} diff --git a/examplepack/stars/__init__.py b/examplepack/stars/__init__.py new file mode 100644 index 00000000..8193b6d8 --- /dev/null +++ b/examplepack/stars/__init__.py @@ -0,0 +1,14 @@ +# Imports go here! +# TODO: If you create a new star, remember to import it here... +# from .example import ExampleStar +# from .api_example import ApiExampleStar + +# Enter the PageStars of your Pack here! +# TODO: and to add it either to the list here if it is a PageStar... +available_page_stars = [ + # ExampleStar, + # ApiExampleStar, +] + +# Don't change this, it should automatically generate __all__ +__all__ = [command.__name__ for command in available_page_stars] diff --git a/examplepack/stars/api_example.py b/examplepack/stars/api_example.py new file mode 100644 index 00000000..80b03165 --- /dev/null +++ b/examplepack/stars/api_example.py @@ -0,0 +1,70 @@ +import royalnet.utils as ru +import royalnet.constellation.api as rca +import royalnet.constellation.api.apierrors as rcae + + +# View autogenerated docs for all ApiStars at the HTTP path `/docs` + + +class EchoStar(rca.ApiStar): + # What does this ApiStar do? + summary = "Returns the same string entered as input." + + # Optional: A longer description of what the ApiStar should do. + description = """ + NOTE: This method can only be used by Royalnet Admins. + """ + + # The HTTP methods that can be used with this ApiStar. + methods = ["GET", "POST"] + # You can disambiguate between methods using the `data.method` variable. + + # The HTTP path this ApiStar should bind to. + path = "/api/example/echo/v1" + + # Does this method require any auth? + # Only for documentation purposes, it doesn't do any check on it's own. + requires_auth = True + # To authenticate an user through their token, use the `await data.user()` method. + # If the user isn't logged in, the method authomatically returns 403 Forbidden, unless `rcae.ForbiddenError` + # is caught. + + # A dict of paramenters accepted by this method, with a description of their purpose. + parameters = { + "echo": "What should the method return? " + "(Optional: if nothing is passed, the ApiStar will return the username of the caller.)", + "error": "Should the method return a sample error?" + } + # You can access parameters by using `data` as a dict with the parameter name as key. + # If a missing parameter is accessed, a `rcae.MissingParameterError` will be raised, which will lead to a + # 400 Bad Request error if not caught. + + # The autodoc categories this ApiStar should fall in. + tags = ["example"] + + # The actual method called when the ApiStar received a HTTP request. + # It must return a JSON-compatible object, such as a str, a int, a float, a list, a dict or None. + async def api(self, data: rca.ApiData) -> ru.JSON: + + # If "true" is passed as the "error" parameter in the query string... + if data["error"] == "true": + # ...return an example error + raise Exception("Example error! Everything works as intended.") + # If the "error" parameter is missing, the ApiStar will respond with 400 Bad Request + + # Ensure the user is logged in + user = await data.user() + # Check if the user has the role "admin" + if "admin" not in user.roles: + raise Exception("Only admins can call this method!") + + # Get the value of the "echo" parameter, without raising an exception if it doesn't exist + echo = data.get("echo") + + if echo is None: + # Find the username of the logged in user + # user is a SQLAlchemy ORM object generated from the Users table defined in `royalnet.backpack.tables.users` + echo = user.username + + # Return a 200 OK successful response containing the value of the echo variable and the HTTP method used + return {"echo": echo, "method_used": data.method} diff --git a/examplepack/stars/example.py b/examplepack/stars/example.py new file mode 100644 index 00000000..6b044cea --- /dev/null +++ b/examplepack/stars/example.py @@ -0,0 +1,11 @@ +from starlette.requests import Request +from starlette.responses import * +from royalnet.constellation import * +from royalnet.utils import * + + +class ExampleStar(PageStar): + path = "/example" + + async def page(self, request: Request) -> JSONResponse: + return HTMLResponse("""

henlo!

""") diff --git a/examplepack/tables/__init__.py b/examplepack/tables/__init__.py new file mode 100644 index 00000000..e417ff16 --- /dev/null +++ b/examplepack/tables/__init__.py @@ -0,0 +1,10 @@ +# Imports go here! +# from .example import Example + +# Enter the tables of your Pack here! +available_tables = [ + # Example +] + +# Don't change this, it should automatically generate __all__ +__all__ = [table.__name__ for table in available_tables] diff --git a/examplepack/tables/example.py b/examplepack/tables/example.py new file mode 100644 index 00000000..83078e7e --- /dev/null +++ b/examplepack/tables/example.py @@ -0,0 +1,19 @@ +from sqlalchemy import * +from sqlalchemy.orm import * +from sqlalchemy.ext.declarative import declared_attr + + +class Example: + __tablename__ = "examples" + + @declared_attr + def creator_id(self): + return Column(Integer, ForeignKey("users.uid"), primary_key=True) + + @declared_attr + def creator(self): + return relationship("User", backref=backref("examples_createdx")) + + @declared_attr + def example(self): + return Column(String, nullable=False, default="Hello world!") diff --git a/examplepack/version.py b/examplepack/version.py new file mode 100644 index 00000000..422feb95 --- /dev/null +++ b/examplepack/version.py @@ -0,0 +1,2 @@ +# TODO: Increment this every new version of your pack! +semantic = "0.1.0" diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 00000000..cc9bf31d --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,58 @@ +# Remember to run `poetry update` after you edit this file! + +[tool.poetry] + # TODO: Insert here your Pack name! + name = "examplepack" + # TODO: Insert here your Pack description! + description = "An example pack for Royalnet." + # TODO: Increment this every new version of your pack! + version = "0.1.0" + # TODO: Set this to your full name and email! + authors = ["Name Surname "] + # TODO: Set this to the license you want to use for your Pack! + license = "" + # TODO: Set this to the GitHub page of your pack (or another website) + homepage = "https://github.com/your-username/" + # TODO: Set this to a link to the Pack documentation (if there's any) + documentation = "https://gh.steffo.eu/royalpack/" + # TODO: Pick some classifiers to include your Pack in: https://pypi.org/classifiers/ + classifiers = [ + "Development Status :: 3 - Alpha", + "Operating System :: OS Independent", + "Programming Language :: Python :: 3.8", + "License :: OSI Approved :: GNU Affero General Public License v3 or later (AGPLv3+)" + ] + readme = "README.md" + +# Library dependencies +[tool.poetry.dependencies] + python = "^3.8" + + [tool.poetry.dependencies.royalnet] + version = "^5.1.6" + # TODO: select the Royalnet modules required by your pack + extras = [ + "telegram", + "discord", + "alchemy_easy", + "bard", + "constellation", + "sentry", + "herald", + "coloredlogs" + ] + +# Development dependencies +[tool.poetry.dev-dependencies] + + + +# Optional dependencies +[tool.poetry.extras] + + +# Poetry stuff +# Leave it alone! +[build-system] + requires = ["poetry>=0.12"] + build-backend = "poetry.masonry.api"