Ejemplo n.º 1
0
def news_sale_title_find(): #图书促销
	global sale_list_link_new
	home = "http://www.queshu.com/sale/"
	try:
		response = urllib2.urlopen(urllib2.Request(home))
		soup = BeautifulSoup(response, "html.parser")
		for news_sale_detail in soup.find_all(class_="news_sale_detail"):
			promotionCompany = news_sale_detail.contents[0].contents[0] #电商名字
			promotionDeadline = news_sale_detail.contents[1].string #活动结束时间
			for news_sale_title in news_sale_detail.find_all(class_="news_sale_title"): #活动链接
				promotionName = news_sale_title.contents[0].contents[0] #活动名称
				promotionLink = news_sale_title.contents[0]["href"]
				if promotionLink[1:5] == "link":
					promotionLink = home[:-5] + promotionLink

				if promotionDeadline: #可能为空
					promotionDeadline = promotionDeadline.encode('utf-8')
				promotionID=promotionLink[-5:]
				result = Promotion(
					promotionID		= promotionID.encode('utf-8'),
					promotionCompany  = promotionCompany.encode('utf-8'), 
					promotionName	 = promotionName.encode('utf-8'), 
					promotionDeadline = promotionDeadline, 
					promotionLink	 = promotionLink.encode('utf-8'))
				result.save()

				font_13_bold = news_sale_detail.find(href=re.compile("sale_list"))  #参加活动图书列表
				if font_13_bold:
					sale_list_link_new[promotionID] = home[:-6] + font_13_bold["href"]
	except urllib2.URLError, e:
		print e.reason
Ejemplo n.º 2
0
def news_sale_title_find(): #活动列表
	global sale_list_link_new
	home = "http://www.queshu.com/sale/"
	try:
		response = urllib2.urlopen(urllib2.Request(home))
		soup = BeautifulSoup(response, "html.parser")
		for news_sale_detail in soup.find_all(class_="news_sale_detail"):
			promotionCompany = news_sale_detail.contents[0].contents[0] #电商名字
			promotionDeadline = news_sale_detail.contents[1].string #活动结束时间
			for news_sale_title in news_sale_detail.find_all(class_="news_sale_title"): #活动链接
				promotionName = news_sale_title.contents[0].contents[0] #活动名称
				promotionLink = news_sale_title.contents[0]["href"]
				if promotionLink[1:5] == "link":
					promotionLink = home[:-5] + promotionLink

				if promotionDeadline: #活动结束时间可能为空
					promotionDeadline = promotionDeadline.encode('utf-8')
				promotionID=promotionLink[-5:]
				promotionSearchLink = ""
				font_13_bold = news_sale_detail.find(href=re.compile("sale_list"))  #参加活动图书列表
				if font_13_bold:
					promotionSearchLink = home[:-6] + font_13_bold["href"]
					sale_list_link_new[promotionID] = promotionSearchLink

				result = Promotion(
					promotionID         = promotionID.encode('utf-8'),
					promotionCompany    = promotionCompany.encode('utf-8'), 
					promotionName       = promotionName.encode('utf-8'), 
					promotionDeadline   = promotionDeadline, 
					promotionLink       = promotionLink.encode('utf-8'),
					promotionSearchLink = promotionSearchLink)
				result.save()
	except urllib2.URLError, e:
		print e.reason
Ejemplo n.º 3
0
 def _parse_promotion(self, json_obj):
     item = Promotion(**json_obj)
     if self.is_logged_in and self.user.favorites:
         if item.type == 'ALBUM':
             item._isFavorite = self.user.favorites.isFavoriteAlbum(item.id)
         elif item.type == 'PLAYLIST':
             item._isFavorite = self.user.favorites.isFavoritePlaylist(
                 item.id)
         elif item.type == 'VIDEO':
             item._isFavorite = self.user.favorites.isFavoriteVideo(item.id)
     return item
