Clean up possible orphan profiles for DDR Ace.
This commit is contained in:
parent
831548715c
commit
eed148f956
@ -1,13 +1,13 @@
|
||||
# vim: set fileencoding=utf-8
|
||||
import base64
|
||||
from typing import Dict, List, Optional
|
||||
from typing import Any, Dict, List, Optional, Tuple
|
||||
from typing_extensions import Final
|
||||
|
||||
from bemani.backend.ess import EventLogHandler
|
||||
from bemani.backend.ddr.base import DDRBase
|
||||
from bemani.backend.ddr.ddr2014 import DDR2014
|
||||
from bemani.common import Profile, ValidatedDict, VersionConstants, CardCipher, Time, ID, intish
|
||||
from bemani.data import Achievement, Machine, Score, UserID
|
||||
from bemani.data import Data, Achievement, Machine, Score, UserID
|
||||
from bemani.protocol import Node
|
||||
|
||||
|
||||
@ -105,6 +105,37 @@ class DDRAce(
|
||||
def previous_version(self) -> Optional[DDRBase]:
|
||||
return DDR2014(self.data, self.config, self.model)
|
||||
|
||||
@classmethod
|
||||
def run_scheduled_work(cls, data: Data, config: Dict[str, Any]) -> List[Tuple[str, Dict[str, Any]]]:
|
||||
# DDR Ace has a weird bug where it sends a profile save for a blank
|
||||
# profile before reading it back when creating a new profile. If there
|
||||
# is no profile on read-back, it errors out, and it also uses the name
|
||||
# and area ID as the takeover/succession data if the user had previous
|
||||
# data on an old game. However, if for some reason the user cancels out
|
||||
# of the name entry, loses power or disconnects from the network at the
|
||||
# right time, then the profile exists in a broken state forever until they
|
||||
# edit it on the front-end. As a work-around to this, we remember the last
|
||||
# time each profile was written to, and we look up profiles that are older
|
||||
# than a few minutes (the maximum possible time for DDR Ace to write back
|
||||
# a new profile after creating a blank one) and have blank names and delete
|
||||
# them in order to keep the profiles on the network in sane order. This
|
||||
# should normally never delete any profiles.
|
||||
profiles = data.local.user.get_all_profiles(cls.game, cls.version)
|
||||
several_minutes_ago = Time.now() - (Time.SECONDS_IN_MINUTE * 5)
|
||||
events = []
|
||||
|
||||
for userid, profile in profiles:
|
||||
if profile.get_str('name') == "" and profile.get_int('write_time') < several_minutes_ago:
|
||||
data.local.user.delete_profile(cls.game, cls.version, userid)
|
||||
events.append((
|
||||
'ddr_profile_purge',
|
||||
{
|
||||
'userid': userid,
|
||||
},
|
||||
))
|
||||
|
||||
return events
|
||||
|
||||
@property
|
||||
def supports_paseli(self) -> bool:
|
||||
if self.model.dest != 'J':
|
||||
@ -681,6 +712,7 @@ class DDRAce(
|
||||
}
|
||||
|
||||
profile.replace_dict('usergamedata', usergamedata)
|
||||
profile.replace_int('write_time', Time.now())
|
||||
self.put_profile(userid, profile)
|
||||
|
||||
playerdata.add_child(Node.s32('result', 0))
|
||||
|
@ -724,6 +724,21 @@ class UserData(BaseData):
|
||||
if profile.extid == 0:
|
||||
profile.extid = self.get_extid(game, version, userid)
|
||||
|
||||
def delete_profile(self, game: GameConstants, version: int, userid: UserID) -> None:
|
||||
"""
|
||||
Given a game/version/userid, delete any associated profile.
|
||||
|
||||
Parameters:
|
||||
game - Enum value identifier of the game looking up the user.
|
||||
version - Integer version of the game looking up the user.
|
||||
userid - Integer user ID, as looked up by one of the above functions.
|
||||
"""
|
||||
refid = self.get_refid(game, version, userid)
|
||||
|
||||
# Delete profile JSON to unlink the profile for this game/version.
|
||||
sql = "DELETE FROM profile WHERE refid = :refid LIMIT 1"
|
||||
self.execute(sql, {'refid': refid})
|
||||
|
||||
def get_achievement(self, game: GameConstants, version: int, userid: UserID, achievementid: int, achievementtype: str) -> Optional[ValidatedDict]:
|
||||
"""
|
||||
Given a game/version/userid and achievement id/type, find that achievement.
|
||||
|
@ -341,3 +341,40 @@ var PopnMusicCourseEvent = React.createClass({
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
var DDRProfilePurge = React.createClass({
|
||||
render: function() {
|
||||
var event = this.props.event;
|
||||
var username = null;
|
||||
var user = null;
|
||||
if (this.props.users) {
|
||||
if (this.props.users[event.data.userid]) {
|
||||
username = this.props.users[event.data.userid];
|
||||
}
|
||||
if (username == null) {
|
||||
user = <span className="placeholder">anonymous account</span>;
|
||||
} else {
|
||||
user = <span>{username}</span>;
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<tr key={event.id}>
|
||||
<td><Timestamp timestamp={event.timestamp} /></td>
|
||||
<td className="profilepurge">
|
||||
<div className="circle" />
|
||||
DDR Ace Profile Purge
|
||||
</td>
|
||||
<td className="details">
|
||||
{ user ?
|
||||
<div>
|
||||
<div className="inline">User:</div>
|
||||
<div className="inline"><a href={Link.get('viewuser', event.data.userid)}>{user}</a></div>
|
||||
</div> : null
|
||||
}
|
||||
<div>Orphaned DDR Ace account was purged from the network.</div>
|
||||
</td>
|
||||
</tr>
|
||||
);
|
||||
},
|
||||
});
|
||||
|
@ -10,6 +10,7 @@ var possible_events = [
|
||||
'pcbevent',
|
||||
'paseli_transaction',
|
||||
'pnm_course',
|
||||
'ddr_profile_purge',
|
||||
];
|
||||
|
||||
var event_names = {
|
||||
@ -22,6 +23,7 @@ var event_names = {
|
||||
'pnm_course': 'Pop\'n Music Course',
|
||||
'pcbevent': 'PCB Events',
|
||||
'paseli_transaction': 'PASELI Transactions',
|
||||
'ddr_profile_purge': 'DDR Ace Profile Purge',
|
||||
};
|
||||
|
||||
var mergehandler = new MergeManager(function(evt) { return evt.id; }, MergeManager.MERGE_POLICY_DROP);
|
||||
@ -176,6 +178,8 @@ var audit_events = React.createClass({
|
||||
return <PASELITransactionEvent event={event} users={this.state.users} arcades={this.state.arcades} />;
|
||||
} else if(event.type == 'pnm_course') {
|
||||
return <PopnMusicCourseEvent event={event} versions={this.state.pnmversions} songs={this.state.pnmsongs} />;
|
||||
} else if(event.type == 'ddr_profile_purge') {
|
||||
return <DDRProfilePurge event={event} users={this.state.users} />;
|
||||
} else {
|
||||
return <UnknownEvent event={event} />;
|
||||
}
|
||||
|
@ -133,3 +133,7 @@ table.events td.pcbevent div.circle {
|
||||
table.events td.transaction div.circle {
|
||||
background-color: #f9ed00;
|
||||
}
|
||||
|
||||
table.events td.profilepurge div.circle {
|
||||
background-color: rgb(214, 72, 72);
|
||||
}
|
||||
|
@ -133,3 +133,7 @@ table.events td.pcbevent div.circle {
|
||||
table.events td.transaction div.circle {
|
||||
background-color: #f9ed00;
|
||||
}
|
||||
|
||||
table.events td.profilepurge div.circle {
|
||||
background-color: rgb(214, 72, 72);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user