1
Fork 0
mirror of https://github.com/RYGhub/royalnet.git synced 2024-11-23 19:44:20 +00:00
royalnet/wikipack/stars/api_wiki.py

233 lines
7.7 KiB
Python
Raw Normal View History

2020-06-22 01:58:55 +00:00
from typing import *
2020-06-22 15:01:28 +00:00
import datetime
2020-06-22 01:58:55 +00:00
import royalnet.constellation.api as rca
import royalnet.utils as ru
2020-06-22 15:01:28 +00:00
import royalnet.backpack.tables as rbt
2020-06-22 01:58:55 +00:00
from ..tables import *
class ApiWikiStar(rca.ApiStar):
path = "/api/wiki/v2"
tags = ["wiki"]
methods = ["GET", "POST", "PUT", "DELETE"]
parameters = {
"get": {
"page_id": "The id of the wiki page to get the details of."
},
"post": {
"category": "The category of the page.",
"title": "The title of the page.",
"contents": "The contents of the page.",
"format": "(Optional) The format of the page. Default is 'gfm' for GitHub Flavored Markdown.",
2020-06-22 16:08:09 +00:00
"role_to_view": "(Optional) The role required to view this page.\n\n"
"A * means unauthenticated users can view this page.\n\n"
"Be careful to not lock yourself out!",
"role_to_edit": "(Optional) The role required to edit this page.\n\n"
"A * means unauthenticated users can edit this page.\n\n"
"Be careful to not lock yourself out!",
2020-06-22 01:58:55 +00:00
},
"put": {
"page_id": "The id of the wiki page to create a new revision of.",
"category": "The category of the page.",
"title": "The title of the page.",
"contents": "The contents of the page.",
"format": "The format of the page. Default is 'gfm' for GitHub Flavored Markdown.",
2020-06-22 16:08:09 +00:00
"role_to_view": "The role required to view this page.\n\n"
"A * means unauthenticated users can view this page.\n\n"
"Be careful to not lock yourself out!",
"role_to_edit": "The role required to edit this page.\n\n"
"A * means unauthenticated users can edit this page.\n\n"
"Be careful to not lock yourself out!",
2020-06-22 01:58:55 +00:00
},
"delete": {
"page_id": "The id of the wiki page to delete.",
},
}
2020-06-22 15:01:28 +00:00
auth = {
"get": True,
"post": True,
"put": True,
"delete": True
}
2020-06-22 01:58:55 +00:00
@property
def default_view_role(self) -> str:
2020-06-22 16:08:09 +00:00
return self.config["roles"]["view"]
2020-06-22 01:58:55 +00:00
2020-06-22 16:08:09 +00:00
async def can_view(self, user: rbt.User, lr: WikiRevision) -> bool:
if lr.role_to_view == "*":
2020-06-22 01:58:55 +00:00
return True
if lr.role_to_view:
if lr.role_to_view in user.roles or self.admin_role in user.roles:
return True
return False
return True
@property
def default_edit_role(self) -> str:
2020-06-22 16:08:09 +00:00
return self.config["roles"]["edit"]
2020-06-22 01:58:55 +00:00
2020-06-22 16:08:09 +00:00
async def can_edit(self, user: rbt.User, lr: WikiRevision) -> bool:
if lr.role_to_edit == "*":
2020-06-22 01:58:55 +00:00
return True
if lr.role_to_edit:
if lr.role_to_edit in user.roles or self.admin_role in user.roles:
return True
return False
return True
@property
def create_role(self) -> str:
2020-06-22 16:08:09 +00:00
return self.config["roles"]["create"]
2020-06-22 01:58:55 +00:00
2020-06-22 15:01:28 +00:00
async def can_create(self, user: rbt.User) -> bool:
2020-06-22 16:08:09 +00:00
if self.create_role == "*":
return True
2020-06-22 01:58:55 +00:00
if self.create_role in user.roles or self.admin_role in user.roles:
return True
return False
@property
def delete_role(self) -> str:
2020-06-22 16:08:09 +00:00
return self.config["roles"]["delete"]
2020-06-22 01:58:55 +00:00
2020-06-22 15:01:28 +00:00
async def can_delete(self, user: rbt.User) -> bool:
2020-06-22 16:08:09 +00:00
if self.delete_role == "*":
2020-06-22 01:58:55 +00:00
return True
if self.delete_role in user.roles or self.admin_role in user.roles:
return True
return False
@property
def admin_role(self) -> str:
2020-06-22 16:08:09 +00:00
return self.config["roles"]["admin"]
2020-06-22 01:58:55 +00:00
2020-06-22 16:08:09 +00:00
async def find_lr(self, data: rca.ApiData) -> WikiRevision:
WikiRevisionT = self.alchemy.get(WikiRevision)
2020-06-22 01:58:55 +00:00
page_id = data.int("page_id")
2020-06-22 16:08:09 +00:00
lr: WikiRevision = await ru.asyncify(
data.session
.query(WikiRevisionT)
.filter_by(page_id=page_id)
.order_by(WikiRevisionT.revision_id.desc())
.first
2020-06-22 01:58:55 +00:00
)
2020-06-22 16:08:09 +00:00
if lr is None:
2020-06-22 01:58:55 +00:00
raise rca.NotFoundError(f"No page found with the id `{page_id}`.")
2020-06-22 16:08:09 +00:00
return lr
2020-06-22 01:58:55 +00:00
async def get(self, data: rca.ApiData) -> ru.JSON:
"""Get the details of a specific Wiki page."""
2020-06-22 16:08:09 +00:00
lr = await self.find_lr(data)
2020-06-22 01:58:55 +00:00
user = await data.user()
2020-06-22 16:08:09 +00:00
if not await self.can_view(user, lr):
2020-06-22 01:58:55 +00:00
raise rca.ForbiddenError(f"Viewing this page requires the `{lr.role_to_view}` role.")
return lr.json()
async def post(self, data: rca.ApiData) -> ru.JSON:
"""Create a new Wiki page."""
WikiRevisionT = self.alchemy.get(WikiRevision)
user = await data.user()
2020-06-22 16:08:09 +00:00
if not await self.can_create(user):
2020-06-22 01:58:55 +00:00
raise rca.ForbiddenError(f"Creating a new page requires the `{self.create_role}` role.")
category = data.str("category", optional=False)
title = data.str("title", optional=False)
contents = data.str("contents", optional=False)
format_ = data.str("format", optional=True)
role_to_view = data.str("role_to_view", optional=True)
role_to_edit = data.str("role_to_edit", optional=True)
nr: WikiRevision = WikiRevisionT(
category=category,
title=title,
contents=contents,
format=format_ or "gfm",
author=user,
timestamp=datetime.datetime.now(),
role_to_view=role_to_view or self.default_view_role,
role_to_edit=role_to_edit or self.default_edit_role,
)
data.session.add(nr)
2020-06-22 16:08:09 +00:00
await data.session_commit()
2020-06-22 01:58:55 +00:00
return nr.json()
async def put(self, data: rca.ApiData) -> ru.JSON:
"""Edit a specific Wiki page, creating a new revision."""
WikiRevisionT = self.alchemy.get(WikiRevision)
2020-06-22 16:08:09 +00:00
lr = await self.find_lr(data)
2020-06-22 01:58:55 +00:00
user = await data.user()
2020-06-22 16:08:09 +00:00
if not await self.can_edit(user, lr):
2020-06-22 01:58:55 +00:00
raise rca.ForbiddenError(f"Editing this page requires the `{lr.role_to_edit}` role.")
category = data.str("category", optional=True)
title = data.str("title", optional=True)
contents = data.str("contents", optional=True)
format_ = data.str("format", optional=True)
role_to_view = data.str("role_to_view", optional=True)
role_to_edit = data.str("role_to_edit", optional=True)
nr: WikiRevision = WikiRevisionT(
2020-06-22 16:08:09 +00:00
page_id=lr.page_id,
2020-06-22 01:58:55 +00:00
category=category or lr.category,
title=title or lr.title,
contents=contents or lr.contents,
format=format_ or lr.format,
author=user,
timestamp=datetime.datetime.now(),
role_to_view=role_to_view or lr.role_to_view,
role_to_edit=role_to_edit or lr.role_to_edit,
)
data.session.add(nr)
2020-06-22 16:08:09 +00:00
await data.session_commit()
2020-06-22 01:58:55 +00:00
return nr.json()
async def delete(self, data: rca.ApiData) -> ru.JSON:
"""Delete a specific Wiki page and all its revisions."""
2020-06-22 16:08:09 +00:00
WikiRevisionT = self.alchemy.get(WikiRevision)
2020-06-22 01:58:55 +00:00
WikiDeletionT = self.alchemy.get(WikiDeletion)
2020-06-22 16:08:09 +00:00
lr = await self.find_lr(data)
2020-06-22 01:58:55 +00:00
user = await data.user()
2020-06-22 16:08:09 +00:00
if not await self.can_delete(user):
2020-06-22 01:58:55 +00:00
raise rca.ForbiddenError(f"Deleting pages requires the `{self.delete_role}` role.")
deletion = WikiDeletionT(
2020-06-22 16:08:09 +00:00
page_id=lr.page_id,
2020-06-22 01:58:55 +00:00
deleted_by=user,
timestamp=datetime.datetime.now(),
)
2020-06-22 16:08:09 +00:00
pages = await ru.asyncify(
data.session.query(WikiRevisionT).filter_by(page_id=lr.page_id).all
)
data.session.delete(pages)
2020-06-22 01:58:55 +00:00
data.session.add(deletion)
2020-06-22 16:08:09 +00:00
await data.session_commit()
2020-06-22 01:58:55 +00:00
2020-06-22 15:01:28 +00:00
return deletion.json()