Example #1
0
    def handle(self, text: str, data: str, *args, **kwargs):
        if data == 'cancel':
            cancel_supply_message(self.db_user, provider=self.provider)
            return Reply(
                text=_('Product list is cleared.'),
                next_state=SupplyState.READY_TO_POST,
            )

        if text:
            if not self.db_user.info.get(
                    UserInfoField.IS_APPROVED_SUPPLY.value):
                logger.warning(
                    'There is an attempt to post a message by user %s',
                    self.db_user.user_id)
                cancel_supply_message(self.db_user, provider=self.provider)
                return Reply(next_state=SupplyState.READY_TO_POST)

            message_id = self.db_user.editing_message_id
            set_message_time(message_id, text)
            publish_supply_event(self.db_user)
            set_message_publication_time(message_id)
            return Reply(
                text=_(
                    "Information is sent. "
                    "I'll notify you when there is someone to take this food."
                ),
                next_state=SupplyState.READY_TO_POST,
            )
Example #2
0
def _handle_take(user: User, provider_str: str, supply_user_id: str,
                 message_id: str):
    message_record = get_supply_message_record_by_id(message_id=message_id)
    supply_user = get_supply_user(supply_user_id, Provider(provider_str))

    if message_record is None or supply_user is None:
        return Reply(_('Information was not found.'))

    info = build_demand_side_full_message_text(supply_user, message_record)

    if message_record.demand_user_id:
        return build_food_taken_message(user, message_record.demand_user_id,
                                        info)

    set_next_command(
        user,
        Command(
            name=DemandCommandName.TAKE.value,
            arguments=[provider_str, supply_user_id, message_id],
        ))

    coordinates = supply_user.approved_coordinates()

    buttons = _get_review_buttons(user)

    if coordinates is not None:
        buttons.append([{
            'text':
            _('🌍 Map'),
            'data':
            DemandCommandName.MAP_TAKE.build(provider_str, supply_user_id,
                                             message_id),
        }])

    buttons.append([{
        'text':
        _('❌ Cancel'),
        'data':
        f'{DemandCommandName.SHORT_INFO.value}|'
        f'{provider_str}|{supply_user_id}|{message_id}',
    }, {
        'text':
        _('Confirm 🆗✅'),
        'data':
        f'{DemandCommandName.FINISH_TAKE.value}|'
        f'{provider_str}|{supply_user_id}|{message_id}',
    }])

    return Reply(
        text=_('%(info)s\n-----------\n%(ask_for_approve)s') % {
            'info':
            info,
            'ask_for_approve':
            _('Please, confirm/edit your contact information to proceed.'),
        },
        buttons=buttons,
    )
Example #3
0
    def get_intro(self) -> Reply:
        reply = Reply(text=self._message)
        if self.info_field_is_set():
            reply.buttons = [[{
                'text': _('Cancel'),
                'data': 'cancel',
            }]]

        return reply
Example #4
0
def _handle_info(user: User, provider_str: str, supply_user_id: str,
                 message_id: str):
    supply_user = get_user(supply_user_id,
                           provider=Provider(provider_str),
                           workflow=Workflow.SUPPLY)
    message_record = get_supply_message_record_by_id(message_id=message_id)

    if supply_user is None or message_record is None:
        return Reply(_('Information was not found.'))

    info = build_demand_side_full_message_text(supply_user, message_record)

    if message_record.demand_user_id is not None:
        return build_food_taken_message(user, message_record.demand_user_id,
                                        info)

    set_next_command(
        user,
        Command(
            name=DemandCommandName.INFO.value,
            arguments=[provider_str, supply_user_id, message_id],
        ))

    coordinates = supply_user.approved_coordinates()

    buttons = []

    if coordinates is not None:
        buttons.append([{
            'text':
            _('🌍 Map'),
            'data':
            DemandCommandName.MAP_INFO.build(provider_str, supply_user_id,
                                             message_id),
        }])

    take_it_button = {
        'text':
        _('Take it'),
        'data':
        f'{DemandCommandName.TAKE.value}|'
        f'{supply_user.provider.value}|'
        f'{supply_user.user_id}|'
        f'{message_id}',
    }
    back_button = {
        'text':
        _('Back'),
        'data':
        DemandCommandName.SHORT_INFO.build(provider_str, supply_user_id,
                                           message_id),
    }
    buttons.append([back_button, take_it_button])

    return Reply(text=info, buttons=buttons)