Ejemplo n.º 4
0
    def get(self):
        """
        Logged in users not allowed here.
        """
        if self.get_current_user():
            return self.redirect("/")

        if options.disable_signups:
            return self.write("Sorry! Signups Are Closed.")

        # voucher key
        key_value = self.get_argument('key', '')

        promotions = Promotion.active()

        # Amazon's ELB will set this header to inform us what scheme is in use
        # Fallback to checking Tornado's protocol if it is absent
        using_https = self.request.headers.get(
            "X-Forwarded-Proto", self.request.protocol) == "https"

        #recaptcha hot fix
        captcha_string = captcha.displayhtml(options.recaptcha_public_key,
                                             use_ssl=using_https)
        return self.render("account/create.html",
                           name="",
                           email="",
                           key=key_value,
                           promotions=promotions,
                           recaptcha=captcha_string)
Ejemplo n.º 5
0
    def get(self):
        """
        Logged in users not allowed here.
        """
        if self.get_current_user():
            return self.redirect("/")

        if options.disable_signups:
            return self.write("Sorry! Signups Are Closed.")

        # voucher key
        key_value = self.get_argument('key', '')

        promotions = Promotion.active()

        # If we're using mltshp-cdn.com, we know that we can use
        # https; if something else is configured, check the
        # X-Forwarded-Proto header and fallback to the protocol
        # of the request
        using_https = options.cdn_ssl_host == "mltshp-cdn.com" or \
            self.request.headers.get("X-Forwarded-Proto",
                self.request.protocol) == "https"

        #recaptcha hot fix
        if options.recaptcha_public_key:
            captcha_string = captcha.displayhtml(options.recaptcha_public_key,
                                                 use_ssl=using_https)
        else:
            captcha_string = ""
        return self.render("account/create.html",
                           name="",
                           email="",
                           key=key_value,
                           promotions=promotions,
                           recaptcha=captcha_string)
Ejemplo n.º 6
0
    def get(self):
        current_user = self.get_current_user_object()
        if current_user.is_paid:
            return self.redirect("/account/settings")

        promotions = Promotion.active()

        return self.render('account/subscribe.html', promotions=promotions)
Ejemplo n.º 7
0
def list_promotions():
    """ Returns all of the Promotions """
    promotions = []
    category = request.args.get('category')
    name = request.args.get('name')
    availability = request.args.get('availability')
    if category:
        promotions = Promotion.find_by_category(category)
    elif name:
        promotions = Promotion.find_by_promo_name(name)
    elif availability:
        promotions = Promotion.find_by_availability(availability)
    else:
        promotions = Promotion.all()

    results = [promotion.serialize() for promotion in promotions]
    return make_response(jsonify(results), status.HTTP_200_OK)
Ejemplo n.º 8
0
 def __init__(self, sub, promotion_type):
     self.promotion = Promotion.Promotion(promotion_type)
     self.sub = sub
     if sub.sub_level == "starter":
         self.__sub_price = 2.99-2.99 * self.promotion.percent
     if sub.sub_level == "plus":
         self.__sub_price = 5.99-5.99 * self.promotion.percent
     if sub.sub_level == "premium":
         self.__sub_price = 9.99-9.99 * self.promotion.percent
Ejemplo n.º 9
0
def delete_promotion(promotion_id):
    """
    Delete a Promotion
    This endpoint will delete a Promotion based the id specified in the path
    """
    promotion = Promotion.find(promotion_id)
    if promotion:
        promotion.delete()
    return make_response('', status.HTTP_204_NO_CONTENT)
Ejemplo n.º 10
0
    def get(self):
        """ Returns all of the Promotions"""
        app.logger.info("Request to list promotions")
        promotions = []
        category = request.args.get('category')
        name = request.args.get('promo_name')
        availability = request.args.get('availability')
        if category:
            promotions = Promotion.find_by_category(category)
        elif name:
            promotions = Promotion.find_by_promo_name(name)
        elif availability:
            availability = str_to_bool(availability)
            promotions = Promotion.find_by_availability(availability)
        else:
            promotions = Promotion.all()

        results = [promotion.serialize() for promotion in promotions]
        return results, status.HTTP_200_OK
