diff --git a/royalpack/commands/brawlhalla.py b/royalpack/commands/brawlhalla.py index 8f0da522..e1c7dcb4 100644 --- a/royalpack/commands/brawlhalla.py +++ b/royalpack/commands/brawlhalla.py @@ -39,7 +39,7 @@ class BrawlhallaCommand(Command): string = f"ℹ️ [b]{bh.name}[/b]\n\n" if bh.rank_1v1: - string += f"1v1: [b]{bh.rank_1v1}[/b]\n" + string += f"1v1: [b]{bh.rank_1v1}[/b] ({bh.rating_1v1} MMR)\n" return string diff --git a/royalpack/stars/__init__.py b/royalpack/stars/__init__.py index 140044c3..db781e92 100644 --- a/royalpack/stars/__init__.py +++ b/royalpack/stars/__init__.py @@ -10,6 +10,9 @@ from .api_wiki_get import ApiWikiGetStar from .api_wiki_list import ApiWikiListStar from .api_fiorygi_get import ApiFiorygiGetStar from .api_diario_random import ApiDiarioRandomStar +from .api_polls_create import ApiPollsCreate +from .api_polls_get import ApiPollsGet +from .api_polls_list import ApiPollsList # Enter the PageStars of your Pack here! available_page_stars = [ @@ -24,6 +27,9 @@ available_page_stars = [ ApiWikiListStar, ApiFiorygiGetStar, ApiDiarioRandomStar, + ApiPollsCreate, + ApiPollsGet, + ApiPollsList, ] # Don't change this, it should automatically generate __all__ diff --git a/royalpack/stars/api_polls_create.py b/royalpack/stars/api_polls_create.py new file mode 100644 index 00000000..50105ee0 --- /dev/null +++ b/royalpack/stars/api_polls_create.py @@ -0,0 +1,41 @@ +from typing import * +import datetime +import uuid +from royalnet.utils import * +from royalnet.constellation.api import * +from ..tables import Poll + + +class ApiPollsCreate(ApiStar): + path = "/api/polls/create/v1" + + summary = "Create a new poll." + + parameters = { + "question": "The question to ask in the poll.", + "description": "A longer Markdown-formatted description.", + "expires": "A ISO timestamp of the expiration date for the poll.", + } + + requires_auth = True + + methods = ["POST"] + + tags = ["polls"] + + async def api(self, data: ApiData) -> JSON: + PollT = self.alchemy.get(Poll) + + poll = PollT( + id=uuid.uuid4(), + creator=await data.user(), + created=datetime.datetime.now(), + expires=datetime.datetime.fromisoformat(data["expires"]) if "expires" in data else None, + question=data["question"], + description=data.get("description"), + ) + + data.session.add(poll) + await data.session_commit() + + return poll.json() diff --git a/royalpack/stars/api_polls_get.py b/royalpack/stars/api_polls_get.py new file mode 100644 index 00000000..4208dfa7 --- /dev/null +++ b/royalpack/stars/api_polls_get.py @@ -0,0 +1,34 @@ +from typing import * +import datetime +from royalnet.utils import * +from royalnet.constellation.api import * +from ..tables import Poll +import uuid + + +class ApiPollsGet(ApiStar): + path = "/api/polls/get/v1" + + summary = "Get the poll with a specific id." + + parameters = { + "uuid": "The UUID of the poll to get.", + } + + requires_auth = True + + tags = ["polls"] + + async def api(self, data: ApiData) -> JSON: + PollT = self.alchemy.get(Poll) + + try: + pid = uuid.UUID(data["uuid"]) + except (ValueError, AttributeError, TypeError): + raise InvalidParameterError("'uuid' is not a valid UUID.") + + poll: Poll = await asyncify(data.session.query(PollT).get, pid) + if poll is None: + raise NotFoundError("No such page.") + + return poll.json() diff --git a/royalpack/stars/api_polls_list.py b/royalpack/stars/api_polls_list.py new file mode 100644 index 00000000..3b007362 --- /dev/null +++ b/royalpack/stars/api_polls_list.py @@ -0,0 +1,28 @@ +from typing import * +from royalnet.utils import * +from royalnet.constellation.api import * +from ..tables import Poll +import uuid + + +class ApiPollsList(ApiStar): + path = "/api/polls/list/v1" + + summary = "Get a list of all polls." + + requires_auth = True + + tags = ["polls"] + + async def api(self, data: ApiData) -> JSON: + PollT = self.alchemy.get(Poll) + + polls: List[Poll] = await asyncify(data.session.query(PollT).all) + + return list(map(lambda p: { + "id": p.id, + "question": p.question, + "creator": p.creator.json(), + "expires": p.expires.isoformat(), + "created": p.created.isoformat(), + }, polls)) diff --git a/royalpack/tables/__init__.py b/royalpack/tables/__init__.py index ffd97efb..87099de9 100644 --- a/royalpack/tables/__init__.py +++ b/royalpack/tables/__init__.py @@ -10,6 +10,9 @@ from .steam import Steam from .dota import Dota from .fiorygitransactions import FiorygiTransaction from .brawlhalla import Brawlhalla +from .polls import Poll +from .pollcomments import PollComment +from .pollvotes import PollVote # Enter the tables of your Pack here! available_tables = [ @@ -24,6 +27,9 @@ available_tables = [ Dota, FiorygiTransaction, Brawlhalla, + Poll, + PollComment, + PollVote, ] # Don't change this, it should automatically generate __all__ diff --git a/royalpack/tables/pollcomments.py b/royalpack/tables/pollcomments.py new file mode 100644 index 00000000..f39851de --- /dev/null +++ b/royalpack/tables/pollcomments.py @@ -0,0 +1,41 @@ +from sqlalchemy import * +from sqlalchemy.orm import * +from sqlalchemy.ext.declarative import declared_attr +from sqlalchemy.dialects.postgresql import UUID +from ..types import PollMood + + +class PollComment: + __tablename__ = "pollcomments" + + @declared_attr + def id(self): + return Column(Integer, primary_key=True) + + @declared_attr + def author_id(self): + return Column(Integer, ForeignKey("users.uid"), nullable=False) + + @declared_attr + def author(self): + return relationship("User", backref=backref("poll_comments_created")) + + @declared_attr + def poll_id(self): + return Column(UUID(as_uuid=True), ForeignKey("polls.id")) + + @declared_attr + def poll(self): + return relationship("Poll", backref=backref("comments")) + + @declared_attr + def posted(self): + return Column(DateTime, nullable=False) + + @declared_attr + def mood(self): + return Column(Enum(PollMood), nullable=False, default=PollMood.NEUTRAL) + + @declared_attr + def comment(self): + return Column(Text) diff --git a/royalpack/tables/polls.py b/royalpack/tables/polls.py new file mode 100644 index 00000000..d45d512d --- /dev/null +++ b/royalpack/tables/polls.py @@ -0,0 +1,64 @@ +from sqlalchemy import * +from sqlalchemy.orm import * +from sqlalchemy.ext.declarative import declared_attr +from sqlalchemy.dialects.postgresql import UUID + + +class Poll: + __tablename__ = "polls" + + @declared_attr + def id(self): + return Column(UUID(as_uuid=True), primary_key=True) + + @declared_attr + def question(self): + return Column(String, nullable=False) + + @declared_attr + def description(self): + return Column(Text, nullable=False, server_default="") + + @declared_attr + def creator_id(self): + return Column(Integer, ForeignKey("users.uid")) + + @declared_attr + def creator(self): + return relationship("User", backref=backref("polls_created")) + + @declared_attr + def expires(self): + return Column(DateTime) + + @declared_attr + def created(self): + return Column(DateTime, nullable=False) + + def json(self): + return { + "id": self.id, + "question": self.question, + "description": self.description, + "creator": self.creator.json(), + "expires": self.expires.isoformat(), + "created": self.created.isoformat(), + "votes": map( + lambda v: { + "caster": v.caster.json(), + "posted": v.posted.isoformat(), + "vote": v.vote.name + }, + sorted(self.votes, key=lambda v: v.posted) + ), + "comments": map( + lambda c: { + "id": c.id, + "comment": c.comment, + "creator": c.creator.json(), + "posted": c.posted.isoformat(), + "mood": c.mood.name, + }, + sorted(self.comments, key=lambda c: c.posted) + ) + } diff --git a/royalpack/tables/pollvotes.py b/royalpack/tables/pollvotes.py new file mode 100644 index 00000000..f4886c04 --- /dev/null +++ b/royalpack/tables/pollvotes.py @@ -0,0 +1,33 @@ +from sqlalchemy import * +from sqlalchemy.orm import * +from sqlalchemy.ext.declarative import declared_attr +from ..types import PollMood +from sqlalchemy.dialects.postgresql import UUID + + +class PollVote: + __tablename__ = "pollvotes" + + @declared_attr + def caster_id(self): + return Column(Integer, ForeignKey("users.uid"), primary_key=True) + + @declared_attr + def caster(self): + return relationship("User", backref=backref("poll_votes_cast")) + + @declared_attr + def poll_id(self): + return Column(UUID(as_uuid=True), ForeignKey("polls.id"), primary_key=True) + + @declared_attr + def poll(self): + return relationship("Poll", backref=backref("votes")) + + @declared_attr + def posted(self): + return Column(DateTime, nullable=False) + + @declared_attr + def vote(self): + return Column(Enum(PollMood), nullable=False, default=PollMood.NEUTRAL) diff --git a/royalpack/types/__init__.py b/royalpack/types/__init__.py index 722f6b4e..88f28a85 100644 --- a/royalpack/types/__init__.py +++ b/royalpack/types/__init__.py @@ -9,6 +9,7 @@ from .dotarank import DotaRank from .brawlhallatier import BrawlhallaTier from .brawlhallametal import BrawlhallaMetal from .brawlhallarank import BrawlhallaRank +from .pollmood import PollMood __all__ = [ @@ -24,4 +25,5 @@ __all__ = [ "BrawlhallaMetal", "BrawlhallaRank", "BrawlhallaTier", + "PollMood", ] diff --git a/royalpack/types/pollmood.py b/royalpack/types/pollmood.py new file mode 100644 index 00000000..e5bf11d4 --- /dev/null +++ b/royalpack/types/pollmood.py @@ -0,0 +1,7 @@ +import enum + + +class PollMood(enum.Enum): + POSITIVE = 1 + NEUTRAL = 0 + NEGATIVE = -1