mai2: add consecutive day login count, update db to v7, fix reader, courses, and docs

This commit is contained in:
Hay1tsme 2023-07-01 21:51:18 -04:00
parent a680699939
commit f279adb894
8 changed files with 115 additions and 28 deletions

View File

@ -0,0 +1 @@
DROP TABLE aime.mai2_profile_consec_logins;

View File

@ -0,0 +1,9 @@
CREATE TABLE `mai2_profile_consec_logins` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user` int(11) NOT NULL,
`version` int(11) NOT NULL,
`logins` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `mai2_profile_consec_logins_uk` (`user`,`version`),
CONSTRAINT `mai2_profile_consec_logins_ibfk_1` FOREIGN KEY (`user`) REFERENCES `aime_user` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;

View File

@ -129,30 +129,31 @@ Config file is located in `config/cxb.yaml`.
| Game Code | Version ID | Version Name | | Game Code | Version ID | Version Name |
|-----------|------------|-------------------------| |-----------|------------|-------------------------|
| SDEZ | 0 | maimai DX |
| SDEZ | 1 | maimai DX PLUS |
| SDEZ | 2 | maimai DX Splash |
| SDEZ | 3 | maimai DX Splash PLUS |
| SDEZ | 4 | maimai DX Universe |
| SDEZ | 5 | maimai DX Universe PLUS |
| SDEZ | 6 | maimai DX Festival |
For versions pre-dx For versions pre-dx
| Game Code | Version ID | Version Name | | Game Code | Version ID | Version Name |
|-----------|------------|----------------------| |-----------|------------|-------------------------|
| SBXL | 1000 | maimai | | SBXL | 0 | maimai |
| SBXL | 1001 | maimai PLUS | | SBXL | 1 | maimai PLUS |
| SBZF | 1002 | maimai GreeN | | SBZF | 2 | maimai GreeN |
| SBZF | 1003 | maimai GreeN PLUS | | SBZF | 3 | maimai GreeN PLUS |
| SDBM | 1004 | maimai ORANGE | | SDBM | 4 | maimai ORANGE |
| SDBM | 1005 | maimai ORANGE PLUS | | SDBM | 5 | maimai ORANGE PLUS |
| SDCQ | 1006 | maimai PiNK | | SDCQ | 6 | maimai PiNK |
| SDCQ | 1007 | maimai PiNK PLUS | | SDCQ | 7 | maimai PiNK PLUS |
| SDDK | 1008 | maimai MURASAKI | | SDDK | 8 | maimai MURASAKI |
| SDDK | 1009 | maimai MURASAKI PLUS | | SDDK | 9 | maimai MURASAKI PLUS |
| SDDZ | 1010 | maimai MILK | | SDDZ | 10 | maimai MILK |
| SDDZ | 1011 | maimai MILK PLUS | | SDDZ | 11 | maimai MILK PLUS |
| SDEY | 1012 | maimai FiNALE | | SDEY | 12 | maimai FiNALE |
| SDEZ | 13 | maimai DX |
| SDEZ | 14 | maimai DX PLUS |
| SDEZ | 15 | maimai DX Splash |
| SDEZ | 16 | maimai DX Splash PLUS |
| SDEZ | 17 | maimai DX Universe |
| SDEZ | 18 | maimai DX Universe PLUS |
| SDEZ | 19 | maimai DX Festival |
### Importer ### Importer

View File

@ -16,4 +16,4 @@ game_codes = [
Mai2Constants.GAME_CODE_GREEN, Mai2Constants.GAME_CODE_GREEN,
Mai2Constants.GAME_CODE, Mai2Constants.GAME_CODE,
] ]
current_schema_version = 6 current_schema_version = 7

View File

@ -140,6 +140,7 @@ class Mai2Base:
def handle_user_login_api_request(self, data: Dict) -> Dict: def handle_user_login_api_request(self, data: Dict) -> Dict:
profile = self.data.profile.get_profile_detail(data["userId"], self.version) profile = self.data.profile.get_profile_detail(data["userId"], self.version)
consec = self.data.profile.get_consec_login(data["userId"], self.version)
if profile is not None: if profile is not None:
lastLoginDate = profile["lastLoginDate"] lastLoginDate = profile["lastLoginDate"]
@ -150,12 +151,32 @@ class Mai2Base:
else: else:
loginCt = 0 loginCt = 0
lastLoginDate = "2017-12-05 07:00:00.0" lastLoginDate = "2017-12-05 07:00:00.0"
if consec is None or not consec:
consec_ct = 1
else:
lastlogindate_ = datetime.strptime(profile["lastLoginDate"], "%Y-%m-%d %H:%M:%S.%f").timestamp()
today_midnight = datetime.now().replace(hour=0, minute=0, second=0, microsecond=0).timestamp()
yesterday_midnight = today_midnight - 86400
if lastlogindate_ < today_midnight:
consec_ct = consec['logins'] + 1
self.data.profile.add_consec_login(data["userId"], self.version)
elif lastlogindate_ < yesterday_midnight:
consec_ct = 1
self.data.profile.reset_consec_login(data["userId"], self.version)
else:
consec_ct = consec['logins']
return { return {
"returnCode": 1, "returnCode": 1,
"lastLoginDate": lastLoginDate, "lastLoginDate": lastLoginDate,
"loginCount": loginCt, "loginCount": loginCt,
"consecutiveLoginCount": 0, # We don't really have a way to track this... "consecutiveLoginCount": consec_ct, # Number of consecutive days we've logged in.
} }
def handle_upload_user_playlog_api_request(self, data: Dict) -> Dict: def handle_upload_user_playlog_api_request(self, data: Dict) -> Dict:
@ -747,3 +768,9 @@ class Mai2Base:
"nextIndex": next_index, "nextIndex": next_index,
"userMusicList": [{"userMusicDetailList": music_detail_list}], "userMusicList": [{"userMusicDetailList": music_detail_list}],
} }
def handle_upload_user_portrait_api_request(self, data: Dict) -> Dict:
self.logger.debug(data)
def handle_upload_user_photo_api_request(self, data: Dict) -> Dict:
self.logger.debug(data)

View File

@ -37,7 +37,7 @@ class Mai2Reader(BaseReader):
def read(self) -> None: def read(self) -> None:
data_dirs = [] data_dirs = []
if self.version < Mai2Constants.VER_MAIMAI: if self.version >= Mai2Constants.VER_MAIMAI_DX:
if self.bin_dir is not None: if self.bin_dir is not None:
data_dirs += self.get_data_directories(self.bin_dir) data_dirs += self.get_data_directories(self.bin_dir)
@ -52,7 +52,6 @@ class Mai2Reader(BaseReader):
self.read_tickets(f"{dir}/ticket") self.read_tickets(f"{dir}/ticket")
else: else:
self.logger.warn("Pre-DX Readers are not yet implemented!")
if not os.path.exists(f"{self.bin_dir}/tables"): if not os.path.exists(f"{self.bin_dir}/tables"):
self.logger.error(f"tables directory not found in {self.bin_dir}") self.logger.error(f"tables directory not found in {self.bin_dir}")
return return

View File

@ -461,6 +461,17 @@ recent_rating = Table(
mysql_charset="utf8mb4", mysql_charset="utf8mb4",
) )
consec_logins = Table(
"mai2_profile_consec_logins",
metadata,
Column("id", Integer, primary_key=True, nullable=False),
Column("user", ForeignKey("aime_user.id", ondelete="cascade", onupdate="cascade"), nullable=False),
Column("version", Integer, nullable=False),
Column("logins", Integer),
UniqueConstraint("user", "version", name="mai2_profile_consec_logins_uk"),
mysql_charset="utf8mb4",
)
class Mai2ProfileData(BaseData): class Mai2ProfileData(BaseData):
def put_profile_detail( def put_profile_detail(
self, user_id: int, version: int, detail_data: Dict, is_dx: bool = True self, user_id: int, version: int, detail_data: Dict, is_dx: bool = True
@ -764,4 +775,43 @@ class Mai2ProfileData(BaseData):
result = self.execute(sql) result = self.execute(sql)
if result is None: if result is None:
return None return None
return result.fetchone() return result.fetchone()
def add_consec_login(self, user_id: int, version: int) -> None:
sql = insert(consec_logins).values(
user=user_id,
version=version,
logins=1
)
conflict = sql.on_duplicate_key_update(
logins=consec_logins.c.logins + 1
)
result = self.execute(conflict)
if result is None:
self.logger.error(f"Failed to update consecutive login count for user {user_id} version {version}")
def get_consec_login(self, user_id: int, version: int) -> Optional[Row]:
sql = select(consec_logins).where(and_(
consec_logins.c.user==user_id,
consec_logins.c.version==version,
))
result = self.execute(sql)
if result is None:
return None
return result.fetchone()
def reset_consec_login(self, user_id: int, version: int) -> Optional[Row]:
sql = consec_logins.update(and_(
consec_logins.c.user==user_id,
consec_logins.c.version==version,
)).values(
logins=1
)
result = self.execute(sql)
if result is None:
return None
return result.fetchone()

View File

@ -362,4 +362,4 @@ class Mai2ScoreData(BaseData):
result = self.execute(sql) result = self.execute(sql)
if result is None: if result is None:
return None return None
return result.fetchone() return result.fetchall()