Ejemplo n.º 11
0
    def delete(self):
        """ Delete all unavailable Promotions

        This endpoint will delete all unavailable Promotions
        """
        promotions = Promotion.find_by_availability(False)
        if promotions:
            for promotion in promotions:
                promotion.delete()
        return '', status.HTTP_204_NO_CONTENT
Ejemplo n.º 12
0
def delete_unavailable_promotion():

    """ Delete all unavailable Promotions """
    """ This endpoint will delete all unavailable Promotions """

    promotions = Promotion.find_by_availability(False)
    if promotions:
        for promotion in promotions:
            promotion.delete()
    return make_response('', status.HTTP_204_NO_CONTENT)
Ejemplo n.º 13
0
def get_promotion(promotion_id):
    """
    Retrieve a single Promotion

    This endpoint will return a Promotion based on it's id
    """
    promotion = Promotion.find(promotion_id)
    if not promotion:
        raise NotFound("Promotion with id '{}' was not found.".format(promotion_id))
    return make_response(jsonify(promotion.serialize()), status.HTTP_200_OK)
Ejemplo n.º 14
0
 def delete(self, promotion_id):
     """
     Delete a Promotion
     This endpoint will delete a Promotion based the id specified in the path
     """
     app.logger.info('Request to Delete a promotion with id [%s]',
                     promotion_id)
     promotion = Promotion.find(promotion_id)
     if promotion:
         promotion.delete()
     return '', status.HTTP_204_NO_CONTENT
Ejemplo n.º 15
0
def update_promotion(promotion_id):
    """
    Update a Promotion
    This endpoint will update a Promotion based the body that is posted
    """
    check_content_type('application/json')
    promotion = Promotion.find(promotion_id)
    if not promotion:
        raise NotFound("Promotion with id '{}' was not found.".format(promotion_id))
    promotion.deserialize(request.get_json())
    promotion.id = promotion_id
    promotion.save()
    return make_response(jsonify(promotion.serialize()), status.HTTP_200_OK)
Ejemplo n.º 16
0
    def setUp(self):
        super(VoucherTests, self).setUp()
        self.admin = test.factories.user()
        self.sign_in("admin", "password")

        self.shake = Shake(user_id=self.admin.id,
                           name='promotion-shake',
                           title='Promotion Shake',
                           type='group')
        self.shake.save()
        self.expired_promotion = Promotion(name="Expired Promotion",
                                           membership_months=60,
                                           expires_at=datetime.utcnow() -
                                           timedelta(seconds=50),
                                           promotion_shake_id=0)
        self.expired_promotion.save()
        self.promotion = Promotion(name="Unit Test Sale",
                                   membership_months=60,
                                   promotion_shake_id=self.shake.id,
                                   expires_at=datetime.utcnow() +
                                   timedelta(seconds=60 * 60 * 24 * 365))
        self.promotion.save()

        self.used_voucher = Voucher(offered_by_user_id=0,
                                    promotion_id=self.promotion.id,
                                    voucher_key="abc123")
        # apply_to_user saves the voucher object (because it touches the
        # claimed_by_user_id and dates) and also the user object (by
        # updating the is_paid status)
        self.used_voucher.apply_to_user(self.admin)

        self.unused_voucher = Voucher(offered_by_user_id=0,
                                      claimed_by_user_id=0,
                                      promotion_id=self.promotion.id,
                                      voucher_key="unclaimed")
        self.unused_voucher.save()

        tornado.httpclient.HTTPClient()
Ejemplo n.º 17
0
def create_promotion():
    """
    Create a new promotion
    This endpoint will create a promotion based on the data in the request body and save it into the db
    """
    check_content_type('application/json')
    promotion = Promotion()
    promotion.deserialize(request.get_json())
    promotion.save()
    saved_info = promotion.serialize()
    location_url = url_for('get_promotion', promotion_id = promotion.id, _external=True)
    return make_response(jsonify(saved_info), status.HTTP_201_CREATED, { 'Location': location_url })
