def test_discount(self): # A unique number on all the giftcards. serial = "1678" # A "correct" hash, based on what the actual code does. correct_hash = hashlib.sha1(serial + self.code).hexdigest() correct_hash = re.sub("[a-f]", "", correct_hash)[:8] gift_code = "1337" + serial + correct_hash print "Using test gift code: %s" % (gift_code) # Now try using this code. user = Membership.get_by_hash(self.user_hash) user.referrer = gift_code user.put() response = self.test_app.post("/account/" + self.user_hash, self._TEST_PARAMS) self.assertEqual(302, response.status_int) # We should have a record of the used code. codes = main.UsedCode.all().run() for code in codes: # We should only have one code in there. self.assertEqual(gift_code, code.code) self.assertEqual("*****@*****.**", code.email) self.assertEqual("OK", code.extra) user = Membership.get_by_hash(self.user_hash) user.username = None user.put() # Try to use the same code again. response = self.test_app.post("/account/" + self.user_hash, self._TEST_PARAMS, expect_errors=True) self.assertEqual(422, response.status_int) self.assertIn("already been used", response.body) # Now we should have individual records of the same code being used twice. codes = main.UsedCode.all().run() # Turn the iterator into a list. codes = [code for code in codes] self.assertEqual(gift_code, codes[0].code) self.assertEqual(gift_code, codes[1].code) self.assertEqual("*****@*****.**", codes[0].email) self.assertEqual("*****@*****.**", codes[1].email) if codes[0].extra == "OK": # The other one should be the duplicate. self.assertEqual("2nd+ attempt", codes[1].extra) elif codes[0].extra == "2nd+ attempt": # The other one should be the good one. self.assertEqual("OK", codes[1].extra) else: fail("Got unexpected extra '%s'." % (codes[0].extra))
def test_create_user(self): response = self.test_app.post("/tasks/create_user", self.params) self.assertEqual(200, response.status_int) # Check that it's sending the right parameters to the domain app. self.assertIn("username=testy.testerson", response.body) self.assertIn("password=notasecret", response.body) self.assertIn("first_name=Testy", response.body) self.assertIn("last_name=Testerson", response.body) user = Membership.get_by_hash(self.user_hash) # Check that the user ended up with a username. self.assertEqual("testy.testerson", user.username) # Check that domain_user got set. self.assertTrue(user.domain_user) # Check that the password got cleared. self.assertEqual(None, user.password) # Check that it sent the right email. messages = self.mail_stub.get_sent_messages(to="*****@*****.**") self.assertEqual(1, len(messages)) # It should give the user this data. body = str(messages[0].body) self.assertIn(user.username, body)
def get(self, hash): member = Membership.get_by_hash(hash) conf = Config() if member: success_html = urlfetch.fetch(conf.SUCCESS_HTML_URL).content success_html = success_html.replace("joining!", "joining, %s!" % member.first_name) is_prod = conf.is_prod self.response.out.write(self.render("templates/success.html", locals()))
def get(self, hash): member = Membership.get_by_hash(hash) c = Config() if member: success_html = urlfetch.fetch(SUCCESS_HTML_URL).content success_html = success_html.replace('joining!', 'joining, %s!' % member.first_name) is_prod = c.is_prod self.response.out.write(render('templates/success.html', locals()))
def test_retry_no_token(self): # Make a user with no token. user = Membership.get_by_hash(self.user_hash) user.spreedly_token=None user.put() # Try to create an account for this user. response = self.test_app.post("/tasks/create_user", self.params) self.assertEqual(200, response.status_int) # We should have a new task now. taskqueue_stub = self.testbed.get_stub(testbed.TASKQUEUE_SERVICE_NAME) tasks = taskqueue_stub.GetTasks("default") self.assertEqual(1, len(tasks)) # The user shouldn't have a domain account yet. user = Membership.get_by_hash(self.user_hash) self.assertFalse(user.domain_user)
def test_get(self): query = urllib.urlencode({"plan": "newhive"}) response = self.test_app.get("/account/%s?%s" % (self.user_hash, query)) self.assertEqual(200, response.status_int) # Our username should be templated in. self.assertIn("testy.testerson", response.body) user = Membership.get_by_hash(self.user_hash) self.assertEqual("newhive", user.plan)
def test_retry_no_token(self): # Make a user with no token. user = Membership.get_by_hash(self.user_hash) user.spreedly_token = None user.put() # Try to create an account for this user. response = self.test_app.post("/tasks/create_user", self.params) self.assertEqual(200, response.status_int) # We should have a new task now. taskqueue_stub = self.testbed.get_stub(testbed.TASKQUEUE_SERVICE_NAME) tasks = taskqueue_stub.GetTasks("default") self.assertEqual(1, len(tasks)) # The user shouldn't have a domain account yet. user = Membership.get_by_hash(self.user_hash) self.assertFalse(user.domain_user)
def get(self, hash): member = Membership.get_by_hash(hash) conf = Config() if member: success_html = urlfetch.fetch(conf.SUCCESS_HTML_URL).content success_html = success_html.replace( "joining!", "joining, %s!" % member.first_name) is_prod = conf.is_prod self.response.out.write( self.render("templates/success.html", locals()))
def test_already_active(self): user = Membership.get_by_hash(self.user_hash) user.status = "active" user.put() query = urllib.urlencode(self._TEST_PARAMS) response = self.test_app.post("/account/" + self.user_hash, query) self.assertEqual(302, response.status_int) self.assertIn("success", response.location) self.assertIn(self.user_hash, response.location)
def test_post(self): query = urllib.urlencode(self._TEST_PARAMS) response = self.test_app.post("/account/" + self.user_hash, query) self.assertEqual(302, response.status_int) user = Membership.get_by_hash(self.user_hash) # We should be redirected to a personal spreedly page. self.assertIn("subs.pinpayments.com", response.location) self.assertIn(self.test_plan.plan_id, response.location) self.assertIn(str(user.key().id()), response.location) self.assertIn("testy.testerson", response.location) # The account information should be in the datastore. user = Membership.get_by_hash(self.user_hash) self.assertEqual("testy.testerson", user.username) self.assertEqual("notasecret", user.password) # We shouldn't have a domain account yet. self.assertFalse(user.domain_user)
def test_bad_length_code(self): code = "133712345" user = Membership.get_by_hash(self.user_hash) user.referrer = code user.put() response = self.test_app.post("/account/" + self.user_hash, self._TEST_PARAMS, expect_errors=True) self.assertEqual(422, response.status_int) self.assertIn("must be 16 digits", response.body)
def test_invalid_code(self): code = "1337424242424242" user = Membership.get_by_hash(self.user_hash) user.referrer = code user.put() response = self.test_app.post("/account/" + self.user_hash, self._TEST_PARAMS, expect_errors=True) self.assertEqual(422, response.status_int) self.assertIn("code was invalid", response.body)
def get(self, hash): membership = Membership.get_by_hash(hash) if not membership: self.response.set_status(422) self.response.out.write("Unknown member hash.") logging.error("Could not find member with hash '%s'." % (hash)) return # Save the plan they want. plan = self.request.get("plan", "newfull") membership.plan = plan membership.put() if ((membership.username and membership.password) and not \ membership.spreedly_token): # We've filled out our account information, but we never started a # subscription. (This could be reached by going back and trying to # change our plan after we were already taken to the PinPayments # page.) In this case, just pass them through to PinPayments. query_str = urllib.urlencode({"first_name": membership.first_name, "last_name": membership.last_name, "email": membership.email, "return_url": "http://%s/success/%s" % \ (self.request.host, membership.hash)}) self.redirect(membership.new_subscribe_url(query_str)) # steal this part to detect if they registered with hacker dojo email above first_part = re.compile(r"[^\w]").sub("", membership.first_name.split(" ")[0]) # First word of first name last_part = re.compile(r"[^\w]").sub("", membership.last_name) if len(first_part)+len(last_part) >= 15: last_part = last_part[0] # Just last initial username = "******".join([first_part, last_part]).lower() usernames = self.fetch_usernames() if usernames == None: # Error page is already rendered. return if username in usernames: # Duplicate username. Use the first part of the email instead. username = membership.email.split("@")[0].lower() user_number = 0 base_username = username while username in usernames: # Still a duplicate. Add a number. user_number += 1 username = "******" % (base_username, user_number) if self.request.get("pick_username"): pick_username = True account_url = str("/account/%s" % membership.hash) self.response.out.write(self.render("templates/account.html", locals()))
def get(self, hash): membership = Membership.get_by_hash(hash) if not membership: self.response.set_status(422) self.response.out.write("Unknown member hash.") logging.error("Could not find member with hash '%s'." % (hash)) return # Save the plan they want. plan = self.request.get("plan", "newfull") membership.plan = plan membership.put() if ((membership.username and membership.password) and not \ membership.spreedly_token): # We've filled out our account information, but we never started a # subscription. (This could be reached by going back and trying to # change our plan after we were already taken to the PinPayments # page.) In this case, just pass them through to PinPayments. self.redirect( membership.new_subscribe_url(self.request.host, plan=plan)) # steal this part to detect if they registered with hacker dojo email above first_part = re.compile(r"[^\w]").sub( "", membership.first_name.split(" ")[0]) # First word of first name last_part = re.compile(r"[^\w]").sub("", membership.last_name) if len(first_part) + len(last_part) >= 15: last_part = last_part[0] # Just last initial username = "******".join([first_part, last_part]).lower() usernames = self.fetch_usernames() if usernames == None: # Error page is already rendered. return if username in usernames: # Duplicate username. Use the first part of the email instead. username = membership.email.split("@")[0].lower() user_number = 0 base_username = username while username in usernames: # Still a duplicate. Add a number. user_number += 1 username = "******" % (base_username, user_number) if self.request.get("pick_username"): pick_username = True account_url = str("/account/%s" % membership.hash) self.response.out.write(self.render("templates/account.html", locals()))
def post(self): def fail(exception): logging.error("CreateUserTask failed: %s" % exception) mail.send_mail(sender=EMAIL_FROM, to=INTERNAL_DEV_EMAIL, subject="[%s] CreateUserTask failure" % APP_NAME, body=str(exception)) def retry(countdown=3): retries = int(self.request.get('retries', 0)) + 1 if retries <= 5: taskqueue.add(url='/tasks/create_user', method='POST', countdown=countdown, params={'hash': self.request.get('hash'), 'retries': retries}) else: fail(Exception("Too many retries for %s" % self.request.get('hash'))) c = Config() user_hash = self.request.get('hash') membership = Membership.get_by_hash(user_hash) if membership is None or membership.username: return if not membership.spreedly_token: logging.warn("CreateUserTask: No spreedly token yet, retrying") return retry(300) try: username, password = memcache.get(hashlib.sha1(membership.hash+c.SPREEDLY_APIKEY).hexdigest()).split(':') except (AttributeError, ValueError): return fail(Exception("Account information expired for %s" % membership.email)) try: url = 'http://%s/users' % DOMAIN_HOST payload = urllib.urlencode({ 'username': username, 'password': password, 'first_name': membership.first_name, 'last_name': membership.last_name, 'secret': keymaster.get('api'), }) logging.info("CreateUserTask: About to create user: "******"CreateUserTask: URL: "+url) logging.info("CreateUserTask: Payload: "+payload) resp = urlfetch.fetch(url, method='POST', payload=payload, deadline=120) membership.username = username membership.put() logging.warn("CreateUserTask: I think that worked: HTTP "+str(resp.status_code)) # Send the welcome email. SuccessHandler.send_email(membership) except urlfetch.DownloadError, e: logging.warn("CreateUserTask: API response error or timeout, retrying") return retry()
def get(self, user_hash): member = Membership.get_by_hash(user_hash) if not member: # Hash is invalid. logging.error("Invalid hash '%s'." % (user_hash)) error = self.render("templates/error.html", message="Invalid reactivation link.") self.response.out.write(error) self.response.set_status(422) return self._plan_switch_page(member)
def test_already_entered(self): user = Membership.get_by_hash(self.user_hash) user.username = "******" user.password = "******" user.spreedly_token = None user.put() response = self.test_app.get("/account/" + self.user_hash, self._TEST_PARAMS) # We should be redirected to a personal spreedly page. self.assertEqual(302, response.status_int) self.assertIn("subs.pinpayments.com", response.location) self.assertIn(self.test_plan.plan_id, response.location) self.assertIn(str(user.key().id()), response.location) self.assertIn("testy.testerson", response.location)
def test_trivial_failures(self): # Give it a bad hash. bad_params = {"hash": "badhash"} response = self.test_app.post("/tasks/create_user", bad_params, expect_errors=True) self.assertEqual(422, response.status_int) # Give it a user with a username already. user = Membership.get_by_hash(self.user_hash) user.username = "******" user.put() response = self.test_app.post("/tasks/create_user", self.params) # This should be okay, because we don't want PinPayments to think it needs # to retry the call. self.assertEqual(200, response.status_int)
def get(self, hash): membership = Membership.get_by_hash(hash) if membership: # steal this part to detect if they registered with hacker dojo email above first_part = re.compile(r'[^\w]').sub('', membership.first_name.split(' ')[0]) # First word of first name last_part = re.compile(r'[^\w]').sub('', membership.last_name) if len(first_part)+len(last_part) >= 15: last_part = last_part[0] # Just last initial username = '******'.join([first_part, last_part]).lower() if username in fetch_usernames(): username = membership.email.split('@')[0].lower() if self.request.get('u'): pick_username = True message = escape(self.request.get('message')) account_url = str('/account/%s' % membership.hash) self.response.out.write(render('templates/account.html', locals())) else: self.response.out.write("404 Not Found")
def test_requirements(self): # Giving it passwords that don't match should be a problem. params = self._TEST_PARAMS.copy() params["password"] = "******" params["password_confirm"] = "stillnotasecret" query = urllib.urlencode(params) response = self.test_app.post("/account/" + self.user_hash, query, expect_errors=True) self.assertEqual(422, response.status_int) self.assertIn("do not match", response.body) # The plan should be in there correctly. self.assertIn("value=\"test\"", response.body) # Giving it a password that is too short should also be a problem. params = self._TEST_PARAMS.copy() params["password"] = "******" params["password_confirm"] = "daniel" query = urllib.urlencode(params) response = self.test_app.post("/account/" + self.user_hash, query, expect_errors=True) self.assertEqual(422, response.status_int) self.assertIn("at least 8 characters", response.body) self.assertIn("value=\"test\"", response.body) user = Membership.get_by_hash(self.user_hash) user.domain_user = True user.put() # If there is already a domain account associated with this user, we should # fail as well. query = urllib.urlencode(self._TEST_PARAMS) response = self.test_app.post("/account/" + self.user_hash, query, expect_errors=True) self.assertEqual(422, response.status_int) self.assertIn("already have an account", response.body) self.assertIn("value=\"test\"", response.body)
def post(self, hash): username = self.request.get("username") password = self.request.get("password") plan = self.request.get("plan") plan_object = plans.Plan.get_by_name(plan) account_url = str("/account/%s" % hash) conf = Config() if password != self.request.get("password_confirm"): self.response.out.write( self.render("templates/account.html", locals(), message="Passwords do not match.")) self.response.set_status(422) return elif len(password) < 8: self.response.out.write( self.render("templates/account.html", locals(), message="Password must be at least 8 characters.")) self.response.set_status(422) return membership = Membership.get_by_hash(hash) if membership.domain_user: logging.warning( "Duplicate user '%s' should have been caught" \ " in first step." % (membership.username)) self.response.out.write( self.render("templates/account.html", locals(), message="You already have an account.")) self.response.set_status(422) return # Start saving the parameters for new-style accounts now, so that these # people won't have to re-enter anything when we make the transition. membership.set_password(password) # Set a username and password in the datastore. membership.username = username membership.password = password membership.put() if membership.status in ("active", "no_visits"): taskqueue.add(url="/tasks/create_user", method="POST", params={ "hash": membership.hash, "username": username, "password": password }, countdown=3) self.redirect( str("http://%s/success/%s" % (self.request.host, membership.hash))) return customer_id = membership.key().id() # All our giftcards start out with 1337. if (membership.referrer and "1337" in membership.referrer): if len(membership.referrer) != 16: message = "<p>Error: code must be 16 digits." message += "<p>Please contact %s if you believe this \ message is in error and we can help!" % \ (conf.SIGNUP_HELP_EMAIL) message += "<p><a href=\"/\">Start again</a>" internal = False self.response.out.write( self.render("templates/error.html", locals())) self.response.set_status(422) return # A unique number on all the giftcards. serial = membership.referrer[4:8] # How we know it's valid. hash = membership.referrer[8:16] confirmation_hash = re.sub( "[a-f]", "", hashlib.sha1(serial + keymaster.get("code:hash")).hexdigest())[:8] if hash != confirmation_hash: message = "<p>Error: this code was invalid: %s" % \ (membership.referrer) message += "<p>Please contact %s if you believe this \ message is in error and we can help!" % \ (conf.SIGNUP_HELP_EMAIL) message += "<p><a href=\"/\">Start again</a>" internal = False uc = UsedCode(code=membership.referrer, email=membership.email, extra="invalid code") uc.put() self.response.out.write( self.render("templates/error.html", locals())) self.response.set_status(422) return previous = UsedCode.all().filter("code =", membership.referrer).get() if previous: message = "<p>Error: this code has already been used: " + membership.referrer message += "<p>Please contact %s if you believe this" \ " message is in error and we can help!" % \ (conf.SIGNUP_HELP_EMAIL) message += "<p><a href=\"/\">Start again</a>" internal = False uc = UsedCode(code=membership.referrer, email=membership.email, extra="2nd+ attempt") uc.put() self.response.out.write( self.render("templates/error.html", locals())) self.response.set_status(422) return # If we're testing, I don't want it doing random things on # pinpayments. if not Config().is_testing: headers = {"Authorization": "Basic %s" % \ base64.b64encode("%s:X" % conf.get_api_key()), "Content-Type":"application/xml"} # Create subscriber data = "<subscriber><customer-id>%s</customer-id><email>%s</email></subscriber>" % ( customer_id, membership.email) resp = \ urlfetch.fetch("https://subs.pinpayments.com" "/api/v4/%s/subscribers.xml" % \ (conf.SPREEDLY_ACCOUNT), method="POST", payload=data, headers = headers, deadline=5) # Credit data = "<credit><amount>95.00</amount></credit>" resp = \ urlfetch.fetch("https://subs.pinpayments.com/api/v4" "/%s/subscribers/%s/credits.xml" % \ (conf.SPREEDLY_ACCOUNT, customer_id), method="POST", payload=data, headers=headers, deadline=5) uc = UsedCode(code=membership.referrer, email=membership.email, extra="OK") uc.put() # Redirect them to the PinPayments page, where they actually pay. self.redirect( membership.new_subscribe_url(self.request.host, plan=plan))
def post(self, hash): username = self.request.get("username") password = self.request.get("password") plan = self.request.get("plan") plan_object = plans.Plan.get_by_name(plan) account_url = str("/account/%s" % hash) conf = Config() if password != self.request.get("password_confirm"): self.response.out.write(self.render("templates/account.html", locals(), message="Passwords do not match.")) self.response.set_status(422) return elif len(password) < 8: self.response.out.write( self.render("templates/account.html", locals(), message="Password must be at least 8 characters.") ) self.response.set_status(422) return membership = Membership.get_by_hash(hash) if membership.domain_user: logging.warning("Duplicate user '%s' should have been caught" " in first step." % (membership.username)) self.response.out.write( self.render("templates/account.html", locals(), message="You already have an account.") ) self.response.set_status(422) return # Start saving the parameters for new-style accounts now, so that these # people won't have to re-enter anything when we make the transition. membership.set_password(password) # Set a username and password in the datastore. membership.username = username membership.password = password membership.put() if membership.status in ("active", "no_visits"): taskqueue.add( url="/tasks/create_user", method="POST", params={"hash": membership.hash, "username": username, "password": password}, countdown=3, ) self.redirect(str("http://%s/success/%s" % (self.request.host, membership.hash))) return customer_id = membership.key().id() # All our giftcards start out with 1337. if membership.referrer and "1337" in membership.referrer: if len(membership.referrer) != 16: message = "<p>Error: code must be 16 digits." message += ( "<p>Please contact %s if you believe this \ message is in error and we can help!" % (conf.SIGNUP_HELP_EMAIL) ) message += '<p><a href="/">Start again</a>' internal = False self.response.out.write(self.render("templates/error.html", locals())) self.response.set_status(422) return # A unique number on all the giftcards. serial = membership.referrer[4:8] # How we know it's valid. hash = membership.referrer[8:16] confirmation_hash = re.sub("[a-f]", "", hashlib.sha1(serial + keymaster.get("code:hash")).hexdigest())[:8] if hash != confirmation_hash: message = "<p>Error: this code was invalid: %s" % (membership.referrer) message += ( "<p>Please contact %s if you believe this \ message is in error and we can help!" % (conf.SIGNUP_HELP_EMAIL) ) message += '<p><a href="/">Start again</a>' internal = False uc = UsedCode(code=membership.referrer, email=membership.email, extra="invalid code") uc.put() self.response.out.write(self.render("templates/error.html", locals())) self.response.set_status(422) return previous = UsedCode.all().filter("code =", membership.referrer).get() if previous: message = "<p>Error: this code has already been used: " + membership.referrer message += "<p>Please contact %s if you believe this" " message is in error and we can help!" % ( conf.SIGNUP_HELP_EMAIL ) message += '<p><a href="/">Start again</a>' internal = False uc = UsedCode(code=membership.referrer, email=membership.email, extra="2nd+ attempt") uc.put() self.response.out.write(self.render("templates/error.html", locals())) self.response.set_status(422) return # If we're testing, I don't want it doing random things on # pinpayments. if not Config().is_testing: headers = { "Authorization": "Basic %s" % base64.b64encode("%s:X" % conf.get_api_key()), "Content-Type": "application/xml", } # Create subscriber data = "<subscriber><customer-id>%s</customer-id><email>%s</email></subscriber>" % ( customer_id, membership.email, ) resp = urlfetch.fetch( "https://subs.pinpayments.com" "/api/v4/%s/subscribers.xml" % (conf.SPREEDLY_ACCOUNT), method="POST", payload=data, headers=headers, deadline=5, ) # Credit data = "<credit><amount>95.00</amount></credit>" resp = urlfetch.fetch( "https://subs.pinpayments.com/api/v4" "/%s/subscribers/%s/credits.xml" % (conf.SPREEDLY_ACCOUNT, customer_id), method="POST", payload=data, headers=headers, deadline=5, ) uc = UsedCode(code=membership.referrer, email=membership.email, extra="OK") uc.put() # Redirect them to the PinPayments page, where they actually pay. self.redirect(membership.new_subscribe_url(self.request.host, plan=plan))
def post(self): """ Report a failure of this task. """ def fail(exception): logging.error("CreateUserTask failed: %s" % exception) mail.send_mail(sender=Config().EMAIL_FROM, to=Config().INTERNAL_DEV_EMAIL, subject="[%s] CreateUserTask failure" % Config().APP_NAME, body=str(exception)) self.response.set_status(500) """ Retry this task. countdown: How long to wait before running it again. """ def retry(countdown=3): retries = int(self.request.get("retries", 0)) + 1 if retries <= 5: taskqueue.add(url="/tasks/create_user", method="POST", countdown=countdown, params={ "hash": self.request.get("hash"), "username": self.request.get("username"), "password": self.request.get("password"), "retries": retries }) else: logging.error("Too many retries for %s" % self.request.get("hash")) # We don't want it to retry again. self.response.set_status(200) user_hash = self.request.get("hash") membership = Membership.get_by_hash(user_hash) if membership is None: logging.error("Got nonexistent hash: %s" % (user_hash)) self.response.set_status(422) return if membership.domain_user: logging.warning( "Not creating domain account for already-existing user '%s'." \ % (membership.username)) # Don't set another status here, because we don't want the # PinPayments system to keep retrying the call. return if not membership.spreedly_token: logging.warn("CreateUserTask: No spreedly token yet, retrying") return retry(300) username = self.request.get("username") password = self.request.get("password") try: url = "http://%s/users" % Config().DOMAIN_HOST payload = urllib.urlencode({ "username": username, "password": password, "first_name": membership.first_name, "last_name": membership.last_name, }) logging.info("CreateUserTask: About to create user: "******"CreateUserTask: URL: " + url) logging.info("CreateUserTask: Payload: " + payload) if not Config().is_testing: resp = urlfetch.fetch(url, method="POST", payload=payload, deadline=120, follow_redirects=False) if resp.status_code == 200: logging.info("I think that worked.") else: logging.error("I think that failed: HTTP %d" % (resp.status_code)) return retry() else: # I want to see what query string it would have used. self.response.out.write(payload) # Invalidate the current cached usernames, since we added a new one. self.invalidate_cached_usernames() membership.domain_user = True # We'll never use the password again, and there's no sense in # leaving this sensitive information sitting in the datastore, so we # might as well get rid of it. membership.password = None membership.put() # Send the welcome email. SuccessHandler.send_email(self, membership) except urlfetch.DownloadError, e: logging.error("Domain app response error or timeout, retrying") return retry()
def post(self): def fail(exception): logging.error("CreateUserTask failed: %s" % exception) mail.send_mail(sender=Config().EMAIL_FROM, to=Config().INTERNAL_DEV_EMAIL, subject="[%s] CreateUserTask failure" % Config().APP_NAME, body=str(exception)) self.response.set_status(500) def retry(countdown=3): retries = int(self.request.get("retries", 0)) + 1 if retries <= 5: taskqueue.add(url="/tasks/create_user", method="POST", countdown=countdown, params={"hash": self.request.get("hash"), "username": self.request.get("username"), "password": self.request.get("password"), "retries": retries}) else: fail(Exception("Too many retries for %s" % self.request.get("hash"))) user_hash = self.request.get("hash") membership = Membership.get_by_hash(user_hash) if membership is None: logging.error("Got nonexistent hash: %s" % (user_hash)) self.response.set_status(422) return if membership.domain_user: logging.warning( "Not creating domain account for already-existing user '%s'." \ % (membership.username)) # Don't set another status here, because we don't want the # PinPayments system to keep retrying the call. return if not membership.spreedly_token: logging.warn("CreateUserTask: No spreedly token yet, retrying") return retry(300) username = self.request.get("username") password = self.request.get("password") try: url = "http://%s/users" % Config().DOMAIN_HOST payload = urllib.urlencode({ "username": username, "password": password, "first_name": membership.first_name, "last_name": membership.last_name, }) logging.info("CreateUserTask: About to create user: "******"CreateUserTask: URL: "+url) logging.info("CreateUserTask: Payload: "+payload) if not Config().is_testing: resp = urlfetch.fetch(url, method="POST", payload=payload, deadline=120, follow_redirects=False) logging.warning("CreateUserTask: I think that worked: HTTP %d" % \ (resp.status_code)) else: # I want to see what query string it would have used. self.response.out.write(payload) membership.domain_user = True # We'll never use the password again, and there's no sense in # leaving this sensitive information sitting in the datastore, so we # might as well get rid of it. membership.password = None membership.put() # Send the welcome email. SuccessHandler.send_email(self, membership) except urlfetch.DownloadError, e: logging.warn("CreateUserTask: API response error or timeout, retrying") return retry()
def post(self, hash): username = self.request.get('username') password = self.request.get('password') c = Config() if password != self.request.get('password_confirm'): self.redirect(str(self.request.path + "?message=Passwords don't match")) elif len(password) < 8: self.redirect(str(self.request.path + "?message=Password must be 8 characters or longer")) else: membership = Membership.get_by_hash(hash) if membership.username: self.redirect(str(self.request.path + "?message=You already have a user account")) return # Yes, storing their username and password temporarily so we can make their account later memcache.set(str(hashlib.sha1(str(membership.hash)+c.SPREEDLY_APIKEY).hexdigest()), '%s:%s' % (username, password), time=3600) if membership.status == 'active': taskqueue.add(url='/tasks/create_user', method='POST', params={'hash': membership.hash}, countdown=3) self.redirect(str('http://%s/success/%s' % (self.request.host, membership.hash))) else: customer_id = membership.key().id() # This code is not weird... if "1337" in membership.referrer: if len(membership.referrer) !=16: error = "<p>Error: code must be 16 digits." error += "<p>Please contact "+ SIGNUP_HELP_EMAIL+" if you believe this message is in error and we can help!" error += "<p><a href='/'>Start again</a>" self.response.out.write(render('templates/error.html', locals())) return serial = membership.referrer[4:8] hash = membership.referrer[8:16] confirmation_hash = re.sub('[a-f]','',hashlib.sha1(serial+keymaster.get('code:hash')).hexdigest())[:8] if hash != confirmation_hash: error = "<p>Error: this code was invavlid: "+ membership.referrer error += "<p>Please contact "+ SIGNUP_HELP_EMAIL+" if you believe this message is in error and we can help!" error += "<p><a href='/'>Start again</a>" uc = UsedCode(code=membership.referrer,email=membership.email,extra="invalid code") uc.put() self.response.out.write(render('templates/error.html', locals())) return previous = UsedCode.all().filter('code =', membership.referrer).get() if previous: error = "<p>Error: this code has already been used: "+ membership.referrer error += "<p>Please contact "+ SIGNUP_HELP_EMAIL+" if you believe this message is in error and we can help!" error += "<p><a href='/'>Start again</a>" uc = UsedCode(code=membership.referrer,email=membership.email,extra="2nd+ attempt") uc.put() self.response.out.write(render('templates/error.html', locals())) return headers = {'Authorization': "Basic %s" % base64.b64encode('%s:X' % c.SPREEDLY_APIKEY), 'Content-Type':'application/xml'} # Create subscriber data = "<subscriber><customer-id>%s</customer-id><email>%s</email></subscriber>" % (customer_id, membership.email) resp = urlfetch.fetch("https://subs.pinpayments.com/api/v4/%s/subscribers.xml" % (c.SPREEDLY_ACCOUNT), method='POST', payload=data, headers = headers, deadline=5) # Credit data = "<credit><amount>95.00</amount></credit>" resp = urlfetch.fetch("https://subs.pinpayments.com/api/v4/%s/subscribers/%s/credits.xml" % (c.SPREEDLY_ACCOUNT, customer_id), method='POST', payload=data, headers=headers, deadline=5) uc = UsedCode(code=membership.referrer,email=membership.email,extra='OK') uc.put() query_str = urllib.urlencode({'first_name': membership.first_name, 'last_name': membership.last_name, 'email': membership.email, 'return_url': 'http://%s/success/%s' % (self.request.host, membership.hash)}) # check if they are active already since we didn't create a new member above # apparently the URL will be different self.redirect(str("https://spreedly.com/%s/subscribers/%s/subscribe/%s/%s?%s" % (c.SPREEDLY_ACCOUNT, customer_id, c.PLAN_IDS[membership.plan], username, query_str)))