Redemption join handlers

This commit is contained in:
Ben 2020-02-14 22:00:31 +00:00
parent 98c2062633
commit c1bd04fe3a
3 changed files with 205 additions and 28 deletions

View File

@ -1168,6 +1168,7 @@ CREATE TABLE redemption_code (
type VARCHAR(8) NOT NULL DEFAULT 'BLANKET',
coins INT NOT NULL DEFAULT 0,
expires TIMESTAMP DEFAULT NULL,
uses INT DEFAULT NULL,
PRIMARY KEY (id)
);
@ -1180,6 +1181,7 @@ COMMENT ON COLUMN redemption_code.code IS 'Redemption code';
COMMENT ON COLUMN redemption_code.type IS 'Code type';
COMMENT ON COLUMN redemption_code.coins IS 'Code coins amount';
COMMENT ON COLUMN redemption_code.expires IS 'Expiry date';
COMMENT ON COLUMN redemption_code.uses IS 'Number of uses';
DROP TABLE IF EXISTS redemption_book;
CREATE TABLE redemption_book (
@ -1212,24 +1214,39 @@ COMMENT ON COLUMN redemption_book_word.line IS 'Line number of page';
COMMENT ON COLUMN redemption_book_word.word_number IS 'The nth word on the line';
COMMENT ON COLUMN redemption_book_word.answer IS 'The correct word';
DROP TABLE IF EXISTS penguin_redemption;
CREATE TABLE penguin_redemption (
DROP TABLE IF EXISTS penguin_redemption_code;
CREATE TABLE penguin_redemption_code (
penguin_id INT NOT NULL,
code_id INT DEFAULT NULL,
book_id INT DEFAULT NULL,
code_id INT NOT NULL,
PRIMARY KEY (penguin_id, code_id),
CONSTRAINT penguin_redemption_ibfk_1 FOREIGN KEY (penguin_id) REFERENCES penguin (id) ON DELETE RESTRICT ON UPDATE CASCADE,
CONSTRAINT penguin_redemption_ibfk_2 FOREIGN KEY (code_id) REFERENCES redemption_code (id) ON DELETE RESTRICT ON UPDATE CASCADE,
CONSTRAINT penguin_redemption_ibfk_3 FOREIGN KEY (book_id) REFERENCES redemption_book (id) ON DELETE RESTRICT ON UPDATE CASCADE
CONSTRAINT penguin_redemption_code_ibfk_1 FOREIGN KEY (penguin_id) REFERENCES penguin (id) ON DELETE RESTRICT ON UPDATE CASCADE,
CONSTRAINT penguin_redemption_code_ibfk_2 FOREIGN KEY (code_id) REFERENCES redemption_code (id) ON DELETE RESTRICT ON UPDATE CASCADE
);
CREATE INDEX penguin_redemption_code_id ON penguin_redemption (code_id);
CREATE INDEX penguin_redemption_book_id ON penguin_redemption (book_id);
CREATE INDEX penguin_redemption_code_code_id ON penguin_redemption_code (code_id);
COMMENT ON TABLE penguin_redemption IS 'Redeemed codes';
COMMENT ON TABLE penguin_redemption_code IS 'Redeemed codes';
COMMENT ON COLUMN penguin_redemption_code.penguin_id IS 'Unique penguin ID';
COMMENT ON COLUMN penguin_redemption_code.code_id IS 'Unique code ID';
DROP TABLE IF EXISTS penguin_redemption_book;
CREATE TABLE penguin_redemption_book (
penguin_id INT NOT NULL,
book_id INT NOT NULL,
PRIMARY KEY (penguin_id, book_id),
CONSTRAINT penguin_redemption_book_ibfk_1 FOREIGN KEY (penguin_id) REFERENCES penguin (id) ON DELETE RESTRICT ON UPDATE CASCADE,
CONSTRAINT penguin_redemption_book_ibfk_2 FOREIGN KEY (book_id) REFERENCES redemption_book (id) ON DELETE RESTRICT ON UPDATE CASCADE
);
CREATE INDEX penguin_redemption_book_book_id ON penguin_redemption_book (book_id);
COMMENT ON TABLE penguin_redemption_book IS 'Redeemed book codes';
COMMENT ON COLUMN penguin_redemption_book.penguin_id IS 'Unique penguin ID';
COMMENT ON COLUMN penguin_redemption_book.book_id IS 'Unique book ID';
COMMENT ON COLUMN penguin_redemption.penguin_id IS 'Unique penguin ID';
COMMENT ON COLUMN penguin_redemption.code_id IS 'Unique code ID';
DROP TABLE IF EXISTS redemption_award_card;
CREATE TABLE redemption_award_card (

View File

@ -1,6 +1,101 @@
from houdini.data import db
class RedemptionCode(db.Model):
__tablename__ = 'redemption_code'
id = db.Column(db.Integer, primary_key=True,
server_default=db.text("nextval('\"redemption_code_id_seq\"'::regclass)"))
code = db.Column(db.String(16), nullable=False, unique=True)
type = db.Column(db.String(8), nullable=False, server_default=db.text("'BLANKET'::character varying"))
coins = db.Column(db.Integer, nullable=False, server_default=db.text("0"))
expires = db.Column(db.DateTime)
uses = db.Column(db.Integer)
def __init__(self, **kwargs):
super().__init__(**kwargs)
self._cards = set()
self._flooring = set()
self._furniture = set()
self._igloos = set()
self._items = set()
self._locations = set()
self._puffles = set()
self._puffle_items = set()
@property
def cards(self):
return self._cards
@cards.setter
def cards(self, child):
if isinstance(child, RedemptionAwardCard):
self._cards.add(child)
@property
def flooring(self):
return self._flooring
@flooring.setter
def flooring(self, child):
if isinstance(child, RedemptionAwardFlooring):
self._flooring.add(child)
@property
def furniture(self):
return self._furniture
@furniture.setter
def furniture(self, child):
if isinstance(child, RedemptionAwardFurniture):
self._furniture.add(child)
@property
def igloos(self):
return self._igloos
@igloos.setter
def igloos(self, child):
if isinstance(child, RedemptionAwardIgloo):
self._igloos.add(child)
@property
def items(self):
return self._items
@items.setter
def items(self, child):
if isinstance(child, RedemptionAwardItem):
self._items.add(child)
@property
def locations(self):
return self._locations
@locations.setter
def locations(self, child):
if isinstance(child, RedemptionAwardLocation):
self._locations.add(child)
@property
def puffles(self):
return self._puffles
@puffles.setter
def puffles(self, child):
if isinstance(child, RedemptionAwardPuffle):
self._puffles.add(child)
@property
def puffle_items(self):
return self._puffle_items
@puffle_items.setter
def puffle_items(self, child):
if isinstance(child, RedemptionAwardPuffleItem):
self._puffle_items.add(child)
class RedemptionBook(db.Model):
__tablename__ = 'redemption_book'
@ -19,17 +114,6 @@ class RedemptionBookWord(db.Model):
answer = db.Column(db.String(20), nullable=False)
class RedemptionCode(db.Model):
__tablename__ = 'redemption_code'
id = db.Column(db.Integer, primary_key=True,
server_default=db.text("nextval('\"redemption_code_id_seq\"'::regclass)"))
code = db.Column(db.String(16), nullable=False, unique=True)
type = db.Column(db.String(8), nullable=False, server_default=db.text("'BLANKET'::character varying"))
coins = db.Column(db.Integer, nullable=False, server_default=db.text("0"))
expires = db.Column(db.DateTime)
class RedemptionAwardCard(db.Model):
__tablename__ = 'redemption_award_card'
code_id = db.Column(db.ForeignKey('redemption_code.id', ondelete='CASCADE', onupdate='CASCADE'), primary_key=True,
@ -56,8 +140,8 @@ class RedemptionAwardFurniture(db.Model):
class RedemptionAwardIgloo(db.Model):
__tablename__ = 'redemption_award_igloo'
code_id = db.Column('CodeID', db.ForeignKey('redemption_code.id', ondelete='CASCADE', onupdate='CASCADE'),
primary_key=True,nullable=False)
code_id = db.Column(db.ForeignKey('redemption_code.id', ondelete='CASCADE', onupdate='CASCADE'),
primary_key=True, nullable=False)
igloo_id = db.Column(db.ForeignKey('igloo.id', ondelete='CASCADE', onupdate='CASCADE'), primary_key=True,
nullable=False)
@ -94,11 +178,19 @@ class RedemptionAwardPuffleItem(db.Model):
primary_key=True, nullable=False)
class PenguinRedemption(db.Model):
__tablename__ = 'penguin_redemption'
class PenguinRedemptionCode(db.Model):
__tablename__ = 'penguin_redemption_code'
penguin_id = db.Column(db.ForeignKey('penguin.id', ondelete='CASCADE', onupdate='CASCADE'), primary_key=True,
nullable=False)
code_id = db.Column(db.ForeignKey('redemption_code.id', ondelete='CASCADE', onupdate='CASCADE'), primary_key=True,
nullable=False, index=True)
book_id = db.Column(db.ForeignKey('redemption_book.id', ondelete='CASCADE', onupdate='CASCADE'), index=True)
class PenguinRedemptionBook(db.Model):
__tablename__ = 'penguin_redemption_book'
penguin_id = db.Column(db.ForeignKey('penguin.id', ondelete='CASCADE', onupdate='CASCADE'), primary_key=True,
nullable=False)
book_id = db.Column(db.ForeignKey('redemption_book.id', ondelete='CASCADE', onupdate='CASCADE'), primary_key=True,
nullable=False, index=True)

View File

@ -0,0 +1,68 @@
from houdini import handlers
from houdini.handlers import XTPacket
from houdini.constants import ClientType
from houdini.data import db
from houdini.data.redemption import RedemptionCode, RedemptionAwardCard, RedemptionAwardFlooring, \
RedemptionAwardFurniture, RedemptionAwardIgloo, RedemptionAwardItem, RedemptionAwardLocation,\
RedemptionAwardPuffle, RedemptionAwardPuffleItem, PenguinRedemptionBook, PenguinRedemptionCode
from datetime import datetime
@handlers.handler(XTPacket('rjs', ext='red'), pre_login=True, client=ClientType.Vanilla)
@handlers.allow_once
async def handle_join_redemption_server_vanilla(p, credentials: str, confirmation_hash: str, lang: str):
pid, _, username, login_key, rdnk, approved, rejected = credentials.split('|')
if login_key != p.login_key:
return await p.close()
tr = p.server.redis.multi_exec()
tr.setex(f'{username}.lkey', p.server.config.auth_ttl, login_key)
tr.setex(f'{username}.ckey', p.server.config.auth_ttl, confirmation_hash)
await tr.execute()
redeemed_books = await PenguinRedemptionBook.query.where(PenguinRedemptionBook.penguin_id == p.id).gino.all()
await p.send_xt('rjs', ','.join(str(redeemed_book.book_id) for redeemed_book in redeemed_books), 'houdini',
int(p.is_member))
@handlers.handler(XTPacket('rsc', ext='red'), pre_login=True)
@handlers.depends_on_packet(XTPacket('rjs', ext='red'))
async def handle_code(p, redemption_code: str):
query = RedemptionCode.load(cards=RedemptionAwardCard,
flooring=RedemptionAwardFlooring,
furniture=RedemptionAwardFurniture,
igloos=RedemptionAwardIgloo,
items=RedemptionAwardItem,
locations=RedemptionAwardLocation,
puffles=RedemptionAwardPuffle,
puffle_items=RedemptionAwardPuffleItem)\
.query.where(RedemptionCode.code == redemption_code)
code = await query.gino.first()
if code is None:
return await p.send_error(720)
if code.uses is not None:
redeemed_count = await db.select([db.func.count(PenguinRedemptionCode.code_id)]).where(
PenguinRedemptionCode.code_id == code.id).gino.scalar()
if redeemed_count >= code.uses:
return await p.send_error(721)
penguin_redeemed = await PenguinRedemptionCode.query.where((PenguinRedemptionCode.code_id == code.id) &
(PenguinRedemptionCode.penguin_id == p.id)).gino.scalar()
if penguin_redeemed:
return await p.send_error(721)
if code.expires is not None and code.expires < datetime.now():
return await p.send_error(726)
if code.type == 'CATALOG':
owned_ids = ','.join((item.item_id for item in code.items if item.item_id in p.inventory))
return await p.send_xt('rsc', 'treasurebook', 3, owned_ids, 0)
await p.send_xt('rsc', code.type, '', code.coins)