Example #1
0
    def test_reminder_message_is_not_created_if_member_has_pending_labaccess_days(
            self):
        member = self.db.create_member()
        self.db.create_span(type=Span.LABACCESS,
                            enddate=self.date(LABACCESS_REMINDER_DAYS_BEFORE))
        p0_count = 1

        expected_sum = self.p0_price * p0_count
        cart = [
            {
                "id": self.p0_id,
                "count": p0_count
            },
        ]

        transaction = create_transaction(member_id=member.member_id,
                                         purchase=dict(
                                             cart=cart,
                                             expected_sum=expected_sum),
                                         stripe_reference_id="not_used")
        transaction.status = Transaction.COMPLETED
        db_session.add(transaction)
        db_session.flush()

        self.send_labaccess()

        self.assertEqual(0, db_session.query(Message).count())
Example #2
0
def register_permissions(permissions):
    for permission in permissions:
        try:
            db_session.add(Permission(permission=permission))
            db_session.commit()
        except IntegrityError:
            db_session.rollback()
Example #3
0
def answer_question(question_id):
    data = request.json
    option_id = int(data["option_id"])

    option = db_session \
        .query(QuizQuestionOption) \
        .join(QuizQuestionOption.question) \
        .filter((QuizQuestion.id == question_id) & (QuizQuestionOption.id == option_id) & (QuizQuestionOption.deleted_at == None)) \
        .one_or_none()
    if option == None:
        return (
            400,
            f"Option id {option_id} is not an option for question id {question_id}"
        )

    db_session.add(
        QuizAnswer(question_id=question_id,
                   option_id=option_id,
                   member_id=g.user_id,
                   correct=option.correct))
    db_session.flush()

    question = db_session.query(QuizQuestion).get(question_id)
    json = quiz_question_entity.to_obj(question)
    json["options"] = []
    for option in question.options:
        option = quiz_question_option_entity.to_obj(option)
        json["options"].append(option)

    return json
Example #4
0
def create_action_required_response(transaction, payment_intent):
    """ The payment_intent requires customer action to be confirmed. Create response to client"""

    try:
        db_session.add(
            StripePending(transaction_id=transaction.id,
                          stripe_token=payment_intent.id))

        if payment_intent.next_action.type == PaymentIntentNextActionType.USE_STRIPE_SDK:
            return dict(type=PaymentIntentNextActionType.USE_STRIPE_SDK,
                        client_secret=payment_intent.client_secret)

        elif payment_intent.next_action.type == PaymentIntentNextActionType.REDIRECT_TO_URL:
            raise InternalServerError(
                log=
                f"unexpected next_action type, {payment_intent.next_action.type}"
            )

        else:
            raise PaymentFailed(
                log=
                f"unknown next_action type, {payment_intent.next_action.type}")

    except Exception:
        # Fail transaction on all known and unknown errors to be safe, we won't charge a failed transaction.
        commit_fail_transaction(transaction)
        logger.info(
            f"failing transaction {transaction.id}, due to error when processing 3ds card"
        )
        raise
Example #5
0
def send_message(template: MessageTemplate,
                 member,
                 db_session=None,
                 render_template=None,
                 **kwargs):

    if render_template is None:
        from flask import render_template

    subject = render_template(
        f"{template.value}.subject.html",
        public_url=get_public_url,
        member=member,
        **kwargs,
    )

    body = render_template(
        f"{template.value}.body.html",
        public_url=get_public_url,
        member=member,
        **kwargs,
    )

    if not db_session:
        from service.db import db_session

    db_session.add(
        Message(
            subject=subject,
            body=body,
            member_id=member.member_id,
            recipient=member.email,
            status=Message.QUEUED,
            template=template.value,
        ))
Example #6
0
    def create_product_action(self, **kwargs):
        if self.product:
            kwargs.setdefault('product_id', self.product.id)

        obj = self.obj.create_product_action(**kwargs)
        self.action = ProductAction(**obj)
        db_session.add(self.action)
        db_session.flush()
        return self.action
Example #7
0
 def create_permission(self, **kwargs):
     obj = dict(
         permission=random_str(),
     )
     obj.update(kwargs)
     self.permission = Permission(**obj)
     db_session.add(self.permission)
     db_session.commit()
     return self.permission
Example #8
0
def complete_transaction(transaction):
    assert transaction.status == Transaction.PENDING

    transaction.status = Transaction.COMPLETED
    db_session.add(transaction)
    db_session.flush()
    logger.info(f"completing transaction {transaction.id}, payment confirmed"
                f", sending email receipt to member {transaction.member_id}")
    send_receipt_email(transaction)
Example #9
0
def get_or_create(model, defaults=None, **kwargs):
    entity = db_session.query(model).filter_by(**kwargs).first()
    if entity:
        return entity

    entity = model(**{**kwargs, **defaults})
    db_session.add(entity)
    db_session.flush()
    return entity
Example #10
0
    def create_product(self, **kwargs):
        if self.category:
            kwargs.setdefault('category_id', self.category.id)

        obj = self.obj.create_product(**kwargs)

        self.product = Product(**obj)
        db_session.add(self.product)
        db_session.flush()
        return self.product
