Skip to content

Commit

Permalink
Store a user's current value for a badge in the DB
Browse files Browse the repository at this point in the history
Signed-off-by: Aurélien Bompard <[email protected]>
  • Loading branch information
abompard committed Jul 25, 2024
1 parent 8d19683 commit b79b1d9
Show file tree
Hide file tree
Showing 3 changed files with 114 additions and 1 deletion.
60 changes: 59 additions & 1 deletion tahrir_api/dbapi.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,15 @@
from collections import OrderedDict
from datetime import datetime, timedelta, timezone

from sqlalchemy import and_, func, not_, text
from sqlalchemy import and_, func, not_, select, text
from sqlalchemy.exc import NoResultFound
from tahrir_messages import BadgeAwardV1, PersonLoginFirstV1, PersonRankAdvanceV1

from .model import (
Assertion,
Authorization,
Badge,
CurrentValue,
Invitation,
Issuer,
Milestone,
Expand Down Expand Up @@ -918,6 +920,62 @@ def add_assertion(self, badge_id, person_email, issued_on, issued_for=None):

return False

def get_current_value(self, badge_id, person_email):
"""
Return the current value for the given badge and the given person's email
:type badge_id: str
:param badge_id: The ID of the badge to query
:type person_email: str
:param person_email: The email of the person to query
"""
if not self.badge_exists(badge_id):
raise ValueError(f"No such badge {badge_id!r}")

person = self.get_person(person_email=person_email)
if person is None:
return None

query = select(CurrentValue.value).where(
CurrentValue.badge_id == badge_id,
CurrentValue.person_id == person.id,
)
try:
return self.session.scalar(query).one()
except NoResultFound:
return None

def set_current_value(self, badge_id, person_email, value):
"""Set the current value for the given badge and the given person's email
:type badge_id: str
:param badge_id: The ID of the badge to query
:type person_email: str
:param person_email: The email of the person to query
:type value: int
:param value: The value to store
"""
if not self.badge_exists(badge_id):
raise ValueError(f"No such badge {badge_id!r}")

person = self.get_person(person_email=person_email)
if person is None:
self.add_person(email=person_email)
person = self.get_person(person_email=person_email)

query = select(CurrentValue).where(
CurrentValue.badge_id == badge_id,
CurrentValue.person_id == person.id,
)
try:
current_value = self.session.scalar(query).one()
except NoResultFound:
current_value = CurrentValue(badge_id=badge_id, value=value)
person.current_values.append(current_value)
self.session.flush()
else:
current_value.value = value

def _adjust_ranks(self, person, old_rank):
"""Given a person model object and the 'old' rank of that person,
adjust the ranks of all persons between the 'old' rank and the present
Expand Down
37 changes: 37 additions & 0 deletions tahrir_api/migrations/versions/51261da641fb_currentvalue.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
"""CurrentValue
Revision ID: 51261da641fb
Revises: 3d3fb9e59e7b
Create Date: 2024-07-23 15:27:48.303528
"""

import sqlalchemy as sa
from alembic import op


# revision identifiers, used by Alembic.
revision = "51261da641fb"
down_revision = "3d3fb9e59e7b"
branch_labels = None
depends_on = None


def upgrade():
op.create_table(
"current_values",
sa.Column("badge_id", sa.Unicode(length=128), nullable=False),
sa.Column("person_id", sa.Integer(), nullable=False),
sa.Column("value", sa.Integer(), nullable=False),
sa.Column("last_update", sa.DateTime(), nullable=False),
sa.ForeignKeyConstraint(
["badge_id"], ["badges.id"], name=op.f("fk_current_values_badge_id_badges")
),
sa.ForeignKeyConstraint(
["person_id"], ["persons.id"], name=op.f("fk_current_values_person_id_persons")
),
sa.PrimaryKeyConstraint("badge_id", "person_id", name=op.f("pk_current_values")),
)


def downgrade():
op.drop_table("current_values")
18 changes: 18 additions & 0 deletions tahrir_api/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ class Badge(DeclarativeBase):
authorizations = relationship("Authorization", backref="badge")
assertions = relationship("Assertion", backref="badge")
invitations = relationship("Invitation", backref="badge")
current_values = relationship("CurrentValue", back_populates="badge")
created_on = Column(DateTime, nullable=False, default=datetime.datetime.now)
tags = Column(Unicode(128))

Expand Down Expand Up @@ -144,6 +145,7 @@ class Person(DeclarativeBase):
authorizations = relationship("Authorization", backref="person")
assertions = relationship("Assertion", backref="person")
invitations = relationship("Invitation", backref="person")
current_values = relationship("CurrentValue", back_populates="person")
nickname = Column(Unicode(128), unique=True)
website = Column(Unicode(128))
bio = Column(Unicode(140))
Expand Down Expand Up @@ -217,6 +219,22 @@ class Authorization(DeclarativeBase):
person_id = Column(Integer, ForeignKey("persons.id"), nullable=False)


class CurrentValue(DeclarativeBase):
"""The current "value" that a user has for a badge they don't yet have .
Most of the time this is going to be a message count.
"""

__tablename__ = "current_values"
badge_id = Column(Unicode(128), ForeignKey("badges.id"), primary_key=True, nullable=False)
person_id = Column(Integer, ForeignKey("persons.id"), primary_key=True, nullable=False)
value = Column(Integer, nullable=False)
last_update = Column(DateTime, nullable=False)

badge = relationship("Badge", back_populates="current_values")
person = relationship("Person", back_populates="current_values")


def recipient_default(context):
person_id = context.current_parameters["person_id"]
salt = context.current_parameters["salt"]
Expand Down

0 comments on commit b79b1d9

Please sign in to comment.