From a50ec8fed2c72d73649065e19b12b767a8e1d95b Mon Sep 17 00:00:00 2001 From: Innokentii Konstantinov Date: Tue, 7 Mar 2023 18:09:37 +0800 Subject: [PATCH] Refactor get_user_verbal_for_team_for_slack. (#809) Remove unused params from signature, rename --- .../renderers/slack_renderer.py | 8 ++++---- .../incident_log_builder/incident_log_builder.py | 2 +- engine/apps/alerts/models/alert_group.py | 4 ++-- .../apps/alerts/models/alert_group_log_record.py | 4 ++-- engine/apps/alerts/models/maintainable_object.py | 2 +- engine/apps/alerts/models/resolution_note.py | 2 +- .../alerts/tasks/invite_user_to_join_incident.py | 2 +- .../alerts/tests/test_alert_group_renderer.py | 6 ++---- .../user_notification_policy_log_record.py | 2 +- engine/apps/slack/models/slack_message.py | 2 +- engine/apps/slack/scenarios/distribute_alerts.py | 12 ++++++------ .../apps/slack/scenarios/escalation_delivery.py | 4 ++-- engine/apps/slack/scenarios/manual_incident.py | 2 +- .../slack/scenarios/notification_delivery.py | 2 +- engine/apps/slack/scenarios/resolution_note.py | 2 +- engine/apps/slack/scenarios/schedules.py | 16 ++++++++-------- engine/apps/slack/scenarios/step_mixins.py | 2 +- .../test_scenario_steps/test_resolution_note.py | 4 ++-- .../apps/telegram/tests/test_message_renderer.py | 6 +++--- engine/apps/user_management/models/user.py | 10 +++------- 20 files changed, 44 insertions(+), 50 deletions(-) diff --git a/engine/apps/alerts/incident_appearance/renderers/slack_renderer.py b/engine/apps/alerts/incident_appearance/renderers/slack_renderer.py index 4d82c83e..708effaf 100644 --- a/engine/apps/alerts/incident_appearance/renderers/slack_renderer.py +++ b/engine/apps/alerts/incident_appearance/renderers/slack_renderer.py @@ -339,7 +339,7 @@ class AlertGroupSlackRenderer(AlertGroupBaseRenderer): return [] buttons = [] for invitation in invitations: - invitee_name = invitation.invitee.get_user_verbal_for_team_for_slack() + invitee_name = invitation.invitee.get_username_with_slack_verbal() buttons.append( { "name": "{}_{}".format( @@ -382,7 +382,7 @@ class AlertGroupSlackRenderer(AlertGroupBaseRenderer): options = [] for user in users: - user_verbal = f"{user.get_user_verbal_for_team_for_slack()}" + user_verbal = f"{user.get_username_with_slack_verbal()}" if len(user_verbal) > 75: user_verbal = user_verbal[:72] + "..." option = {"text": {"type": "plain_text", "text": user_verbal}, "value": json.dumps({"user_id": user.pk})} @@ -413,7 +413,7 @@ class AlertGroupSlackRenderer(AlertGroupBaseRenderer): if users_count <= MAX_STATIC_SELECT_OPTIONS: initial_options = [] for user in users: - user_verbal = f"{user.get_user_verbal_for_team_for_slack()}" + user_verbal = f"{user.get_username_with_slack_verbal()}" option = { "text": {"type": "plain_text", "text": user_verbal}, "value": json.dumps({"user_id": user.pk}), @@ -421,7 +421,7 @@ class AlertGroupSlackRenderer(AlertGroupBaseRenderer): initial_options.append(option) element["initial_options"] = initial_options elif not multi_select and initial_user: - user_verbal = f"{initial_user.get_user_verbal_for_team_for_slack()}" + user_verbal = f"{initial_user.get_username_with_slack_verbal()}" initial_option = { "text": {"type": "plain_text", "text": user_verbal}, "value": json.dumps({"user_id": initial_user.pk}), diff --git a/engine/apps/alerts/incident_log_builder/incident_log_builder.py b/engine/apps/alerts/incident_log_builder/incident_log_builder.py index 3d982d4d..f3f55d58 100644 --- a/engine/apps/alerts/incident_log_builder/incident_log_builder.py +++ b/engine/apps/alerts/incident_log_builder/incident_log_builder.py @@ -579,7 +579,7 @@ class IncidentLogBuilder: """ UserNotificationPolicy = apps.get_model("base", "UserNotificationPolicy") result = "" - user_verbal = user_to_notify.get_user_verbal_for_team_for_slack() if for_slack else user_to_notify.username + user_verbal = user_to_notify.get_username_with_slack_verbal() if for_slack else user_to_notify.username if notification_policy.step == UserNotificationPolicy.Step.NOTIFY: if notification_policy.notify_by == UserNotificationPolicy.NotificationChannel.SLACK: result += f"invite {user_verbal} in Slack" diff --git a/engine/apps/alerts/models/alert_group.py b/engine/apps/alerts/models/alert_group.py index 9388a199..bf58d3d3 100644 --- a/engine/apps/alerts/models/alert_group.py +++ b/engine/apps/alerts/models/alert_group.py @@ -1574,7 +1574,7 @@ class AlertGroup(AlertGroupSlackRenderingMixin, EscalationSnapshotMixin, models. return "Resolved by stop maintenance" else: if self.resolved_by_user is not None: - user_text = self.resolved_by_user.get_user_verbal_for_team_for_slack(mention=mention_user) + user_text = self.resolved_by_user.get_username_with_slack_verbal(mention=mention_user) return f"Resolved by {user_text}" else: return "Resolved" @@ -1583,7 +1583,7 @@ class AlertGroup(AlertGroupSlackRenderingMixin, EscalationSnapshotMixin, models. if self.acknowledged_by == AlertGroup.SOURCE: return "Acknowledged by alert source" elif self.acknowledged_by == AlertGroup.USER and self.acknowledged_by_user is not None: - user_text = self.acknowledged_by_user.get_user_verbal_for_team_for_slack(mention=mention_user) + user_text = self.acknowledged_by_user.get_username_with_slack_verbal(mention=mention_user) return f"Acknowledged by {user_text}" else: return "Acknowledged" diff --git a/engine/apps/alerts/models/alert_group_log_record.py b/engine/apps/alerts/models/alert_group_log_record.py index 2f2a805e..86bdde42 100644 --- a/engine/apps/alerts/models/alert_group_log_record.py +++ b/engine/apps/alerts/models/alert_group_log_record.py @@ -246,12 +246,12 @@ class AlertGroupLogRecord(models.Model): if substitute_author_with_tag: author_name = "{{author}}" elif for_slack: - author_name = self.author.get_user_verbal_for_team_for_slack() + author_name = self.author.get_username_with_slack_verbal() else: author_name = self.author.username if self.invitation is not None: if for_slack: - invitee_name = self.invitation.invitee.get_user_verbal_for_team_for_slack() + invitee_name = self.invitation.invitee.get_username_with_slack_verbal() else: invitee_name = self.invitation.invitee.username diff --git a/engine/apps/alerts/models/maintainable_object.py b/engine/apps/alerts/models/maintainable_object.py index bfffc82b..299c59b9 100644 --- a/engine/apps/alerts/models/maintainable_object.py +++ b/engine/apps/alerts/models/maintainable_object.py @@ -78,7 +78,7 @@ class MaintainableObject(models.Model): organization = _self.get_organization() team = _self.get_team() verbal = _self.get_verbal() - user_verbal = user.get_user_verbal_for_team_for_slack() + user_verbal = user.get_username_with_slack_verbal() duration_verbal = humanize.naturaldelta(maintenance_duration) # NOTE: there could be multiple maintenance integrations in case of a race condition # (no constraints at the db level, it shouldn't be an issue functionality-wise) diff --git a/engine/apps/alerts/models/resolution_note.py b/engine/apps/alerts/models/resolution_note.py index a22b74a7..4bc8a70c 100644 --- a/engine/apps/alerts/models/resolution_note.py +++ b/engine/apps/alerts/models/resolution_note.py @@ -186,7 +186,7 @@ class ResolutionNote(models.Model): But AlertGroupPostmortem has no author field. So this method was introduces as workaround. """ if self.author is not None: - return self.author.get_user_verbal_for_team_for_slack(mention) + return self.author.get_username_with_slack_verbal(mention) else: return "" diff --git a/engine/apps/alerts/tasks/invite_user_to_join_incident.py b/engine/apps/alerts/tasks/invite_user_to_join_incident.py index 708b96ee..ecae5b8a 100644 --- a/engine/apps/alerts/tasks/invite_user_to_join_incident.py +++ b/engine/apps/alerts/tasks/invite_user_to_join_incident.py @@ -31,7 +31,7 @@ def invite_user_to_join_incident(invitation_pk): delay = Invitation.get_delay_by_attempt(invitation.attempt) - user_verbal = invitation.author.get_user_verbal_for_team_for_slack(mention=True) + user_verbal = invitation.author.get_username_with_slack_verbal(mention=True) reason = "Invitation activated by {}. Will try again in {} (attempt {}/{})".format( user_verbal, humanize.naturaldelta(delay), diff --git a/engine/apps/alerts/tests/test_alert_group_renderer.py b/engine/apps/alerts/tests/test_alert_group_renderer.py index aa7df113..72cd1fba 100644 --- a/engine/apps/alerts/tests/test_alert_group_renderer.py +++ b/engine/apps/alerts/tests/test_alert_group_renderer.py @@ -112,9 +112,7 @@ def test_get_acknowledge_text( alert_group.acknowledge(acknowledged_by=source, acknowledged_by_user=user) - assert alert_group.get_acknowledge_text() == expected_text.format( - username=user.get_user_verbal_for_team_for_slack() - ) + assert alert_group.get_acknowledge_text() == expected_text.format(username=user.get_username_with_slack_verbal()) @pytest.mark.django_db @@ -142,4 +140,4 @@ def test_get_resolved_text( alert_group.resolve(resolved_by=source, resolved_by_user=user) - assert alert_group.get_resolve_text() == expected_text.format(username=user.get_user_verbal_for_team_for_slack()) + assert alert_group.get_resolve_text() == expected_text.format(username=user.get_username_with_slack_verbal()) diff --git a/engine/apps/base/models/user_notification_policy_log_record.py b/engine/apps/base/models/user_notification_policy_log_record.py index efd8d6e1..d3c83c76 100644 --- a/engine/apps/base/models/user_notification_policy_log_record.py +++ b/engine/apps/base/models/user_notification_policy_log_record.py @@ -162,7 +162,7 @@ class UserNotificationPolicyLogRecord(models.Model): if substitute_author_with_tag: user_verbal = "{{author}}" elif for_slack: - user_verbal = self.author.get_user_verbal_for_team_for_slack() + user_verbal = self.author.get_username_with_slack_verbal() else: user_verbal = self.author.username diff --git a/engine/apps/slack/models/slack_message.py b/engine/apps/slack/models/slack_message.py index 3248508b..047c82ef 100644 --- a/engine/apps/slack/models/slack_message.py +++ b/engine/apps/slack/models/slack_message.py @@ -112,7 +112,7 @@ class SlackMessage(models.Model): def send_slack_notification(self, user, alert_group, notification_policy): UserNotificationPolicyLogRecord = apps.get_model("base", "UserNotificationPolicyLogRecord") slack_message = alert_group.get_slack_message() - user_verbal = user.get_user_verbal_for_team_for_slack(mention=True) + user_verbal = user.get_username_with_slack_verbal(mention=True) slack_user_identity = user.slack_user_identity if slack_user_identity is None: diff --git a/engine/apps/slack/scenarios/distribute_alerts.py b/engine/apps/slack/scenarios/distribute_alerts.py index 599205b0..a71a63bd 100644 --- a/engine/apps/slack/scenarios/distribute_alerts.py +++ b/engine/apps/slack/scenarios/distribute_alerts.py @@ -581,7 +581,7 @@ class CustomButtonProcessStep( debug_message = f"```{curl_request}```" if log_record.author is not None: - user_verbal = log_record.author.get_user_verbal_for_team_for_slack(mention=True) + user_verbal = log_record.author.get_username_with_slack_verbal(mention=True) text = ( f"{user_verbal} sent a request from an outgoing webhook `{log_record.custom_button.name}` " f"with the result `{result_message}`" @@ -702,7 +702,7 @@ class UnAcknowledgeGroupStep( if log_record.type == AlertGroupLogRecord.TYPE_AUTO_UN_ACK: channel_id = alert_group.slack_message.channel_id if log_record.author is not None: - user_verbal = log_record.author.get_user_verbal_for_team_for_slack(mention=True) + user_verbal = log_record.author.get_username_with_slack_verbal(mention=True) else: user_verbal = "No one" @@ -759,7 +759,7 @@ class AcknowledgeConfirmationStep(AcknowledgeGroupStep): if alert_group.acknowledged: if alert_group.acknowledged_by == AlertGroup.USER: if self.user == alert_group.acknowledged_by_user: - user_verbal = alert_group.acknowledged_by_user.get_user_verbal_for_team_for_slack() + user_verbal = alert_group.acknowledged_by_user.get_username_with_slack_verbal() text = f"{user_verbal} confirmed that the incident is still acknowledged" self._slack_client.api_call( "chat.update", @@ -777,7 +777,7 @@ class AcknowledgeConfirmationStep(AcknowledgeGroupStep): text="This alert is acknowledged by another user. Acknowledge it yourself first.", ) elif alert_group.acknowledged_by == AlertGroup.SOURCE: - user_verbal = self.user.get_user_verbal_for_team_for_slack() + user_verbal = self.user.get_username_with_slack_verbal() text = f"{user_verbal} confirmed that the incident is still acknowledged" self._slack_client.api_call( "chat.update", @@ -806,7 +806,7 @@ class AcknowledgeConfirmationStep(AcknowledgeGroupStep): alert_group = log_record.alert_group channel_id = alert_group.slack_message.channel_id - user_verbal = log_record.author.get_user_verbal_for_team_for_slack(mention=True) + user_verbal = log_record.author.get_username_with_slack_verbal(mention=True) text = f"{user_verbal}, please confirm that you're still working on this incident." if alert_group.channel.organization.unacknowledge_timeout != Organization.UNACKNOWLEDGE_TIMEOUT_NEVER: @@ -885,7 +885,7 @@ class WipeGroupStep(scenario_step.ScenarioStep): def process_signal(self, log_record): alert_group = log_record.alert_group - user_verbal = log_record.author.get_user_verbal_for_team_for_slack() + user_verbal = log_record.author.get_username_with_slack_verbal() text = f"Wiped by {user_verbal}" self.alert_group_slack_service.publish_message_to_alert_group_thread(alert_group, text=text) self.alert_group_slack_service.update_alert_group_slack_message(alert_group) diff --git a/engine/apps/slack/scenarios/escalation_delivery.py b/engine/apps/slack/scenarios/escalation_delivery.py index 1c8e7572..d0dc4c3c 100644 --- a/engine/apps/slack/scenarios/escalation_delivery.py +++ b/engine/apps/slack/scenarios/escalation_delivery.py @@ -13,8 +13,8 @@ class EscalationDeliveryStep(scenario_step.ScenarioStep): UserNotificationPolicy = apps.get_model("base", "UserNotificationPolicy") notification_channel = notification_policy.notify_by notification_step = notification_policy.step - user_verbal = user.get_user_verbal_for_team_for_slack() - user_verbal_with_mention = user.get_user_verbal_for_team_for_slack(mention=True) + user_verbal = user.get_username_with_slack_verbal() + user_verbal_with_mention = user.get_username_with_slack_verbal(mention=True) if ( notification_channel == UserNotificationPolicy.NotificationChannel.SLACK diff --git a/engine/apps/slack/scenarios/manual_incident.py b/engine/apps/slack/scenarios/manual_incident.py index f3251f0a..0b3dbbb7 100644 --- a/engine/apps/slack/scenarios/manual_incident.py +++ b/engine/apps/slack/scenarios/manual_incident.py @@ -122,7 +122,7 @@ class FinishCreateIncidentFromMessage(scenario_step.ScenarioStep): link_to_upstream_details=None, alert_receive_channel=alert_receive_channel, raw_request_data=payload, - integration_unique_data={"created_by": user.get_user_verbal_for_team_for_slack()}, + integration_unique_data={"created_by": user.get_username_with_slack_verbal()}, force_route_id=selected_route.pk, ) diff --git a/engine/apps/slack/scenarios/notification_delivery.py b/engine/apps/slack/scenarios/notification_delivery.py index f45edb77..49c5645d 100644 --- a/engine/apps/slack/scenarios/notification_delivery.py +++ b/engine/apps/slack/scenarios/notification_delivery.py @@ -12,7 +12,7 @@ class NotificationDeliveryStep(scenario_step.ScenarioStep): user = log_record.author alert_group = log_record.alert_group - user_verbal_with_mention = user.get_user_verbal_for_team_for_slack(mention=True) + user_verbal_with_mention = user.get_username_with_slack_verbal(mention=True) # move message generation to UserNotificationPolicyLogRecord if log_record.type == UserNotificationPolicyLogRecord.TYPE_PERSONAL_NOTIFICATION_FAILED: diff --git a/engine/apps/slack/scenarios/resolution_note.py b/engine/apps/slack/scenarios/resolution_note.py index 50af3e80..02bff31b 100644 --- a/engine/apps/slack/scenarios/resolution_note.py +++ b/engine/apps/slack/scenarios/resolution_note.py @@ -492,7 +492,7 @@ class ResolutionNoteModalStep(CheckAlertIsUnarchivedMixin, scenario_step.Scenari ) for message in resolution_note_slack_messages[: self.RESOLUTION_NOTE_MESSAGES_MAX_COUNT]: - user_verbal = message.user.get_user_verbal_for_team_for_slack(mention=True) + user_verbal = message.user.get_username_with_slack_verbal(mention=True) blocks.append( { "type": "divider", diff --git a/engine/apps/slack/scenarios/schedules.py b/engine/apps/slack/scenarios/schedules.py index 606fbc30..4bdb81f8 100644 --- a/engine/apps/slack/scenarios/schedules.py +++ b/engine/apps/slack/scenarios/schedules.py @@ -157,7 +157,7 @@ class EditScheduleShiftNotifyStep(scenario_step.ScenarioStep): user_ids.extend(item.get("users", [])) prev_users = organization.users.filter(id__in=user_ids) users_verbal = " ".join( - [f"{user.get_user_verbal_for_team_for_slack(mention=True)}" for user in prev_users] + [f"{user.get_username_with_slack_verbal(mention=True)}" for user in prev_users] ) now_text = f"No one on-call now! Inviting prev shift: {users_verbal}\n" else: @@ -228,12 +228,12 @@ class EditScheduleShiftNotifyStep(scenario_step.ScenarioStep): now_text = "_*Now*_:\n" if schedule.mention_oncall_start: - user_mention = current_user.get_user_verbal_for_team_for_slack( + user_mention = current_user.get_username_with_slack_verbal( mention=True, ) else: - user_mention = current_user.get_user_verbal_for_team_for_slack( + user_mention = current_user.get_username_with_slack_verbal( mention=False, ) now_text += f"*{user_mention}*" @@ -244,11 +244,11 @@ class EditScheduleShiftNotifyStep(scenario_step.ScenarioStep): next_piece, next_user = next_shift next_text = "\n_*Next*_:\n" if schedule.mention_oncall_next: - user_mention = next_user.get_user_verbal_for_team_for_slack( + user_mention = next_user.get_username_with_slack_verbal( mention=True, ) else: - user_mention = next_user.get_user_verbal_for_team_for_slack( + user_mention = next_user.get_username_with_slack_verbal( mention=False, ) next_text += f"*{user_mention}*" @@ -286,8 +286,8 @@ class EditScheduleShiftNotifyStep(scenario_step.ScenarioStep): def get_ical_shift_notification_text(cls, shift, mention, users): if shift["all_day"]: - notification = " ".join([f"{user.get_user_verbal_for_team_for_slack(mention=mention)}" for user in users]) - user_verbal = shift["users"][0].get_user_verbal_for_team_for_slack( + notification = " ".join([f"{user.get_username_with_slack_verbal(mention=mention)}" for user in users]) + user_verbal = shift["users"][0].get_username_with_slack_verbal( mention=False, ) if shift["start"].day == shift["end"].day: @@ -302,7 +302,7 @@ class EditScheduleShiftNotifyStep(scenario_step.ScenarioStep): shift_end_timestamp = int(shift["end"].astimezone(pytz.UTC).timestamp()) notification = ( - " ".join([f"{user.get_user_verbal_for_team_for_slack(mention=mention)}" for user in users]) + " ".join([f"{user.get_username_with_slack_verbal(mention=mention)}" for user in users]) + f" from {format_datetime_to_slack(shift_start_timestamp)}" f" to {format_datetime_to_slack(shift_end_timestamp)}\n" ) diff --git a/engine/apps/slack/scenarios/step_mixins.py b/engine/apps/slack/scenarios/step_mixins.py index ee322761..199cde11 100644 --- a/engine/apps/slack/scenarios/step_mixins.py +++ b/engine/apps/slack/scenarios/step_mixins.py @@ -41,7 +41,7 @@ class IncidentActionsAccessControlMixin(AccessControl): text = "Attempted to {} by {}, but failed due to a lack of permissions.".format( self.ACTION_VERBOSE, - self.user.get_user_verbal_for_team_for_slack(), + self.user.get_username_with_slack_verbal(), ) self._slack_client.api_call( diff --git a/engine/apps/slack/tests/test_scenario_steps/test_resolution_note.py b/engine/apps/slack/tests/test_scenario_steps/test_resolution_note.py index 8a3a98a7..75bf823f 100644 --- a/engine/apps/slack/tests/test_scenario_steps/test_resolution_note.py +++ b/engine/apps/slack/tests/test_scenario_steps/test_resolution_note.py @@ -72,7 +72,7 @@ def test_get_resolution_notes_blocks_non_empty( "text": { "type": "mrkdwn", "text": "{} \n{}".format( - resolution_note.user.get_user_verbal_for_team_for_slack(mention=True), + resolution_note.user.get_username_with_slack_verbal(mention=True), float(resolution_note.ts), resolution_note.text, ), @@ -149,7 +149,7 @@ def test_get_resolution_notes_blocks_latest_limit( "text": { "type": "mrkdwn", "text": "{} \n{}".format( - m.user.get_user_verbal_for_team_for_slack(mention=True), + m.user.get_username_with_slack_verbal(mention=True), float(m.ts), m.text, ), diff --git a/engine/apps/telegram/tests/test_message_renderer.py b/engine/apps/telegram/tests/test_message_renderer.py index 02a9b6a8..b2ef56b0 100644 --- a/engine/apps/telegram/tests/test_message_renderer.py +++ b/engine/apps/telegram/tests/test_message_renderer.py @@ -40,7 +40,7 @@ def test_log_message( make_alert_group_log_record, ): organization, user = make_organization_and_user() - user_name = user.get_user_verbal_for_team_for_slack(organization) + user_name = user.get_username_with_slack_verbal() alert_receive_channel = make_alert_receive_channel( organization, integration=AlertReceiveChannel.INTEGRATION_GRAFANA, verbal_name="Test integration" @@ -90,7 +90,7 @@ def test_log_message_too_long_is_trimmed( make_alert_group_log_record, ): organization, user = make_organization_and_user() - user_name = user.get_user_verbal_for_team_for_slack(organization) + user_name = user.get_username_with_slack_verbal() alert_receive_channel = make_alert_receive_channel( organization, integration=AlertReceiveChannel.INTEGRATION_GRAFANA, verbal_name="Test integration" @@ -139,7 +139,7 @@ def test_personal_message( make_alert, ): organization, user = make_organization_and_user() - user_name = user.get_user_verbal_for_team_for_slack(organization) + user_name = user.get_username_with_slack_verbal() alert_receive_channel = make_alert_receive_channel( organization, integration=AlertReceiveChannel.INTEGRATION_GRAFANA, verbal_name="Test integration" diff --git a/engine/apps/user_management/models/user.py b/engine/apps/user_management/models/user.py index 2bfb7998..ecd1b395 100644 --- a/engine/apps/user_management/models/user.py +++ b/engine/apps/user_management/models/user.py @@ -221,11 +221,8 @@ class User(models.Model): def is_notification_allowed(self): return user_is_authorized(self, [RBACPermission.Permissions.NOTIFICATIONS_READ]) - # using in-memory cache instead of redis to avoid pickling python objects - # @timed_lru_cache(timeout=100) - def get_user_verbal_for_team_for_slack(self, amixr_team=None, slack_team_identity=None, mention=False): + def get_username_with_slack_verbal(self, mention=False): slack_verbal = None - verbal = self.username if self.slack_user_identity: slack_verbal = ( @@ -235,10 +232,9 @@ class User(models.Model): ) if slack_verbal: - slack_verbal_str = f" ({slack_verbal})" - verbal = f"{verbal}{slack_verbal_str}" + return f"{self.username} ({slack_verbal})" - return verbal + return self.username @property def timezone(self):