Example #11
0
    def create_key(self, **kwargs):
        if 'member' in kwargs:
            member = kwargs.pop('member')
        else:
            member = self.member

        obj = self.obj.create_key(**kwargs)
        self.key = Key(**obj, member=member)
        db_session.add(self.key)
        db_session.commit()
        return self.key
Example #12
0
 def create_box(self, **kwargs):
     obj = dict(
         member_id=self.member.member_id,
         box_label_id=randint(1e9, 9e9),
         session_token=random_str(),
     )
     obj.update(kwargs)
     self.box = Box(**obj)
     db_session.add(self.box)
     db_session.commit()
     return self.box
Example #13
0
 def create_span(self, **kwargs):
     if 'member' in kwargs:
         member = kwargs.pop('member')
     else:
         member = self.member
         
     obj = self.obj.create_span(**kwargs)
     self.span = Span(**obj, member=member)
     db_session.add(self.span)
     db_session.commit()
     return self.span
Example #14
0
 def create_password_reset_token(self, member=None, **kwargs):
     member = member or self.member
     
     obj = dict(
         member_id=member.member_id,
         token=random_str(),
     )
     obj.update(**kwargs)
     self.password_reset_token = PasswordResetToken(**obj)
     db_session.add(self.password_reset_token)
     db_session.commit()
     return self.password_reset_token
Example #15
0
 def create_access_token(self, **kwargs):
     obj = dict(
         user_id=TEST_SERVICE_USER_ID,
         access_token=random_str(),
         browser=f'a-browser-{random_str()}',
         ip=f'{randint(0, 255)}.{randint(0, 255)}.{randint(0, 255)}.{randint(0, 255)}',
         expires=self.test.datetime(days=1),
     )
     obj.update(kwargs)
     self.access_token = AccessToken(**obj)
     db_session.add(self.access_token)
     db_session.commit()
     return self.access_token
Example #16
0
def roll_service_token(user_id):
    try:
        access_token = db_session.query(AccessToken).filter_by(
            user_id=user_id).one()
        access_token.access_token = generate_token()
        db_session.add(access_token)
    except NoResultFound:
        raise NotFound()

    except MultipleResultsFound as e:
        raise Exception(
            f"Found multiple of service token id {user_id}, this is a bug."
        ) from e
Example #17
0
def request_password_reset(user_identification):
    member = get_member_by_user_identification(user_identification)

    token = generate_token()

    db_session.add(PasswordResetToken(member_id=member.member_id, token=token))
    db_session.flush()

    send_message(
        MessageTemplate.PASSWORD_RESET,
        member,
        url=config.get_admin_url(
            f"/password-reset?reset_token={quote_plus(token)}"),
    )
Example #18
0
    def _create_internal(self, data, commit=True):
        """ Internal create to make it easier for subclasses to manipulated data before create. """
        input_data = self.to_model(data)
        self.validate_all(input_data)
        if not input_data:
            raise UnprocessableEntity("Can not create using empty data.")
        entity = self.model(**input_data)
        db_session.add(entity)
        if commit:
            db_session.commit()
        else:
            db_session.flush()  # Flush to get id of created entity.

        return entity
Example #19
0
 def create_message(self, member=None, **kwargs):
     member = member or self.member
     
     obj = dict(
         member=member,
         subject=random_str(),
         body=self.fake.bs(),
         recipient=member.email if member else self.fake.email(),
         status=Message.QUEUED,
     )
     obj.update(**kwargs)
     self.message = Message(**obj)
     db_session.add(self.message)
     db_session.commit()
     return self.member
Example #20
0
def send_messages(key, domain, sender, to_override, limit):
    query = db_session.query(Message)
    query = query.filter(Message.status == Message.QUEUED)
    query = query.limit(limit)

    for message in query:
        to = message.recipient
        msg = f"sending {message.id} to {to}"

        if to_override:
            msg += f" (overriding to {to_override})"
            to = to_override

        msg += f": {message.subject}"

        logger.info(msg)

        response = requests.post(
            f"https://api.mailgun.net/v3/{domain}/messages",
            auth=('api', key),
            data={
                'from': sender,
                'to': to,
                'subject': message.subject,
                'html': message.body,
            })

        if response.ok:
            message.status = Message.SENT
            message.sent_at = datetime.utcnow()

            db_session.add(message)
            db_session.commit()

        else:
            message.status = Message.FAILED

            db_session.add(message)
            db_session.commit()

            logger.error(
                f"failed to send {message.id} to {to}: {response.content.decode('utf-8')}"
            )
Example #21
0
def create_access_token(ip,
                        browser,
                        user_id,
                        valid_duration: Optional[timedelta] = None):
    assert user_id > 0

    access_token = AccessToken(
        user_id=user_id,
        access_token=generate_token(),
        browser=browser,
        ip=ip,
        expires=datetime.utcnow() +
        (timedelta(minutes=15) if valid_duration is None else valid_duration),
        lifetime=int(timedelta(days=14).total_seconds()),
    )

    db_session.add(access_token)

    return dict(access_token=access_token.access_token,
                expires=access_token.expires.isoformat())
