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', type VARCHAR(8) NOT NULL DEFAULT 'BLANKET',
coins INT NOT NULL DEFAULT 0, coins INT NOT NULL DEFAULT 0,
expires TIMESTAMP DEFAULT NULL, expires TIMESTAMP DEFAULT NULL,
uses INT DEFAULT NULL,
PRIMARY KEY (id) 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.type IS 'Code type';
COMMENT ON COLUMN redemption_code.coins IS 'Code coins amount'; COMMENT ON COLUMN redemption_code.coins IS 'Code coins amount';
COMMENT ON COLUMN redemption_code.expires IS 'Expiry date'; 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; DROP TABLE IF EXISTS redemption_book;
CREATE TABLE 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.word_number IS 'The nth word on the line';
COMMENT ON COLUMN redemption_book_word.answer IS 'The correct word'; COMMENT ON COLUMN redemption_book_word.answer IS 'The correct word';
DROP TABLE IF EXISTS penguin_redemption; DROP TABLE IF EXISTS penguin_redemption_code;
CREATE TABLE penguin_redemption ( CREATE TABLE penguin_redemption_code (
penguin_id INT NOT NULL, penguin_id INT NOT NULL,
code_id INT DEFAULT NULL, code_id INT NOT NULL,
book_id INT DEFAULT NULL,
PRIMARY KEY (penguin_id, code_id), 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_code_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_code_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
); );
CREATE INDEX penguin_redemption_code_id ON penguin_redemption (code_id); CREATE INDEX penguin_redemption_code_code_id ON penguin_redemption_code (code_id);
CREATE INDEX penguin_redemption_book_id ON penguin_redemption (book_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; DROP TABLE IF EXISTS redemption_award_card;
CREATE TABLE redemption_award_card ( CREATE TABLE redemption_award_card (

View File

@ -1,6 +1,101 @@
from houdini.data import db 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): class RedemptionBook(db.Model):
__tablename__ = 'redemption_book' __tablename__ = 'redemption_book'
@ -19,17 +114,6 @@ class RedemptionBookWord(db.Model):
answer = db.Column(db.String(20), nullable=False) 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): class RedemptionAwardCard(db.Model):
__tablename__ = 'redemption_award_card' __tablename__ = 'redemption_award_card'
code_id = db.Column(db.ForeignKey('redemption_code.id', ondelete='CASCADE', onupdate='CASCADE'), primary_key=True, code_id = db.Column(db.ForeignKey('redemption_code.id', ondelete='CASCADE', onupdate='CASCADE'), primary_key=True,
@ -56,7 +140,7 @@ class RedemptionAwardFurniture(db.Model):
class RedemptionAwardIgloo(db.Model): class RedemptionAwardIgloo(db.Model):
__tablename__ = 'redemption_award_igloo' __tablename__ = 'redemption_award_igloo'
code_id = db.Column('CodeID', db.ForeignKey('redemption_code.id', ondelete='CASCADE', onupdate='CASCADE'), code_id = db.Column(db.ForeignKey('redemption_code.id', ondelete='CASCADE', onupdate='CASCADE'),
primary_key=True, nullable=False) primary_key=True, nullable=False)
igloo_id = db.Column(db.ForeignKey('igloo.id', ondelete='CASCADE', onupdate='CASCADE'), primary_key=True, igloo_id = db.Column(db.ForeignKey('igloo.id', ondelete='CASCADE', onupdate='CASCADE'), primary_key=True,
nullable=False) nullable=False)
@ -94,11 +178,19 @@ class RedemptionAwardPuffleItem(db.Model):
primary_key=True, nullable=False) primary_key=True, nullable=False)
class PenguinRedemption(db.Model): class PenguinRedemptionCode(db.Model):
__tablename__ = 'penguin_redemption' __tablename__ = 'penguin_redemption_code'
penguin_id = db.Column(db.ForeignKey('penguin.id', ondelete='CASCADE', onupdate='CASCADE'), primary_key=True, penguin_id = db.Column(db.ForeignKey('penguin.id', ondelete='CASCADE', onupdate='CASCADE'), primary_key=True,
nullable=False) nullable=False)
code_id = db.Column(db.ForeignKey('redemption_code.id', ondelete='CASCADE', onupdate='CASCADE'), primary_key=True, code_id = db.Column(db.ForeignKey('redemption_code.id', ondelete='CASCADE', onupdate='CASCADE'), primary_key=True,
nullable=False, index=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)