Example #5
0
    def handle(self, text: str, data: str, *args, **kwargs):
        if data == 'view-info':
            return Reply(next_state=SupplyState.VIEW_INFO)

        if not text:
            return

        if not self.db_user.info.get(UserInfoField.IS_APPROVED_SUPPLY.value):
            return

        create_supply_message(self.db_user, text, provider=self.provider)
        return Reply(next_state=SupplyState.POSTING)
Example #6
0
    def handle(self, text: str, data: str, *args, **kwargs):
        if data == 'set-time':
            return Reply(next_state=SupplyState.SET_TIME)

        if data == 'cancel':
            cancel_supply_message(self.db_user, provider=self.provider)
            return Reply(
                text=_('Product list is cleared.'),
                next_state=SupplyState.READY_TO_POST,
            )

        if text:
            extend_supply_message(self.db_user, text)
Example #7
0
    def _build_set_intro(self):
        reply = Reply(
            text=_('Please, send me your coordinates. (Attach -> Location)'))
        if self.info_field_is_set():
            reply.buttons = [[{
                'text': _('Cancel'),
                'data': 'cancel',
            }]]
        else:
            reply.buttons = [[{
                'text': _('Provide later'),
                'data': 'later',
            }]]

        return reply
Example #8
0
    def handle(self, text: str, data: Optional[str], *args, **kwargs):
        if data == 'edit-name':
            return Reply(next_state=SupplyState.EDIT_NAME)

        if data == 'edit-address':
            return Reply(next_state=SupplyState.EDIT_ADDRESS)

        if data == 'edit-phone':
            return Reply(next_state=SupplyState.EDIT_PHONE)

        if data == 'edit-coordinates':
            return Reply(next_state=SupplyState.EDIT_COORDINATES)

        if data == 'back':
            return Reply(next_state=SupplyState.READY_TO_POST)
Example #9
0
 def get_intro(self):
     return Reply(
         text=_('You can edit your contact info here'),
         buttons=[
             [{
                 'text': _('Name: %s') % self.db_user.info['name'],
                 'data': 'edit-name',
             }],
             [{
                 'text': _('Address: %s') % self.db_user.info['address'],
                 'data': 'edit-address',
             }],
             [{
                 'text':
                 _('Coordinates: %s') %
                 ('✅' if self.db_user.approved_coordinates() else '❌'),
                 'data':
                 'edit-coordinates',
             }],
             [{
                 'text':
                 _('Phone: %s') % (self.db_user.info['phone'] if 'phone'
                                   in self.db_user.info else '❌'),
                 'data':
                 'edit-phone',
             }, {
                 'text': _('Back'),
                 'data': 'back',
             }],
         ])
Example #10
0
class PostingState(State):
    intro = Reply(buttons=[[{
        'text': _('Set time and send'),
        'data': 'set-time',
    }, {
        'text': _('Cancel'),
        'data': 'cancel',
    }]])

    def get_intro(self):
        reply = super().get_intro()
        reply.text = _('Food you can share:\n{}').format(
            build_active_food_message(self.db_user))
        return reply

    def handle(self, text: str, data: str, *args, **kwargs):
        if data == 'set-time':
            return Reply(next_state=SupplyState.SET_TIME)

        if data == 'cancel':
            cancel_supply_message(self.db_user, provider=self.provider)
            return Reply(
                text=_('Product list is cleared.'),
                next_state=SupplyState.READY_TO_POST,
            )

        if text:
            extend_supply_message(self.db_user, text)
Example #11
0
 def process(self, serialized_data: str):
     data = json.loads(serialized_data)
     try:
         send_messages(tg_chat_id=data['chat_id'],
                       replies=[Reply(**data['reply'])],
                       workflow=Workflow(data['workflow']))
     except Exception as e:
         logger.exception('Message was not send:\n%s', data)
Example #12
0
    def build(self, message_id: str):
        coordinates = self.supply_user.approved_coordinates()

        if coordinates is None:
            logger.error('Map is requested while coordinates where not set.')
            return Reply(text=_('Coordinates where not provided.'))

        buttons = [[{
            'text':
            _('Open in app'),
            'url':
            f'https://dzmitry.by/redirect?to=geo:{coordinates[0]},{coordinates[1]}?z=21',
        }]]

        buttons.append(self._get_action_buttons(message_id))

        return Reply(coordinates=coordinates, buttons=buttons)
Example #13
0
 def handle(self, text: str, data=None, coordinates=None):
     notify_demand_for_cancel(
         supply_user=self.db_user,
         message_id=self.db_user.context['booking_to_cancel'],
         message=text)
     cancel_booking(supply_user=self.db_user,
                    message_id=self.db_user.context['booking_to_cancel'])
     return Reply(text=_('Cancelled'), next_state=SupplyState.READY_TO_POST)