Example #22
0
def add_membership_days(member_id=None,
                        span_type=None,
                        days=None,
                        creation_reason=None,
                        default_start_date=None):
    assert days >= 0

    old_span = db_session.query(Span).filter_by(
        creation_reason=creation_reason).first()
    if old_span:
        if days == (old_span.enddate -
                    old_span.startdate).days and span_type == old_span.type:
            # Duplicate add days can happend because the code that handles the transactions is not yet done in a db
            # transaction, there are also an external script for handling puchases in ticktail that can create
            # dupllicates.
            return get_membership_summary(member_id)
        raise UnprocessableEntity(f"Duplicate entry.",
                                  fields='creation_reason',
                                  what=NOT_UNIQUE)

    if not default_start_date:
        default_start_date = date.today()

    last_end, = db_session.query(func.max(Span.enddate)).filter(
        Span.member_id == member_id, Span.type == span_type,
        Span.deleted_at.is_(None)).first()

    if not last_end or last_end < default_start_date:
        last_end = default_start_date

    end = last_end + timedelta(days=days)

    span = Span(member_id=member_id,
                startdate=last_end,
                enddate=end,
                type=span_type,
                creation_reason=creation_reason)
    db_session.add(span)
    db_session.flush()

    return get_membership_summary(member_id)
Example #23
0
def box_terminator_validate(member_number=None,
                            box_label_id=None,
                            session_token=None):
    query = get_box_query()
    query = query.filter(Box.box_label_id == box_label_id)
    try:
        box = query.one()
    except NoResultFound:
        try:
            member = db_session.query(Member).filter(
                Member.member_number == member_number).one()
        except NoResultFound:
            raise NotFound()

        box = Box(member_id=member.member_id, box_label_id=box_label_id)

    box.last_check_at = datetime.utcnow()
    box.session_token = session_token
    db_session.add(box)
    db_session.flush()

    return get_box_info(box)
Example #24
0
def password_reset(reset_token, unhashed_password):
    try:
        password_reset_token = db_session.query(PasswordResetToken).filter_by(
            token=reset_token).one()

    except NoResultFound:
        return dict(
            error_message=
            "Could not find password reset token, try to request a new reset link."
        )

    except MultipleResultsFound:
        raise InternalServerError(
            log=f"Multiple tokens {reset_token} found, this is a bug.")

    if datetime.utcnow() - password_reset_token.created_at > timedelta(
            minutes=10):
        return dict(error_message="Reset link expired, try to request a new.")

    try:
        hashed_password = check_and_hash_password(unhashed_password)
    except ValueError as e:
        return dict(error_message=str(e))

    try:
        member = db_session.query(Member).get(password_reset_token.member_id)
    except NoResultFound:
        raise InternalServerError(
            log=
            f"No member with id {password_reset_token.member_id} found, this is a bug."
        )

    member.password = hashed_password
    db_session.add(member)

    return {}
Example #25
0
def commit_transaction_to_db(member_id=None,
                             total_amount=None,
                             contents=None,
                             stripe_card_source_id=None,
                             activates_member=False):
    """ Save as new transaction with transaction content in db and return it transaction. """

    transaction = Transaction(member_id=member_id,
                              amount=total_amount,
                              status=Transaction.PENDING)

    db_session.add(transaction)
    db_session.flush()

    for content in contents:
        content.transaction_id = transaction.id
        db_session.add(content)
        db_session.flush()

        db_session.execute(
            """
            INSERT INTO webshop_transaction_actions (content_id, action_type, value, status)
            SELECT :content_id AS content_id, action_type, SUM(:count * value) AS value, :pending AS status
            FROM webshop_product_actions WHERE product_id=:product_id AND deleted_at IS NULL GROUP BY action_type
            """, {
                'content_id': content.id,
                'count': content.count,
                'pending': TransactionAction.PENDING,
                'product_id': content.product_id
            })

    if activates_member:
        # Mark this transaction as one that is for registering a member.
        db_session.add(PendingRegistration(transaction_id=transaction.id))

    db_session.add(
        StripePending(transaction_id=transaction.id,
                      stripe_token=stripe_card_source_id))

    return transaction
Example #26
0
 def create_member(self, **kwargs):
     obj = self.obj.create_member(**kwargs)
     self.member = Member(**obj, member_number=self.get_member_number())
     db_session.add(self.member)
     db_session.commit()
     return self.member
Example #27
0
def commit_fail_transaction(transaction):
    transaction.status = Transaction.FAILED
    db_session.add(transaction)
    db_session.commit()
Example #28
0
def activate_member(member):
    logger.info(f"activating member {member.member_id}")
    member.deleted_at = None
    db_session.add(member)
    db_session.flush()
    send_new_member_email(member)
Example #29
0
def complete_pending_action(action):
    action.status = TransactionAction.COMPLETED
    action.completed_at = datetime.utcnow()
    db_session.add(action)
    db_session.flush()
Example #30
0
 def create_group(self, **kwargs):
     obj = self.obj.create_group(**kwargs)
     self.group = Group(**obj)
     db_session.add(self.group)
     db_session.commit()
     return self.group