From d0d1fca2ba5337095b953e0f83dba8cf7a2ec3a8 Mon Sep 17 00:00:00 2001 From: Egor Tensin Date: Fri, 17 Jun 2016 03:12:51 +0300 Subject: add the platform a user was "last seen" using --- vk/user.py | 69 ++++++++++++++++++++++++++++++++++++++++-- vk/utils/tracking/db/record.py | 58 ++++++++++++++++++++--------------- vk/utils/tracking/logger.py | 13 +++++--- 3 files changed, 108 insertions(+), 32 deletions(-) (limited to 'vk') diff --git a/vk/user.py b/vk/user.py index 4c8c71f..80702f6 100644 --- a/vk/user.py +++ b/vk/user.py @@ -7,6 +7,7 @@ from collections.abc import Hashable, Mapping, MutableMapping from datetime import datetime, timezone from enum import Enum from numbers import Real, Integral +import re class UserField(Enum): UID = 'uid' @@ -21,10 +22,54 @@ class UserField(Enum): class LastSeenField(Enum): TIME = 'time' + PLATFORM = 'platform' def __str__(self): return self.value +class Platform(Enum): + MOBILE = 1 + IPHONE = 2 + IPAD = 3 + ANDROID = 4 + WINDOWS_PHONE = 5 + WINDOWS8 = 6 + WEB = 7 + + def from_string(s): + return Platform(int(s)) + + def __str__(self): + return str(self.value) + + @staticmethod + def _uppercase_first_letter(s): + m = re.search(r'\w', s) + if m is None: + return s + return s[:m.start()] + m.group().upper() + s[m.end():] + + def get_description_for_header(self): + return self._uppercase_first_letter(_PLATFORM_DESCRIPTIONS[self]) + + def get_description_for_sentence(self): + s = _PLATFORM_DESCRIPTIONS[self] + s = s.replace('unrecognized', 'an unrecognized') + return 'the ' + s + + def get_description_for_sentence_beginning(self): + return self._uppercase_first_letter(self.get_description_for_sentence()) + +_PLATFORM_DESCRIPTIONS = { + Platform.MOBILE: '"mobile" web version (or unrecognized mobile app)', + Platform.IPHONE: 'official iPhone app', + Platform.IPAD: 'official iPad app', + Platform.ANDROID: 'official Android app', + Platform.WINDOWS_PHONE: 'official Windows Phone app', + Platform.WINDOWS8: 'official Windows 8 app', + Platform.WEB: 'web version (or unrecognized app)' +} + class LastSeen(MutableMapping): @staticmethod def from_api_response(source): @@ -71,8 +116,17 @@ class LastSeen(MutableMapping): else: raise TypeError() + def _parse_platform(x): + if x in Platform: + return x + if isinstance(x, str): + return Platform.from_string(x) + else: + return Platform(x) + _FIELD_PARSERS = { LastSeenField.TIME: _parse_time, + LastSeenField.PLATFORM: _parse_platform, } _DEFAULT_FIELD_PARSER = str @@ -86,6 +140,15 @@ class LastSeen(MutableMapping): def set_time(self, t): self[LastSeenField.TIME] = t + def has_platform(self): + return LastSeenField.PLATFORM in self + + def get_platform(self): + return self[LastSeenField.PLATFORM] + + def set_platform(self, platform): + self[LastSeenField.PLATFORM] = platform + class User(Hashable, MutableMapping): @staticmethod def from_api_response(source): @@ -195,11 +258,11 @@ class User(Hashable, MutableMapping): def set_last_seen(self, last_seen): self[UserField.LAST_SEEN] = last_seen - def get_last_seen_time(self): - return self.has_last_seen() and self.get_last_seen().has_time() - def get_last_seen_time(self): return self[UserField.LAST_SEEN].get_time() def get_last_seen_time_local(self): return self[UserField.LAST_SEEN].get_time().astimezone() + + def get_last_seen_platform(self): + return self[UserField.LAST_SEEN].get_platform() diff --git a/vk/utils/tracking/db/record.py b/vk/utils/tracking/db/record.py index 4748a37..fd684cc 100644 --- a/vk/utils/tracking/db/record.py +++ b/vk/utils/tracking/db/record.py @@ -6,7 +6,7 @@ from collections import OrderedDict from collections.abc import MutableMapping from datetime import datetime, timezone -from vk.user import LastSeen, User, UserField +from vk.user import LastSeen, LastSeenField, User, UserField class Timestamp: @staticmethod @@ -28,23 +28,14 @@ class Timestamp: dt = self._new() dt = dt.replace(microsecond=0) dt = self._lose_timezone(dt) - self._dt = dt + self.dt = dt @staticmethod def from_string(s): return Timestamp(datetime.strptime(s, '%Y-%m-%dT%H:%M:%SZ')) def __str__(self): - return self._dt.isoformat() + 'Z' - - @staticmethod - def from_last_seen(ls): - return Timestamp(ls.get_time()) - - def to_last_seen(self): - ls = LastSeen() - ls.set_time(self._dt) - return ls + return self.dt.isoformat() + 'Z' class Record(MutableMapping): FIELDS = ( @@ -53,7 +44,8 @@ class Record(MutableMapping): UserField.LAST_NAME, UserField.SCREEN_NAME, UserField.ONLINE, - UserField.LAST_SEEN, + LastSeenField.TIME, + LastSeenField.PLATFORM, ) def __init__(self, timestamp=None, fields=None): @@ -65,21 +57,26 @@ class Record(MutableMapping): self._fields = fields def __getitem__(self, field): - if field is UserField.LAST_SEEN: - return Timestamp.from_last_seen(self._fields[field]) + if field is LastSeenField.TIME: + return Timestamp(self._fields[field]) return self._fields[field] def __setitem__(self, field, value): - if field is UserField.LAST_SEEN: + if field is LastSeenField.TIME: if isinstance(value, str): - value = Timestamp.from_string(value).to_last_seen() + value = Timestamp.from_string(value).dt elif isinstance(value, Timestamp): - value = value.to_last_seen() - elif isinstance(value, LastSeen): + value = value.dt + elif isinstance(value, datetime): pass else: raise TypeError() - self._fields[field] = User.parse(field, value) + if isinstance(field, LastSeenField): + self._fields[field] = LastSeen.parse(field, value) + elif isinstance(field, UserField): + self._fields[field] = User.parse(field, value) + else: + raise TypeError() def __delitem__(self, field): del self._fields[field] @@ -95,13 +92,26 @@ class Record(MutableMapping): @staticmethod def from_user(user): - instance = Record() + record = Record() for field in Record.FIELDS: - instance[field] = user[field] - return instance + if isinstance(field, UserField): + record[field] = user[field] + elif isinstance(field, LastSeenField): + record[field] = user.get_last_seen()[field] + else: + assert False + return record def to_user(self): user = User() + last_seen = LastSeen() for field in self: - user[field] = self[field] + if isinstance(field, LastSeenField): + last_seen[field] = self[field] + elif isinstance(field, UserField): + user[field] = self[field] + else: + assert False + if len(last_seen): + user.set_last_seen(last_seen) return user diff --git a/vk/utils/tracking/logger.py b/vk/utils/tracking/logger.py index a36e679..8da418a 100644 --- a/vk/utils/tracking/logger.py +++ b/vk/utils/tracking/logger.py @@ -42,20 +42,23 @@ class Logger: @staticmethod def _format_user_is_online(user): - return '{} is ONLINE'.format(Logger._format_user(user)) + return '{} is ONLINE.'.format(Logger._format_user(user)) @staticmethod def _format_user_is_offline(user): - return '{} is OFFLINE'.format(Logger._format_user(user)) + return '{} is OFFLINE.'.format(Logger._format_user(user)) @staticmethod def _format_user_last_seen(user): - return '{} was last seen at {}'.format(Logger._format_user(user), user.get_last_seen_time_local()) + return '{} was last seen at {} using {}.'.format( + Logger._format_user(user), + user.get_last_seen_time_local(), + user.get_last_seen_platform().get_description_for_sentence()) @staticmethod def _format_user_went_online(user): - return '{} went ONLINE'.format(Logger._format_user(user)) + return '{} went ONLINE.'.format(Logger._format_user(user)) @staticmethod def _format_user_went_offline(user): - return '{} went OFFLINE'.format(Logger._format_user(user)) + return '{} went OFFLINE.'.format(Logger._format_user(user)) -- cgit v1.2.3