Example #14
0
    def handle(self,
               text: str,
               data: Optional[str] = None,
               coordinates: Optional[tuple] = None):
        if data == 'cancel':
            return Reply(next_state=SupplyState.VIEW_INFO)

        return self.handle_text(text)
Example #15
0
def show_non_demanded_message(user, message_id: str):
    message = _('Not yet booked.\n\n%s') % build_short_message_text_by_id(
        message_id=message_id)

    return Reply(text=message,
                 buttons=[[{
                     'text': _('View all messages'),
                     'data': f'c|{SupplyCommand.LIST_MESSAGES}',
                 }]])
Example #16
0
 def get_intro(self) -> Reply:
     return Reply(text=_('What to tell the foodsaver?'),
                  buttons=[[{
                      'text':
                      _('Back to the message'),
                      'data':
                      f'c|{SupplyCommand.SHOW_DEMANDED_MESSAGE}|'
                      f'{self.db_user.context["booking_to_cancel"]}'
                  }]])
Example #17
0
def _handle_finish_take(user: User, provider_str: str, supply_user_db_id: str,
                        message_id: str):
    supply_user = get_user(supply_user_db_id,
                           provider=Provider(provider_str),
                           workflow=Workflow.SUPPLY)

    is_successfully_booked = mark_message_as_booked(demand_user=user,
                                                    message_id=message_id)

    if not is_successfully_booked:
        return Reply(text=_('Someone has already taken it.'))

    notify_supply_for_booked(supply_user=supply_user,
                             message_id=message_id,
                             demand_user=user)

    return Reply(text=_(
        "%s is notified that you'll take the food. Please, wait for approval.")
                 % supply_user.info[UserInfoField.NAME.value])
Example #18
0
def notify_supplier_is_declined(user: User):
    queue_messages(
        tg_chat_id=user.chat_id,
        workflow=Workflow.SUPPLY,
        replies=[
            Reply(text=(_(
                'Your account was declined. Please, contact %s for any clarifications.'
            ) % FEEDBACK_TG_BOT))
        ],
    )
Example #19
0
    def handle_text(self, text):
        text = text or ''
        if text.startswith('❌'):
            unset_info(self.db_user, self._info_to_edit)
            return Reply(text=_('OK ✅'), next_state=self.get_next_state())

        if text.startswith('←'):
            return Reply(text=_('OK ✅'), next_state=self.get_next_state())

        try:
            validate_phone_number(text)
        except ValidationError as e:
            return Reply(text=e.message)

        reply = super().handle_text(text)
        reply.text = _(
            'OK ✅'
        )  # Text response is required to clear telegram text keyboard.
        return reply
Example #20
0
def _handle_edit_social_status(user: User):
    buttons = [[{
        'text':
        soc_status_translation.get(x) or '~~',
        'data':
        f'{DemandCommandName.SET_SOCIAL_STATUS.value}|{x.value}',
    }] for x in SocialStatus]

    buttons.append([get_demand_back_button(user)])

    return Reply(text=_('Choose your social status:'), buttons=buttons)
Example #21
0
def build_new_supplier_notification(supply_user: User) -> Reply:
    return Reply(
        text=build_new_supplier_notification_text(supply_user),
        buttons=[[{
            'text': _('Approve'),
            'data': f'c|{SupplyCommand.APPROVE_SUPPLIER}|{supply_user.id}',
        }, {
            'text': _('Decline'),
            'data': f'c|{SupplyCommand.DECLINE_SUPPLIER}|{supply_user.id}',
        }]]
    )
Example #22
0
def approve_supplier(user: User, supplier_id: str):
    supply_user = get_user_by_id(supplier_id)
    set_info(supply_user, UserInfoField.IS_APPROVED_SUPPLY, True)
    notify_supplier_is_approved(supply_user)

    return Reply(text=build_supplier_approved_text(supply_user),
                 buttons=[[{
                     'text':
                     _('Nope, decline it'),
                     'data':
                     f'c|{SupplyCommand.DECLINE_SUPPLIER}|{supplier_id}'
                 }]])
Example #23
0
def view_messages(user):
    messages = list_messages(user)
    buttons = [
        _get_demanded_message_button(x)
        if x.demand_user_id else _get_non_demanded_message_button(x)
        for x in messages
    ]
    buttons.append([{
        'text': _('Go to product posting'),
        'data': f'c|{SupplyCommand.BACK_TO_POSTING}'
    }])
    return Reply(text=_('Last messages'), buttons=buttons)