Ejemplo n.º 18
0
    def get(self, promotion_id):
        """
        Retrieve a single Promotion

        This endpoint will return a Promotion based on it's id
        """
        app.logger.info("Request to Retrieve a promotion with id [%s]",
                        promotion_id)
        promotion = Promotion.find(promotion_id)
        if not promotion:
            app.logger.error('Promotion with id %d was not found.',
                             promotion_id)
            raise NotFound(
                "Promotion with id '{}' was not found.".format(promotion_id))
        return promotion.serialize(), status.HTTP_200_OK
Ejemplo n.º 19
0
    def get(self):
        user = self.get_current_user_object()
        payments = []
        if user.is_paid:
            payments = PaymentLog.last_payments(count=3, user_id=user.id)

        already_requested = self.get_secure_cookie("image_request")

        promotions = Promotion.active()

        return self.render("account/settings.html",
                           user=user,
                           payments=payments,
                           already_requested=already_requested,
                           promotions=promotions)
Ejemplo n.º 20
0
 def get(self):
     vid = self.get_argument('vid', None)
     shake = None
     promotion = None
     voucher = None
     user = self.get_current_user_object()
     if vid is not None:
         voucher = Voucher.get("id=%s", vid)
         if voucher is not None and voucher.claimed_by_user_id == user.id:
             if voucher.promotion_id:
                 promotion = Promotion.get("id=%s", voucher.promotion_id)
                 if promotion is not None:
                     shake = promotion.shake()
     return self.render(
         "account/confirm.html", promotion=promotion,
         promotion_shake=shake, voucher=voucher, current_user_obj=user)
Ejemplo n.º 21
0
    def post(self):
        key_value = self.get_argument('key', '')

        voucher = is_valid_voucher_key(key_value)

        user = self.get_current_user_object()
        if voucher is not None:
            if not voucher.claimed_by_user_id:
                voucher.apply_to_user(user)
                return self.redirect("/account/settings")

        promotions = Promotion.active()

        self.add_error('key', 'Invalid discount code')
        return self.render("account/redeem.html",
            key=key_value, promotions=promotions)
Ejemplo n.º 22
0
    def post(self):
        user = self.get_current_user_object()
        email = self.get_argument('email', None)
        disable_notifications = self.get_argument('disable_notifications', 0)
        show_naked_people = self.get_argument('show_naked_people', 0)
        show_stats = self.get_argument('show_stats', 0)
        disable_autoplay = self.get_argument('disable_autoplay', 0)

        if email != user.email and email != None:
            user.update_email(email)
            user.invalidate_email()

        if disable_notifications:
            user.disable_notifications = 1
        else:
            user.disable_notifications = 0

        if show_naked_people:
            user.show_naked_people = 1
        else:
            user.show_naked_people = 0

        if show_stats:
            user.show_stats = 1
        else:
            user.show_stats = 0

        if disable_autoplay:
            user.disable_autoplay = 1
        else:
            user.disable_autoplay = 0

        if user.save():
            return self.redirect("/account/settings")

        promotions = Promotion.active()

        self.add_errors(user.errors)
        return self.render("account/settings.html",
                           user=user,
                           errors=self._errors,
                           promotions=promotions)
Ejemplo n.º 23
0
 def post(self):
     """
     Create a new promotion
     This endpoint will create a promotion based on the data in the request body and save it into the db
     """
     app.logger.info('Request to Create a Promotion')
     check_content_type('application/json')
     promotion = Promotion()
     app.logger.info('Payload = %s', api.payload)
     promotion.deserialize(api.payload)
     promotion.save()
     app.logger.info('Promotion with new id [%s] saved!', promotion.id)
     location_url = api.url_for(PromotionResource,
                                promotion_id=promotion.id,
                                _external=True)
     return promotion.serialize(), status.HTTP_201_CREATED, {
         'Location': location_url
     }
