mirror of
https://github.com/solero/houdini.git
synced 2024-11-21 21:17:21 +00:00
Full support for expiring memberships
This commit is contained in:
parent
82a3753d0d
commit
f255ad112d
@ -119,6 +119,9 @@ if __name__ == '__main__':
|
||||
client_group.add_argument('-kt', '--auth-ttl', action='store', type=int, default=3000,
|
||||
help='Auth key TTL (seconds)')
|
||||
|
||||
membership_group = parser.add_argument_group('membership')
|
||||
membership_group.add_argument('--expire-membership', action='store_true', help='Should membership expire?')
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
args.port = args.port if args.port else 9875 if args.type == 'world' else 6112
|
||||
|
@ -1371,13 +1371,17 @@ COMMENT ON TABLE penguin_stamp IS 'Penguin earned stamps';
|
||||
COMMENT ON COLUMN penguin_stamp.penguin_id IS 'Stamp penguin ID';
|
||||
COMMENT ON COLUMN penguin_stamp.stamp_id IS 'Stamp ID';
|
||||
COMMENT ON COLUMN penguin_stamp.recent IS 'Is recently earned?';
|
||||
COMMENT ON COLUMN penguin_stamp.recent IS 'Is recently earned?';
|
||||
|
||||
DROP TABLE IF EXISTS penguin_membership;
|
||||
CREATE TABLE penguin_membership (
|
||||
penguin_id INT NOT NULL,
|
||||
start TIMESTAMP NOT NULL,
|
||||
expires TIMESTAMP NOT NULL,
|
||||
PRIMARY KEY(penguin_id, start, expires),
|
||||
expires TIMESTAMP DEFAULT NULL,
|
||||
start_aware BOOLEAN DEFAULT FALSE,
|
||||
expires_aware BOOLEAN DEFAULT FALSE,
|
||||
expired_aware BOOLEAN DEFAULT FALSE,
|
||||
PRIMARY KEY(penguin_id, start),
|
||||
CONSTRAINT penguin_membership_ibfk_1 FOREIGN KEY (penguin_id) REFERENCES penguin (id) ON DELETE RESTRICT ON UPDATE CASCADE
|
||||
);
|
||||
|
||||
|
@ -84,7 +84,7 @@ class PenguinStringCompiler(OrderedDict):
|
||||
'Y': PenguinStringCompiler.attribute_by_name('y'),
|
||||
'Frame': PenguinStringCompiler.attribute_by_name('frame'),
|
||||
'Member': PenguinStringCompiler.attribute_by_name('member'),
|
||||
'MemberDays': PenguinStringCompiler.attribute_by_name('membership_days'),
|
||||
'MemberDays': PenguinStringCompiler.attribute_by_name('membership_days_total'),
|
||||
'Avatar': PenguinStringCompiler.attribute_by_name('avatar'),
|
||||
'PenguinState': PenguinStringCompiler.attribute_by_name('penguin_state'),
|
||||
'PartyState': PenguinStringCompiler.attribute_by_name('party_state'),
|
||||
|
@ -148,7 +148,10 @@ class PenguinMembership(db.Model):
|
||||
penguin_id = db.Column(db.ForeignKey('penguin.id', ondelete='CASCADE', onupdate='CASCADE'), primary_key=True,
|
||||
nullable=False)
|
||||
start = db.Column(db.DateTime, primary_key=True, nullable=False)
|
||||
expires = db.Column(db.DateTime, primary_key=True, nullable=False)
|
||||
expires = db.Column(db.DateTime)
|
||||
start_aware = db.Column(db.Boolean, server_default=db.text("false"))
|
||||
expires_aware = db.Column(db.Boolean, server_default=db.text("false"))
|
||||
expired_aware = db.Column(db.Boolean, server_default=db.text("false"))
|
||||
|
||||
|
||||
class Login(db.Model):
|
||||
|
@ -43,7 +43,7 @@ async def handle_join_server(p, penguin_id: int, login_key: str):
|
||||
|
||||
await p.send_xt('lp', await p.string, p.coins, int(p.safe_chat), p.egg_timer_minutes,
|
||||
penguin_standard_time, p.age, 0, p.minutes_played,
|
||||
"membership_days", server_time_offset, int(p.opened_playercard),
|
||||
p.membership_days_remain, server_time_offset, int(p.opened_playercard),
|
||||
p.map_category, p.status_field)
|
||||
|
||||
spawn = random.choice(p.server.spawn_rooms)
|
||||
|
@ -1,11 +1,14 @@
|
||||
from houdini import handlers
|
||||
from houdini.converters import SeparatorConverter
|
||||
from houdini.handlers import XTPacket
|
||||
from houdini.data.penguin import Penguin
|
||||
from houdini.handlers.play.navigation import handle_join_server
|
||||
from houdini.data import db
|
||||
from houdini.data.penguin import Penguin, PenguinMembership
|
||||
from houdini.data.mail import PenguinPostcard
|
||||
from houdini.constants import ClientType
|
||||
|
||||
from aiocache import cached
|
||||
from datetime import datetime
|
||||
from datetime import datetime, timedelta
|
||||
import random
|
||||
import asyncio
|
||||
import time
|
||||
@ -77,6 +80,78 @@ async def server_egg_timer(server):
|
||||
await p.send_error_and_disconnect(910)
|
||||
|
||||
|
||||
MemberWarningDaysToExpiry = 14
|
||||
MemberWarningPostcardsVanilla = [122, 123]
|
||||
MemberWarningPostcardsLegacy = [163]
|
||||
MemberExpiredPostcard = 124
|
||||
MemberStartPostcardVanilla = 121
|
||||
MemberStartPostcardLegacy = 164
|
||||
|
||||
|
||||
@handlers.handler(XTPacket('j', 'js'), pre_login=True, before=handle_join_server)
|
||||
@handlers.allow_once
|
||||
async def handle_setup_membership(p):
|
||||
if not p.server.config.expire_membership or p.moderator or p.character:
|
||||
p.is_member = True
|
||||
p.membership_days_total = p.age
|
||||
return
|
||||
|
||||
membership_history = PenguinMembership.query.where(PenguinMembership.penguin_id == p.id)
|
||||
current_timestamp = datetime.now()
|
||||
postcards = []
|
||||
|
||||
warning_postcards = MemberWarningPostcardsVanilla if p.is_vanilla_client else MemberWarningPostcardsLegacy
|
||||
start_postcard = MemberStartPostcardVanilla if p.is_vanilla_client else MemberStartPostcardLegacy
|
||||
|
||||
async with db.transaction():
|
||||
async for membership_record in membership_history.gino.iterate():
|
||||
membership_recurring = membership_record.expires is None
|
||||
membership_active = membership_recurring or membership_record.expires >= current_timestamp
|
||||
|
||||
if membership_record.start < current_timestamp:
|
||||
if membership_active:
|
||||
p.is_member = True
|
||||
|
||||
if not membership_recurring:
|
||||
days_to_expiry = (membership_record.expires.date() - datetime.now().date()).days
|
||||
p.membership_days_remain = days_to_expiry
|
||||
|
||||
if days_to_expiry <= MemberWarningDaysToExpiry and not membership_record.expires_aware:
|
||||
postcards.append(dict(
|
||||
penguin_id=p.id,
|
||||
postcard_id=random.choice(warning_postcards),
|
||||
send_date=membership_record.expires - timedelta(days=MemberWarningDaysToExpiry)
|
||||
))
|
||||
await membership_record.update(expires_aware=True).apply()
|
||||
else:
|
||||
if p.membership_days_remain < 0:
|
||||
days_since_expiry = (membership_record.expires.date() - datetime.now().date()).days
|
||||
p.membership_days_remain = min(p.membership_days_remain, days_since_expiry)
|
||||
|
||||
if not membership_record.expired_aware:
|
||||
if p.is_vanilla_client:
|
||||
postcards.append(dict(
|
||||
penguin_id=p.id,
|
||||
postcard_id=MemberExpiredPostcard,
|
||||
send_date=membership_record.expires
|
||||
))
|
||||
await membership_record.update(expired_aware=True).apply()
|
||||
|
||||
if not membership_record.start_aware:
|
||||
postcards.append(dict(
|
||||
penguin_id=p.id,
|
||||
postcard_id=start_postcard,
|
||||
send_date=membership_record.start
|
||||
))
|
||||
await membership_record.update(start_aware=True).apply()
|
||||
|
||||
membership_end_date = current_timestamp if membership_active else membership_record.expires
|
||||
p.membership_days_total += (membership_end_date - membership_record.start).days
|
||||
|
||||
if postcards:
|
||||
await PenguinPostcard.insert().values(postcards).gino.status()
|
||||
|
||||
|
||||
@handlers.handler(XTPacket('u', 'h'))
|
||||
@handlers.cooldown(59)
|
||||
async def handle_heartbeat(p):
|
||||
|
@ -7,9 +7,9 @@ from houdini.data import penguin
|
||||
class Penguin(Spheniscidae, penguin.Penguin):
|
||||
|
||||
__slots__ = ['x', 'y', 'frame', 'toy', 'room', 'waddle', 'table',
|
||||
'data', 'muted', 'login_key', 'member', 'membership_days',
|
||||
'avatar', 'walking_puffle', 'permissions', 'active_quests',
|
||||
'buddy_requests', 'heartbeat', 'login_timestamp',
|
||||
'data', 'muted', 'login_key', 'is_member', 'membership_days_total',
|
||||
'membership_days_remain', 'avatar', 'walking_puffle', 'permissions',
|
||||
'active_quests', 'legacy_buddy_requests', 'heartbeat', 'login_timestamp',
|
||||
'egg_timer_minutes']
|
||||
|
||||
def __init__(self, *args):
|
||||
@ -25,8 +25,9 @@ class Penguin(Spheniscidae, penguin.Penguin):
|
||||
|
||||
self.login_key = None
|
||||
|
||||
self.member = 1
|
||||
self.membership_days = 1
|
||||
self.is_member = False
|
||||
self.membership_days_total = 0
|
||||
self.membership_days_remain = -1
|
||||
|
||||
self.avatar = None
|
||||
self.walking_puffle = None
|
||||
@ -58,6 +59,10 @@ class Penguin(Spheniscidae, penguin.Penguin):
|
||||
def safe_name(self):
|
||||
return self.safe_nickname(self.server.config.lang)
|
||||
|
||||
@property
|
||||
def member(self):
|
||||
return int(self.is_member)
|
||||
|
||||
async def join_room(self, room):
|
||||
await room.add_penguin(self)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user