Example #24
0
def decline_supplier(user: User, supplier_id: str):
    supply_user = get_user_by_id(supplier_id)
    set_info(supply_user, UserInfoField.IS_APPROVED_SUPPLY, False)
    notify_supplier_is_declined(supply_user)

    return Reply(text=build_supplier_declined_text(supply_user),
                 buttons=[[{
                     'text':
                     _('Sorry, approve it'),
                     'data':
                     f'c|{SupplyCommand.APPROVE_SUPPLIER}|{supplier_id}'
                 }]])
Example #25
0
def notify_supplier_is_approved(user: User):
    queue_messages(
        tg_chat_id=user.chat_id,
        workflow=Workflow.SUPPLY,
        replies=[
            Reply(text=_('Your account is approved!'),
                  buttons=[[{
                      'data': f'c|{SupplyCommand.BACK_TO_POSTING}',
                      'text': _('OK ✅'),
                  }]])
        ],
    )
Example #26
0
 def process(self, data: str):
     try:
         data = json.loads(data)
         send_messages(
             tg_chat_id=data['tg_chat_id'],
             original_message=(data['original_message']
                               and TgMessage.de_json(
                                   data['original_message'], None)),
             replies=[Reply(**x) for x in data['replies']],
             workflow=Workflow(data['workflow']),
         )
     except Exception:
         logger.exception('Message was not sent. Data:\n%s', data)
Example #27
0
 def _build_approve_intro(self):
     return Reply(
         coordinates=self.db_user.info[UserInfoField.COORDINATES.value],
         buttons=[[{
             'text': _('No! Edit! 🌍'),
             'data': 'change-coordinates',
         }], [{
             'text': _('Yes! Approve ✅'),
             'data': 'approve-coordinates',
         }], [{
             'text': _('Cancel'),
             'data': 'cancel',
         }]])
Example #28
0
    def get_intro(self) -> Reply:
        buttons = [[{
            'text': _('❌ Dismiss')
        }, {
            'text': _('Send phone'),
            'request_contact': True
        }]]

        return Reply(
            text=_('Please, send your contact number.'),
            buttons=buttons,
            is_text_buttons=True,
        )
Example #29
0
    def handle(self,
               text: str,
               data: Optional[str] = None,
               coordinates: Optional[tuple] = None):
        if data == 'change-coordinates':
            set_info(self.db_user, UserInfoField.COORDINATES, None)
            return

        if data == 'approve-coordinates':
            set_info(self.db_user, UserInfoField.IS_APPROVED_COORDINATES, True)
            return Reply(next_state=self.get_next_state())

        if data == 'later':
            set_info(self.db_user, UserInfoField.IS_APPROVED_COORDINATES, True)
            return Reply(next_state=self.get_next_state())

        if coordinates:
            set_info(self.db_user, UserInfoField.COORDINATES,
                     [str(x) for x in coordinates])
            set_info(self.db_user, UserInfoField.IS_APPROVED_COORDINATES, True)
            return Reply(next_state=self.get_next_state())

        return super().handle(text, data)
Example #30
0
class ReadyToPostState(State):
    intro = Reply(buttons=[
        [{
            'text': _('Edit restaurant info'),
            'data': 'view-info',
        }],
    ], )

    def _get_intro_text(self):
        if self.db_user.info.get(UserInfoField.IS_APPROVED_SUPPLY.value):
            return _('Enter food you can share and click "send"')

        if self.db_user.info.get(
                UserInfoField.IS_APPROVED_SUPPLY.value) is False:
            return (_(
                'Your account was declined. Please, contact %s for any clarifications.'
            ) % FEEDBACK_TG_BOT)

        notify_admin_about_new_supply_user_if_necessary(self.db_user)

        return (_(
            "We'll notify you when your account is approved. Also, you can contact us with %s"
        ) % FEEDBACK_TG_BOT)

    def get_intro(self) -> Reply:
        reply = super().get_intro()
        reply.text = self._get_intro_text()

        messages = list_messages(self.db_user)
        if messages:
            reply.buttons.append([{
                'text': _('View posted products'),
                'data': f'c|{SupplyCommand.LIST_MESSAGES}',
            }])

        return reply

    def handle(self, text: str, data: str, *args, **kwargs):
        if data == 'view-info':
            return Reply(next_state=SupplyState.VIEW_INFO)

        if not text:
            return

        if not self.db_user.info.get(UserInfoField.IS_APPROVED_SUPPLY.value):
            return

        create_supply_message(self.db_user, text, provider=self.provider)
        return Reply(next_state=SupplyState.POSTING)