Ejemplo n.º 24
0
    def get(self):
        """
        Logged out users not allowed here.
        """
        # voucher key
        key_value = self.get_argument('key', '')

        user = self.get_current_user_object()
        if user is None:
            if key_value != '':
                query = "?" + urlencode({"key": key_value})
            return self.redirect("/create-account%s" % query)

        if user.is_paid:
            # pro users can't redeem
            return self.redirect("/account/settings")

        promotions = Promotion.active()

        return self.render("account/redeem.html",
            key=key_value, promotions=promotions)
Ejemplo n.º 25
0
 def create_model(self, form):
     try:
         assert form.promotion_type is not None and form.promotion_type.data in PromotionType.__members__
         assert isinstance(form.bonus_amount.data, int) and form.bonus_amount.data > 0
         assert isinstance(form.betting_volume_threshold.data, int) and form.bonus_amount.data > 0
         assert isinstance(form.user_balance_minimum.data, int) and form.bonus_amount.data > 0
         model = Promotion(
             promotion_type=PromotionType[form.promotion_type.data],
             bonus_amount=form.bonus_amount.data,
             betting_volume_threshold=form.betting_volume_threshold.data,
             user_balance_minimum=form.user_balance_minimum.data
         )
         self.session.add(model)
         self.session.commit()
         logger.info(f'Promotion created by admin {auth_get_current_username()}: {model.to_json()}')
     except Exception as ex:
         self.session.rollback()
         flash(f'Failed to create promotion. {str(ex)}', 'error')
         logger.exception(f'Promotion create by admin {auth_get_current_username()} raised exception')
         return False
     return True
Ejemplo n.º 26
0
    def put(self, promotion_id):
        """
        Update a Promotion
        This endpoint will update a Promotion based the body that is posted
        """
        app.logger.info('Request to Update a promotion with id [%s]',
                        promotion_id)
        check_content_type('application/json')
        promotion = Promotion.find(promotion_id)
        if not promotion:
            app.logger.error('Promotion with id %d was not found.',
                             promotion_id)
            raise NotFound(
                "Promotion with id '{}' was not found.".format(promotion_id))

        data = api.payload
        app.logger.info(data)
        promotion.deserialize(data)
        promotion.id = promotion_id
        promotion.save()
        return promotion.serialize(), status.HTTP_200_OK
Ejemplo n.º 27
0
def add_promotions():
    promotions_file = request.files.get('promotions')
    if not promotions_file or not promotions_file.filename:
        raise HttpError('Missing field', 400, {
            'errors': {
                'discounts': 'this field is required',
            },
        })

    promotions_parsed = parse(promotions_file)

    # for production, create_products should probably be 'false'. I set it
    #  as a facility to automatically create missing products
    promotions = Promotion.from_file(promotions_parsed,
                                     request.user,
                                     create_products=True)
    promotions_dict = list(map(serialize_promotion, promotions))

    response = jsonify(promotions_dict)
    response.status_code = 201
    return response
Ejemplo n.º 28
0
    def get(self):
        user = self.get_current_user_object()
        payments = []
        if user.is_paid:
            payments = PaymentLog.last_payments(count=3, user_id=user.id)

        already_requested = self.get_secure_cookie("image_request")
        cancel_flag = "canceled" in (user.stripe_plan_id or "")
        migrated_flag = self.get_argument('migrated', 0)

        promotions = Promotion.active()

        has_data_to_migrate = not MigrationState.has_migrated(user.id)

        return self.render("account/settings.html",
                           user=user,
                           payments=payments,
                           already_requested=already_requested,
                           promotions=promotions,
                           plan_name=plan_name(user.stripe_plan_id),
                           has_data_to_migrate=has_data_to_migrate,
                           migrated_flag=migrated_flag,
                           cancel_flag=cancel_flag)
Ejemplo n.º 29
0
    def post(self):
        if options.disable_signups:
            return

        name_value = self.get_argument('name', '')
        email_value = self.get_argument('email', '')
        key_value = self.get_argument('key', '')
        has_errors = False
        voucher = None

        if key_value != '':
            voucher = is_valid_voucher_key(key_value)
            if voucher is None:
                has_errors = True
                self.add_error('key', 'Invalid discount code')

        new_user = User(name=name_value, email=email_value, email_confirmed=0)
        new_user.set_and_confirm_password(
            self.get_argument('password', ""),
            self.get_argument('password_again', ""))

        skip_recaptcha = self.get_argument('_skip_recaptcha_test_only', False)
        if not options.recaptcha_private_key:
            skip_recaptcha = True

        #recaptcha hotfix
        if not skip_recaptcha:
            response = captcha.submit(
                self.get_argument('recaptcha_challenge_field'),
                self.get_argument('recaptcha_response_field'),
                options.recaptcha_private_key, self.request.remote_ip)

            if not response.is_valid:
                has_errors = True
                self.add_error('recaptcha', 'Invalid captcha')

        if not has_errors:
            try:
                # create form asserts the user agress to terms of use
                new_user.tou_agreed = 1

                if new_user.save():
                    if options.postmark_api_key:
                        # i'd like to NOT invalidate_email in the
                        # case of using a voucher, but the person
                        # may use a different email for MLTSHP than
                        # they used for receiving their voucher, so...
                        new_user.invalidate_email()
                    else:
                        # we have no way to send a verification
                        # email, so we're gonna trust 'em
                        new_user.email_confirmed = 1
                        new_user.save()

                    query_str = ''
                    if voucher is not None:
                        voucher.apply_to_user(new_user)
                        query_str = '?vid=%s' % str(voucher.id)

                    self.log_user_in(new_user)
                    if new_user.email_confirmed:
                        return self.redirect('/')
                    else:
                        return self.redirect('/confirm-account%s' % query_str)
            except torndb.IntegrityError:
                #This is a rare edge case, so we handle it lazily -- IK.
                pass
            has_errors = True
            self.add_errors(new_user.errors)

        #recaptcha hot fix
        captcha_string = captcha.displayhtml(options.recaptcha_public_key)
        promotions = Promotion.active()
        return self.render("account/create.html",
                           name=name_value,
                           email=email_value,
                           key=key_value,
                           recaptcha=captcha_string,
                           promotions=promotions)
Ejemplo n.º 30
0
    def post(self):
        if options.disable_signups:
            return

        name_value = self.get_argument('name', '')
        email_value = self.get_argument('email', '')
        key_value = self.get_argument('key', '')
        has_errors = False
        voucher = None

        if key_value != '':
            voucher = is_valid_voucher_key(key_value)
            if voucher is None:
                has_errors = True
                self.add_error('key', 'Invalid discount code')

        new_user = User(name=name_value, email=email_value, email_confirmed=0)
        new_user.set_and_confirm_password(
            self.get_argument('password', ""),
            self.get_argument('password_again', ""))

        skip_recaptcha = self.get_argument('_skip_recaptcha_test_only', False)
        if not options.recaptcha_secret_key:
            skip_recaptcha = True

        # recaptcha validation, when configured
        if not skip_recaptcha:
            response = requests.post(
                "https://www.google.com/recaptcha/api/siteverify",
                params={
                    "secret": options.recaptcha_secret_key,
                    "response": self.get_argument("recaptcha_token"),
                })
            try:
                result = response.json()
                if not result["success"] or result["score"] < 0.5:
                    has_errors = True
                    self.add_error("recaptcha", "Invalid captcha")
            except ValueError:
                has_errors = True
                self.add_error("recaptcha", "Invalid captcha")

        if not has_errors:
            try:
                # create form asserts the user agress to terms of use
                new_user.tou_agreed = 1

                if new_user.save():
                    if options.postmark_api_key:
                        # i'd like to NOT invalidate_email in the
                        # case of using a voucher, but the person
                        # may use a different email for MLTSHP than
                        # they used for receiving their voucher, so...
                        new_user.invalidate_email()
                    else:
                        # we have no way to send a verification
                        # email, so we're gonna trust 'em
                        new_user.email_confirmed = 1
                        new_user.save()

                    query_str = ''
                    if voucher is not None:
                        voucher.apply_to_user(new_user)
                        query_str = '?vid=%s' % str(voucher.id)

                    self.log_user_in(new_user)
                    if new_user.email_confirmed:
                        return self.redirect('/')
                    else:
                        return self.redirect('/confirm-account%s' % query_str)
            except torndb.IntegrityError:
                #This is a rare edge case, so we handle it lazily -- IK.
                pass
            has_errors = True
            self.add_errors(new_user.errors)

        promotions = Promotion.active()
        return self.render("account/create.html",
                           name=name_value,
                           email=email_value,
                           key=key_value,
                           recaptcha_site_key=options.recaptcha_site_key,
                           promotions=promotions)
Ejemplo n.º 31
0
    def get(self):
        user = self.get_current_user_object()
        payments = []
        if user.is_paid:
            payments = []
            if user.stripe_customer_id:
                customer_id = user.stripe_customer_id
                charges = stripe.Charge.list(limit=5, customer=customer_id)
                for charge in charges.data:
                    payments.append({
                        "transaction_amount":
                        "USD %0.2f" % (charge.amount / 100.0, ),
                        "refund_amount":
                        charge.refunded and "USD %0.2f" %
                        (charge.amount_refunded / 100.0, ) or "",
                        "created_at":
                        datetime.datetime.fromtimestamp(charge.created),
                        "status":
                        "charged",
                        "is_pending":
                        charge.status == "pending",
                        "is_failed":
                        charge.status == "failed",
                        "is_success":
                        charge.status == "succeeded",
                        "is_refund":
                        charge.refunded,
                    })
            else:
                log = PaymentLog.last_payments(count=5, user_id=user.id)
                for payment in log:
                    payments.append({
                        "transaction_amount": payment.transaction_amount,
                        "refund_amount": "",
                        "created_at": payment.created_at,
                        "status": payment.status,
                        "is_pending": False,
                        "is_success": True,
                        "is_failed": False,
                        "is_refund": False,
                    })

        already_requested = self.get_secure_cookie("image_request")
        cancel_flag = "canceled" in (user.stripe_plan_id or "")
        updated_flag = self.get_argument("update", "") == "1"
        migrated_flag = self.get_argument("migrated", 0)
        past_due = False
        source_card_type = None
        source_last_4 = None
        source_expiration = None

        promotions = Promotion.active()

        has_data_to_migrate = not MigrationState.has_migrated(user.id)

        if user.stripe_customer_id:
            customer = None
            try:
                customer = stripe.Customer.retrieve(user.stripe_customer_id)
            except stripe.error.InvalidRequestError:
                pass
            if customer and not hasattr(customer, 'deleted'):
                if customer.subscriptions.total_count >= 1:
                    subscriptions = [
                        sub for sub in customer.subscriptions.data
                        if sub.plan.id == user.stripe_plan_id
                    ]
                    if subscriptions:
                        subscription = subscriptions[0]
                        past_due = subscription.status == "past_due"
                        if customer.sources.total_count > 0:
                            if customer.sources.data[0].object == "card":
                                card = customer.sources.data[0]
                            elif customer.sources.data[0].object == "source":
                                card = customer.sources.data[0].card
                            source_card_type = card.brand
                            source_last_4 = card.last4
                            source_expiration = "%d/%d" % (card.exp_month,
                                                           card.exp_year)

        return self.render("account/settings.html",
                           user=user,
                           payments=payments,
                           already_requested=already_requested,
                           promotions=promotions,
                           plan_name=plan_name(user.stripe_plan_id),
                           past_due=past_due,
                           stripe_public_key=options.stripe_public_key,
                           source_card_type=source_card_type,
                           source_last_4=source_last_4,
                           source_expiration=source_expiration,
                           has_data_to_migrate=has_data_to_migrate,
                           updated_flag=updated_flag,
                           migrated_flag=migrated_flag,
                           cancel_flag=cancel_flag)