User.plan with an enum instead of User.upgraded
This commit is contained in:
parent
cb145b9fd0
commit
0156b05d4d
2
Pipfile
2
Pipfile
|
@ -19,9 +19,9 @@ hashids = "==1.2.0"
|
||||||
psycopg2 = "==2.7.4"
|
psycopg2 = "==2.7.4"
|
||||||
redis = "==2.10.5"
|
redis = "==2.10.5"
|
||||||
requests = "==2.1.0"
|
requests = "==2.1.0"
|
||||||
|
SQLAlchemy = "==1.0.13"
|
||||||
stripe = "==1.55.0"
|
stripe = "==1.55.0"
|
||||||
structlog = "==16.1.0"
|
structlog = "==16.1.0"
|
||||||
SQLAlchemy = "==1.0.13"
|
|
||||||
Flask = "==1"
|
Flask = "==1"
|
||||||
Flask-CDN = "==1.5.3"
|
Flask-CDN = "==1.5.3"
|
||||||
Flask-Cors = "==3.0.2"
|
Flask-Cors = "==3.0.2"
|
||||||
|
|
|
@ -14,7 +14,7 @@ from .models import Form, Submission
|
||||||
@login_required
|
@login_required
|
||||||
def list():
|
def list():
|
||||||
# grab all the forms this user controls
|
# grab all the forms this user controls
|
||||||
if current_user.upgraded:
|
if current_user.has_feature('dashboard'):
|
||||||
forms = current_user.forms.order_by(Form.id.desc()).all()
|
forms = current_user.forms.order_by(Form.id.desc()).all()
|
||||||
else:
|
else:
|
||||||
forms = []
|
forms = []
|
||||||
|
@ -22,8 +22,8 @@ def list():
|
||||||
return jsonify({
|
return jsonify({
|
||||||
'ok': True,
|
'ok': True,
|
||||||
'user': {
|
'user': {
|
||||||
'upgraded': current_user.upgraded,
|
'features': {f: True for f in current_user.features},
|
||||||
'email': current_user.email
|
'email': current_user.email
|
||||||
},
|
},
|
||||||
'forms': [f.serialize() for f in forms]
|
'forms': [f.serialize() for f in forms]
|
||||||
})
|
})
|
||||||
|
@ -37,8 +37,8 @@ def create():
|
||||||
if referrer != service:
|
if referrer != service:
|
||||||
return jsonerror(400, {'error': 'Improper request.'})
|
return jsonerror(400, {'error': 'Improper request.'})
|
||||||
|
|
||||||
if not current_user.upgraded:
|
if not current_user.has_feature('dashboard'):
|
||||||
g.log.info('Failed to create form from dashboard. User is not upgraded.')
|
g.log.info('Failed to create form from dashboard. Forbidden.')
|
||||||
return jsonerror(402, {'error': "Please upgrade your account."})
|
return jsonerror(402, {'error': "Please upgrade your account."})
|
||||||
|
|
||||||
email = request.get_json().get('email')
|
email = request.get_json().get('email')
|
||||||
|
@ -97,7 +97,7 @@ def create():
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
def get(hashid):
|
def get(hashid):
|
||||||
if not current_user.upgraded:
|
if not current_user.has_feature('dashboard'):
|
||||||
return jsonerror(402, {'error': "Please upgrade your account."})
|
return jsonerror(402, {'error': "Please upgrade your account."})
|
||||||
|
|
||||||
form = Form.get_with_hashid(hashid)
|
form = Form.get_with_hashid(hashid)
|
||||||
|
|
|
@ -6,6 +6,8 @@ import datetime
|
||||||
from flask import url_for, render_template, render_template_string, g
|
from flask import url_for, render_template, render_template_string, g
|
||||||
from sqlalchemy.sql import table
|
from sqlalchemy.sql import table
|
||||||
from sqlalchemy.sql.expression import delete
|
from sqlalchemy.sql.expression import delete
|
||||||
|
from sqlalchemy.dialects.postgresql import JSON
|
||||||
|
from sqlalchemy.ext.mutable import MutableDict
|
||||||
from sqlalchemy import func
|
from sqlalchemy import func
|
||||||
from werkzeug.datastructures import ImmutableMultiDict, \
|
from werkzeug.datastructures import ImmutableMultiDict, \
|
||||||
ImmutableOrderedMultiDict
|
ImmutableOrderedMultiDict
|
||||||
|
@ -14,6 +16,7 @@ from formspree import settings
|
||||||
from formspree.stuff import DB, redis_store, TEMPLATES
|
from formspree.stuff import DB, redis_store, TEMPLATES
|
||||||
from formspree.utils import send_email, unix_time_for_12_months_from_now, \
|
from formspree.utils import send_email, unix_time_for_12_months_from_now, \
|
||||||
next_url, IS_VALID_EMAIL, request_wants_json
|
next_url, IS_VALID_EMAIL, request_wants_json
|
||||||
|
from formspree.users.models import Plan
|
||||||
from .helpers import HASH, HASHIDS_CODEC, REDIS_COUNTER_KEY, \
|
from .helpers import HASH, HASHIDS_CODEC, REDIS_COUNTER_KEY, \
|
||||||
http_form_to_dict, referrer_to_path, \
|
http_form_to_dict, referrer_to_path, \
|
||||||
store_first_submission, fetch_first_submission, \
|
store_first_submission, fetch_first_submission, \
|
||||||
|
@ -103,10 +106,9 @@ class Form(DB.Model):
|
||||||
.filter(Form.id == self.id)
|
.filter(Form.id == self.id)
|
||||||
return by_email.union(by_creation)
|
return by_email.union(by_creation)
|
||||||
|
|
||||||
@property
|
def has_feature(self, feature):
|
||||||
def upgraded(self):
|
c = [user for user in self.controllers if user.has_feature(feature)]
|
||||||
upgraded_controllers = [i for i in self.controllers if i.upgraded]
|
return len(c) > 0
|
||||||
return len(upgraded_controllers) > 0
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_with_hashid(cls, hashid):
|
def get_with_hashid(cls, hashid):
|
||||||
|
@ -207,8 +209,8 @@ class Form(DB.Model):
|
||||||
# increment the forms counter
|
# increment the forms counter
|
||||||
self.counter = Form.counter + 1
|
self.counter = Form.counter + 1
|
||||||
|
|
||||||
# if submission storage is disabled and form is upgraded, don't store submission
|
# if submission storage is disabled, don't store submission
|
||||||
if self.disable_storage and self.upgraded:
|
if self.disable_storage and self.has_feature('dashboard'):
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
DB.session.add(self)
|
DB.session.add(self)
|
||||||
|
@ -239,17 +241,18 @@ class Form(DB.Model):
|
||||||
# url to request_unconfirm_form page
|
# url to request_unconfirm_form page
|
||||||
unconfirm = url_for('request_unconfirm_form', form_id=self.id, _external=True)
|
unconfirm = url_for('request_unconfirm_form', form_id=self.id, _external=True)
|
||||||
|
|
||||||
# check if the forms are over the counter and the user is not upgraded
|
# check if the forms are over the counter and the user has unlimited submissions
|
||||||
overlimit = False
|
overlimit = False
|
||||||
monthly_counter = self.get_monthly_counter()
|
monthly_counter = self.get_monthly_counter()
|
||||||
monthly_limit = settings.MONTHLY_SUBMISSIONS_LIMIT \
|
monthly_limit = settings.MONTHLY_SUBMISSIONS_LIMIT \
|
||||||
if self.id > settings.FORM_LIMIT_DECREASE_ACTIVATION_SEQUENCE \
|
if self.id > settings.FORM_LIMIT_DECREASE_ACTIVATION_SEQUENCE \
|
||||||
else settings.GRANDFATHER_MONTHLY_LIMIT
|
else settings.GRANDFATHER_MONTHLY_LIMIT
|
||||||
|
|
||||||
if monthly_counter > monthly_limit and not self.upgraded:
|
if monthly_counter > monthly_limit and not self.has_feature('unlimited'):
|
||||||
overlimit = True
|
overlimit = True
|
||||||
|
|
||||||
if monthly_counter == int(monthly_limit * 0.9) and not self.upgraded:
|
if monthly_counter == int(monthly_limit * 0.9) and \
|
||||||
|
not self.has_feature('unlimited'):
|
||||||
# send email notification
|
# send email notification
|
||||||
send_email(
|
send_email(
|
||||||
to=self.email,
|
to=self.email,
|
||||||
|
@ -295,8 +298,8 @@ class Form(DB.Model):
|
||||||
else:
|
else:
|
||||||
return {'code': Form.STATUS_OVERLIMIT}
|
return {'code': Form.STATUS_OVERLIMIT}
|
||||||
|
|
||||||
# if emails are disabled and form is upgraded, don't send email notification
|
# if emails are disabled, don't send email notification
|
||||||
if self.disable_email and self.upgraded:
|
if self.disable_email and self.has_feature('dashboard'):
|
||||||
return {'code': Form.STATUS_NO_EMAIL, 'next': next}
|
return {'code': Form.STATUS_NO_EMAIL, 'next': next}
|
||||||
else:
|
else:
|
||||||
result = send_email(
|
result = send_email(
|
||||||
|
@ -483,15 +486,12 @@ class Form(DB.Model):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
from sqlalchemy.dialects.postgresql import JSON
|
|
||||||
from sqlalchemy.ext.mutable import MutableDict
|
|
||||||
|
|
||||||
class Submission(DB.Model):
|
class Submission(DB.Model):
|
||||||
__tablename__ = 'submissions'
|
__tablename__ = 'submissions'
|
||||||
|
|
||||||
id = DB.Column(DB.Integer, primary_key=True)
|
id = DB.Column(DB.Integer, primary_key=True)
|
||||||
submitted_at = DB.Column(DB.DateTime)
|
submitted_at = DB.Column(DB.DateTime)
|
||||||
form_id = DB.Column(DB.Integer, DB.ForeignKey('forms.id'))
|
form_id = DB.Column(DB.Integer, DB.ForeignKey('forms.id'), nullable=False)
|
||||||
data = DB.Column(MutableDict.as_mutable(JSON))
|
data = DB.Column(MutableDict.as_mutable(JSON))
|
||||||
|
|
||||||
def __init__(self, form_id):
|
def __init__(self, form_id):
|
||||||
|
|
|
@ -195,8 +195,8 @@ def send(email_or_string):
|
||||||
captcha_verified or
|
captcha_verified or
|
||||||
settings.TESTING)
|
settings.TESTING)
|
||||||
|
|
||||||
# if form is upgraded check if captcha is disabled
|
# check if captcha is disabled
|
||||||
if form.upgraded:
|
if form.has_feature('dashboard'):
|
||||||
needs_captcha = needs_captcha and not form.captcha_disabled
|
needs_captcha = needs_captcha and not form.captcha_disabled
|
||||||
|
|
||||||
if needs_captcha:
|
if needs_captcha:
|
||||||
|
@ -492,7 +492,7 @@ def serve_dashboard(hashid=None, s=None):
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
def export_submissions(hashid, format=None):
|
def export_submissions(hashid, format=None):
|
||||||
if not current_user.upgraded:
|
if not current_user.has_feature('dashboard'):
|
||||||
return jsonerror(402, {'error': "Please upgrade your account."})
|
return jsonerror(402, {'error': "Please upgrade your account."})
|
||||||
|
|
||||||
form = Form.get_with_hashid(hashid)
|
form = Form.get_with_hashid(hashid)
|
||||||
|
|
|
@ -36,7 +36,7 @@ module.exports = class CreateForm extends React.Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
if (!this.props.user.upgraded) {
|
if (!this.props.user.features.dashboard) {
|
||||||
return (
|
return (
|
||||||
<div className="col-1-1 create-form">
|
<div className="col-1-1 create-form">
|
||||||
<h6 className="light">
|
<h6 className="light">
|
||||||
|
|
|
@ -109,7 +109,7 @@ module.exports = class FormList extends React.Component {
|
||||||
|
|
||||||
{this.state.enabled_forms.length === 0 &&
|
{this.state.enabled_forms.length === 0 &&
|
||||||
this.state.disabled_forms.length === 0 &&
|
this.state.disabled_forms.length === 0 &&
|
||||||
this.state.user.upgraded ? (
|
this.state.user.features.dashboard ? (
|
||||||
<h6 className="light">
|
<h6 className="light">
|
||||||
You don't have any forms associated with this account, maybe you
|
You don't have any forms associated with this account, maybe you
|
||||||
should <a href="/account">verify your email</a>.
|
should <a href="/account">verify your email</a>.
|
||||||
|
|
|
@ -64,7 +64,7 @@
|
||||||
<div class="menu">
|
<div class="menu">
|
||||||
{% if request.path != '/' %}<span class="item"><a href="/">Home</a></span>{% endif %}
|
{% if request.path != '/' %}<span class="item"><a href="/">Home</a></span>{% endif %}
|
||||||
<span class="item"><a href="{{ url_for('dashboard') }}">Your forms</a></span>
|
<span class="item"><a href="{{ url_for('dashboard') }}">Your forms</a></span>
|
||||||
<span class="item"><a href="{{ url_for('account') }}">{% if current_user.upgraded %}Your{% else %}Upgrade{% endif %} account</a></span>
|
<span class="item"><a href="{{ url_for('account') }}">{% if current_user.has_feature('dashboard') %}Your{% else %}Upgrade{% endif %} account</a></span>
|
||||||
{% else %}
|
{% else %}
|
||||||
<div class="greetings">
|
<div class="greetings">
|
||||||
<h4 class="light">
|
<h4 class="light">
|
||||||
|
|
|
@ -43,7 +43,7 @@
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<h3>Plan</h3>
|
<h3>Plan</h3>
|
||||||
|
|
||||||
{% if current_user.upgraded %}
|
{% if current_user.has_feature('dashboard') %}
|
||||||
<p>You are a {{ config.SERVICE_NAME }} {{ config.UPGRADED_PLAN_NAME }} user.</p>
|
<p>You are a {{ config.SERVICE_NAME }} {{ config.UPGRADED_PLAN_NAME }} user.</p>
|
||||||
{% if sub.cancel_at_period_end %}
|
{% if sub.cancel_at_period_end %}
|
||||||
<p>You've cancelled your subscription and it is ending on {{ sub.current_period_end }}.</p>
|
<p>You've cancelled your subscription and it is ending on {{ sub.current_period_end }}.</p>
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<h3>Plan</h3>
|
<h3>Plan</h3>
|
||||||
|
|
||||||
{% if current_user.upgraded %}
|
{% if current_user.has_feature('dashboard') %}
|
||||||
<p>You are a {{ config.SERVICE_NAME }} {{ config.UPGRADED_PLAN_NAME }} user.</p>
|
<p>You are a {{ config.SERVICE_NAME }} {{ config.UPGRADED_PLAN_NAME }} user.</p>
|
||||||
{% if sub.cancel_at_period_end %}
|
{% if sub.cancel_at_period_end %}
|
||||||
<p>You've cancelled your subscription and it is ending on {{ sub.current_period_end }}.</p>
|
<p>You've cancelled your subscription and it is ending on {{ sub.current_period_end }}.</p>
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
|
|
||||||
<div class="row section grey">
|
<div class="row section grey">
|
||||||
<div class="container narrow block">
|
<div class="container narrow block">
|
||||||
{% if current_user.upgraded %}
|
{% if current_user.has_feature('dashboard') %}
|
||||||
<div class="col-1-2">
|
<div class="col-1-2">
|
||||||
<p>{{config.SERVICE_NAME}} is a tool <a href="https://github.com/formspree/formspree">managed on GitHub</a>. For fastest support check out our <a href="https://help.formspree.io">knowledge base</a> or use the form on the right.</p>
|
<p>{{config.SERVICE_NAME}} is a tool <a href="https://github.com/formspree/formspree">managed on GitHub</a>. For fastest support check out our <a href="https://help.formspree.io">knowledge base</a> or use the form on the right.</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import hmac
|
import hmac
|
||||||
import hashlib
|
import hashlib
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
from flask import url_for, render_template, render_template_string, g
|
from flask import url_for, render_template, render_template_string, g
|
||||||
|
|
||||||
from formspree import settings
|
from formspree import settings
|
||||||
|
@ -8,13 +9,30 @@ from formspree.stuff import DB, TEMPLATES
|
||||||
from formspree.utils import send_email, IS_VALID_EMAIL
|
from formspree.utils import send_email, IS_VALID_EMAIL
|
||||||
from .helpers import hash_pwd
|
from .helpers import hash_pwd
|
||||||
|
|
||||||
|
|
||||||
|
class Plan(DB.Enum):
|
||||||
|
free = 'v1_free'
|
||||||
|
gold = 'v1_gold'
|
||||||
|
platinum = 'v1_platinum'
|
||||||
|
|
||||||
|
plan_features = {
|
||||||
|
'v1_free': set(),
|
||||||
|
'v1_gold': {'dashboard', 'unlimited'},
|
||||||
|
'v1_platinum': {'dashboard', 'unlimited', 'whitelabel'}
|
||||||
|
}
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def has_feature(cls, plan, feature_id):
|
||||||
|
return feature_id in cls.plan_features[plan]
|
||||||
|
|
||||||
|
|
||||||
class User(DB.Model):
|
class User(DB.Model):
|
||||||
__tablename__ = 'users'
|
__tablename__ = 'users'
|
||||||
|
|
||||||
id = DB.Column(DB.Integer, primary_key=True)
|
id = DB.Column(DB.Integer, primary_key=True)
|
||||||
email = DB.Column(DB.Text, unique=True, index=True)
|
email = DB.Column(DB.Text, unique=True, index=True)
|
||||||
password = DB.Column(DB.String(100))
|
password = DB.Column(DB.String(100))
|
||||||
upgraded = DB.Column(DB.Boolean)
|
plan = DB.Column(DB.Enum(*Plan.plan_features.keys(), name='plans'), nullable=False)
|
||||||
stripe_id = DB.Column(DB.String(50))
|
stripe_id = DB.Column(DB.String(50))
|
||||||
registered_on = DB.Column(DB.DateTime)
|
registered_on = DB.Column(DB.DateTime)
|
||||||
invoice_address = DB.Column(DB.Text)
|
invoice_address = DB.Column(DB.Text)
|
||||||
|
@ -40,7 +58,7 @@ class User(DB.Model):
|
||||||
|
|
||||||
self.email = email
|
self.email = email
|
||||||
self.password = hash_pwd(password)
|
self.password = hash_pwd(password)
|
||||||
self.upgraded = False
|
self.plan = Plan.free
|
||||||
self.registered_on = datetime.utcnow()
|
self.registered_on = datetime.utcnow()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
@ -55,6 +73,13 @@ class User(DB.Model):
|
||||||
def is_anonymous(self):
|
def is_anonymous(self):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
@property
|
||||||
|
def features(self):
|
||||||
|
return Plan.plan_features[self.plan]
|
||||||
|
|
||||||
|
def has_feature(self, feature_id):
|
||||||
|
return Plan.has_feature(self.plan, feature_id)
|
||||||
|
|
||||||
def get_id(self):
|
def get_id(self):
|
||||||
return self.id
|
return self.id
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@ from sqlalchemy.exc import IntegrityError
|
||||||
from formspree import settings
|
from formspree import settings
|
||||||
from formspree.stuff import DB, TEMPLATES
|
from formspree.stuff import DB, TEMPLATES
|
||||||
from formspree.utils import send_email
|
from formspree.utils import send_email
|
||||||
from .models import User, Email
|
from .models import User, Email, Plan
|
||||||
from .helpers import check_password, hash_pwd, send_downgrade_email, \
|
from .helpers import check_password, hash_pwd, send_downgrade_email, \
|
||||||
send_downgrade_reason_email
|
send_downgrade_reason_email
|
||||||
|
|
||||||
|
@ -231,7 +231,7 @@ def upgrade():
|
||||||
"error")
|
"error")
|
||||||
return redirect(url_for('dashboard'))
|
return redirect(url_for('dashboard'))
|
||||||
|
|
||||||
current_user.upgraded = True
|
current_user.plan = Plan.gold
|
||||||
DB.session.add(current_user)
|
DB.session.add(current_user)
|
||||||
DB.session.commit()
|
DB.session.commit()
|
||||||
flash(u"Congratulations! You are now a {SERVICE_NAME} "
|
flash(u"Congratulations! You are now a {SERVICE_NAME} "
|
||||||
|
@ -278,7 +278,8 @@ def downgrade():
|
||||||
if reason:
|
if reason:
|
||||||
send_downgrade_reason_email.delay(current_user.email, reason)
|
send_downgrade_reason_email.delay(current_user.email, reason)
|
||||||
|
|
||||||
sub = sub.delete(at_period_end=True)
|
sub.cancel_at_period_end = True
|
||||||
|
sub.save()
|
||||||
flash(u"You were unregistered from the {SERVICE_NAME} "
|
flash(u"You were unregistered from the {SERVICE_NAME} "
|
||||||
"{UPGRADED_PLAN_NAME} plan.".format(**settings.__dict__),
|
"{UPGRADED_PLAN_NAME} plan.".format(**settings.__dict__),
|
||||||
'success')
|
'success')
|
||||||
|
@ -310,7 +311,7 @@ def stripe_webhook():
|
||||||
customer = stripe.Customer.retrieve(customer_id)
|
customer = stripe.Customer.retrieve(customer_id)
|
||||||
if len(customer.subscriptions.data) == 0:
|
if len(customer.subscriptions.data) == 0:
|
||||||
user = User.query.filter_by(stripe_id=customer_id).first()
|
user = User.query.filter_by(stripe_id=customer_id).first()
|
||||||
user.upgraded = False
|
user.plan = Plan.free
|
||||||
DB.session.add(user)
|
DB.session.add(user)
|
||||||
DB.session.commit()
|
DB.session.commit()
|
||||||
g.log.info('Downgraded user from webhook.', account=user.email)
|
g.log.info('Downgraded user from webhook.', account=user.email)
|
||||||
|
@ -320,8 +321,10 @@ def stripe_webhook():
|
||||||
customer = stripe.Customer.retrieve(customer_id)
|
customer = stripe.Customer.retrieve(customer_id)
|
||||||
g.log.info('User payment failed', account=customer.email)
|
g.log.info('User payment failed', account=customer.email)
|
||||||
send_email(to=customer.email,
|
send_email(to=customer.email,
|
||||||
subject='[ACTION REQUIRED] Failed Payment for {} {}'.format(settings.SERVICE_NAME,
|
subject='[ACTION REQUIRED] Failed Payment for {} {}'.format(
|
||||||
settings.UPGRADED_PLAN_NAME),
|
settings.SERVICE_NAME,
|
||||||
|
settings.UPGRADED_PLAN_NAME
|
||||||
|
),
|
||||||
text=render_template('email/payment-failed.txt'),
|
text=render_template('email/payment-failed.txt'),
|
||||||
html=render_template_string(TEMPLATES.get('payment-failed.html')),
|
html=render_template_string(TEMPLATES.get('payment-failed.html')),
|
||||||
sender=settings.DEFAULT_SENDER)
|
sender=settings.DEFAULT_SENDER)
|
||||||
|
@ -433,6 +436,7 @@ def account():
|
||||||
sub.current_period_end = datetime.datetime.fromtimestamp(sub.current_period_end).strftime('%A, %B %d, %Y')
|
sub.current_period_end = datetime.datetime.fromtimestamp(sub.current_period_end).strftime('%A, %B %d, %Y')
|
||||||
except stripe.error.StripeError:
|
except stripe.error.StripeError:
|
||||||
return render_template('error.html', title='Unable to connect', text="We're unable to make a secure connection to verify your account details. Please try again in a little bit. If this problem persists, please contact <strong>%s</strong>" % settings.CONTACT_EMAIL)
|
return render_template('error.html', title='Unable to connect', text="We're unable to make a secure connection to verify your account details. Please try again in a little bit. If this problem persists, please contact <strong>%s</strong>" % settings.CONTACT_EMAIL)
|
||||||
|
|
||||||
return render_template('users/account.html', emails=emails, cards=cards, sub=sub)
|
return render_template('users/account.html', emails=emails, cards=cards, sub=sub)
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
|
|
|
@ -3,7 +3,7 @@ import json
|
||||||
from formspree import settings
|
from formspree import settings
|
||||||
from formspree.stuff import DB
|
from formspree.stuff import DB
|
||||||
from formspree.forms.helpers import HASH
|
from formspree.forms.helpers import HASH
|
||||||
from formspree.users.models import User
|
from formspree.users.models import User, Plan
|
||||||
from formspree.forms.models import Form, Submission
|
from formspree.forms.models import Form, Submission
|
||||||
|
|
||||||
def test_automatically_created_forms(client, msend):
|
def test_automatically_created_forms(client, msend):
|
||||||
|
@ -147,7 +147,7 @@ def test_automatically_created_forms(client, msend):
|
||||||
assert newest.data['name'] == 'husserl'
|
assert newest.data['name'] == 'husserl'
|
||||||
assert last.data['name'] == 'schelling'
|
assert last.data['name'] == 'schelling'
|
||||||
|
|
||||||
def test_upgraded_user_access(client, msend):
|
def test_gold_user_access(client, msend):
|
||||||
# register user
|
# register user
|
||||||
r = client.post('/register',
|
r = client.post('/register',
|
||||||
data={'email': 'colorado@springs.com',
|
data={'email': 'colorado@springs.com',
|
||||||
|
@ -156,7 +156,7 @@ def test_upgraded_user_access(client, msend):
|
||||||
|
|
||||||
# upgrade user manually
|
# upgrade user manually
|
||||||
user = User.query.filter_by(email='colorado@springs.com').first()
|
user = User.query.filter_by(email='colorado@springs.com').first()
|
||||||
user.upgraded = True
|
user.plan = Plan.gold
|
||||||
DB.session.add(user)
|
DB.session.add(user)
|
||||||
DB.session.commit()
|
DB.session.commit()
|
||||||
|
|
||||||
|
@ -209,7 +209,7 @@ def test_upgraded_user_access(client, msend):
|
||||||
assert '"hi in my name is bruce!"', lines[1]
|
assert '"hi in my name is bruce!"', lines[1]
|
||||||
|
|
||||||
# test submissions endpoint with the user downgraded
|
# test submissions endpoint with the user downgraded
|
||||||
user.upgraded = False
|
user.plan = Plan.free
|
||||||
DB.session.add(user)
|
DB.session.add(user)
|
||||||
DB.session.commit()
|
DB.session.commit()
|
||||||
r = client.get("/api-int/forms/" + form_endpoint)
|
r = client.get("/api-int/forms/" + form_endpoint)
|
||||||
|
|
|
@ -2,7 +2,7 @@ import json
|
||||||
|
|
||||||
from formspree import settings
|
from formspree import settings
|
||||||
from formspree.stuff import DB
|
from formspree.stuff import DB
|
||||||
from formspree.users.models import User, Email
|
from formspree.users.models import User, Email, Plan
|
||||||
from formspree.forms.models import Form
|
from formspree.forms.models import Form
|
||||||
|
|
||||||
from .conftest import parse_confirmation_link_sent
|
from .conftest import parse_confirmation_link_sent
|
||||||
|
@ -61,7 +61,7 @@ def test_user_gets_previous_forms_assigned_to_him(client, msend):
|
||||||
link, qs = parse_confirmation_link_sent(msend.call_args[1]['text'])
|
link, qs = parse_confirmation_link_sent(msend.call_args[1]['text'])
|
||||||
client.get(link, query_string=qs)
|
client.get(link, query_string=qs)
|
||||||
|
|
||||||
# confirm that the user has no access to the form since he is not upgraded
|
# confirm that the user has no access to the form since he is not gold
|
||||||
r = client.get(
|
r = client.get(
|
||||||
"/api-int/forms",
|
"/api-int/forms",
|
||||||
headers={"Accept": "application/json", "Referer": settings.SERVICE_URL},
|
headers={"Accept": "application/json", "Referer": settings.SERVICE_URL},
|
||||||
|
@ -71,7 +71,7 @@ def test_user_gets_previous_forms_assigned_to_him(client, msend):
|
||||||
|
|
||||||
# upgrade user
|
# upgrade user
|
||||||
user = User.query.filter_by(email=u'márkö@example.com').first()
|
user = User.query.filter_by(email=u'márkö@example.com').first()
|
||||||
user.upgraded = True
|
user.plan = Plan.gold
|
||||||
DB.session.add(user)
|
DB.session.add(user)
|
||||||
DB.session.commit()
|
DB.session.commit()
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@ import json
|
||||||
from formspree import settings
|
from formspree import settings
|
||||||
from formspree.stuff import DB
|
from formspree.stuff import DB
|
||||||
from formspree.forms.helpers import HASH
|
from formspree.forms.helpers import HASH
|
||||||
from formspree.users.models import User, Email
|
from formspree.users.models import User, Email, Plan
|
||||||
from formspree.forms.models import Form, Submission
|
from formspree.forms.models import Form, Submission
|
||||||
|
|
||||||
def test_form_creation(client, msend):
|
def test_form_creation(client, msend):
|
||||||
|
@ -27,7 +27,7 @@ def test_form_creation(client, msend):
|
||||||
|
|
||||||
# upgrade user manually
|
# upgrade user manually
|
||||||
user = User.query.filter_by(email='colorado@springs.com').first()
|
user = User.query.filter_by(email='colorado@springs.com').first()
|
||||||
user.upgraded = True
|
user.plan = Plan.gold
|
||||||
DB.session.add(user)
|
DB.session.add(user)
|
||||||
DB.session.commit()
|
DB.session.commit()
|
||||||
|
|
||||||
|
@ -67,7 +67,7 @@ def test_form_creation(client, msend):
|
||||||
# Make sure that it marks the first form as AJAX
|
# Make sure that it marks the first form as AJAX
|
||||||
assert Form.query.first().uses_ajax
|
assert Form.query.first().uses_ajax
|
||||||
|
|
||||||
# send 5 forms (monthly limits should not apply to the upgraded user)
|
# send 5 forms (monthly limits should not apply to the gold user)
|
||||||
assert settings.MONTHLY_SUBMISSIONS_LIMIT == 2
|
assert settings.MONTHLY_SUBMISSIONS_LIMIT == 2
|
||||||
for i in range(5):
|
for i in range(5):
|
||||||
r = client.post(
|
r = client.post(
|
||||||
|
@ -98,7 +98,7 @@ def test_form_creation_with_a_registered_email(client, msend):
|
||||||
)
|
)
|
||||||
# upgrade user manually
|
# upgrade user manually
|
||||||
user = User.query.filter_by(email="user@testsite.com").first()
|
user = User.query.filter_by(email="user@testsite.com").first()
|
||||||
user.upgraded = True
|
user.plan = Plan.gold
|
||||||
DB.session.add(user)
|
DB.session.add(user)
|
||||||
DB.session.commit()
|
DB.session.commit()
|
||||||
|
|
||||||
|
@ -180,7 +180,7 @@ def test_sitewide_forms(client, msend, mocker):
|
||||||
)
|
)
|
||||||
# upgrade user manually
|
# upgrade user manually
|
||||||
user = User.query.filter_by(email="user@testsite.com").first()
|
user = User.query.filter_by(email="user@testsite.com").first()
|
||||||
user.upgraded = True
|
user.plan = Plan.gold
|
||||||
DB.session.add(user)
|
DB.session.add(user)
|
||||||
DB.session.commit()
|
DB.session.commit()
|
||||||
|
|
||||||
|
@ -330,7 +330,7 @@ def test_form_settings(client, msend):
|
||||||
# register and upgrade user
|
# register and upgrade user
|
||||||
client.post("/register", data={"email": "texas@springs.com", "password": "water"})
|
client.post("/register", data={"email": "texas@springs.com", "password": "water"})
|
||||||
user = User.query.filter_by(email="texas@springs.com").first()
|
user = User.query.filter_by(email="texas@springs.com").first()
|
||||||
user.upgraded = True
|
user.plan = Plan.gold
|
||||||
DB.session.add(user)
|
DB.session.add(user)
|
||||||
DB.session.commit()
|
DB.session.commit()
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
from formspree import settings
|
from formspree import settings
|
||||||
from formspree.stuff import DB
|
from formspree.stuff import DB
|
||||||
from formspree.forms.models import Form
|
from formspree.forms.models import Form
|
||||||
from formspree.users.models import User, Email
|
from formspree.users.models import User, Email, Plan
|
||||||
|
|
||||||
http_headers = {
|
http_headers = {
|
||||||
'Referer': 'testwebsite.com'
|
'Referer': 'testwebsite.com'
|
||||||
|
@ -233,13 +233,13 @@ def test_monthly_limits(client, msend):
|
||||||
assert f.counter == 3
|
assert f.counter == 3
|
||||||
assert f.get_monthly_counter() == 3 # the counters mark 4
|
assert f.get_monthly_counter() == 3 # the counters mark 4
|
||||||
|
|
||||||
# the user pays and becomes upgraded
|
# the user pays and becomes gold
|
||||||
r = client.post('/register',
|
r = client.post('/register',
|
||||||
data={'email': 'luke@testwebsite.com',
|
data={'email': 'luke@testwebsite.com',
|
||||||
'password': 'banana'}
|
'password': 'banana'}
|
||||||
)
|
)
|
||||||
user = User.query.filter_by(email='luke@testwebsite.com').first()
|
user = User.query.filter_by(email='luke@testwebsite.com').first()
|
||||||
user.upgraded = True
|
user.plan = Plan.gold
|
||||||
user.emails = [Email(address='luke@testwebsite.com')]
|
user.emails = [Email(address='luke@testwebsite.com')]
|
||||||
DB.session.add(user)
|
DB.session.add(user)
|
||||||
DB.session.commit()
|
DB.session.commit()
|
||||||
|
|
|
@ -5,7 +5,7 @@ import stripe
|
||||||
from formspree import settings
|
from formspree import settings
|
||||||
from formspree.stuff import DB
|
from formspree.stuff import DB
|
||||||
from formspree.forms.helpers import HASH
|
from formspree.forms.helpers import HASH
|
||||||
from formspree.users.models import User, Email
|
from formspree.users.models import User, Email, Plan
|
||||||
from formspree.forms.models import Form, Submission
|
from formspree.forms.models import Form, Submission
|
||||||
|
|
||||||
from .conftest import parse_confirmation_link_sent
|
from .conftest import parse_confirmation_link_sent
|
||||||
|
@ -123,7 +123,7 @@ def test_form_creation(client, msend):
|
||||||
|
|
||||||
# upgrade user manually
|
# upgrade user manually
|
||||||
user = User.query.filter_by(email='colorado@springs.com').first()
|
user = User.query.filter_by(email='colorado@springs.com').first()
|
||||||
user.upgraded = True
|
user.plan = Plan.gold
|
||||||
DB.session.add(user)
|
DB.session.add(user)
|
||||||
DB.session.commit()
|
DB.session.commit()
|
||||||
|
|
||||||
|
@ -156,7 +156,7 @@ def test_form_creation(client, msend):
|
||||||
client.get('/confirm/%s:%s' % (HASH(form.email, str(form.id)), form.hashid))
|
client.get('/confirm/%s:%s' % (HASH(form.email, str(form.id)), form.hashid))
|
||||||
assert Form.query.first().confirmed
|
assert Form.query.first().confirmed
|
||||||
|
|
||||||
# send 5 forms (monthly limits should not apply to the upgraded user)
|
# send 5 forms (monthly limits should not apply to the gold user)
|
||||||
assert settings.MONTHLY_SUBMISSIONS_LIMIT == 2
|
assert settings.MONTHLY_SUBMISSIONS_LIMIT == 2
|
||||||
for i in range(5):
|
for i in range(5):
|
||||||
r = client.post('/' + form_endpoint,
|
r = client.post('/' + form_endpoint,
|
||||||
|
@ -192,7 +192,7 @@ def test_form_toggle(client, msend):
|
||||||
|
|
||||||
# upgrade user
|
# upgrade user
|
||||||
user = User.query.filter_by(email='hello@world.com').first()
|
user = User.query.filter_by(email='hello@world.com').first()
|
||||||
user.upgraded = True
|
user.plan = Plan.gold
|
||||||
DB.session.add(user)
|
DB.session.add(user)
|
||||||
DB.session.commit()
|
DB.session.commit()
|
||||||
|
|
||||||
|
@ -281,7 +281,7 @@ def test_form_and_submission_deletion(client, msend):
|
||||||
|
|
||||||
# upgrade user
|
# upgrade user
|
||||||
user = User.query.filter_by(email='hello@world.com').first()
|
user = User.query.filter_by(email='hello@world.com').first()
|
||||||
user.upgraded = True
|
user.plan = Plan.gold
|
||||||
DB.session.add(user)
|
DB.session.add(user)
|
||||||
DB.session.commit()
|
DB.session.commit()
|
||||||
|
|
||||||
|
@ -399,7 +399,7 @@ def test_user_upgrade_and_downgrade(client, msend, mocker):
|
||||||
msend.reset_mock()
|
msend.reset_mock()
|
||||||
|
|
||||||
user = User.query.filter_by(email='maria@example.com').first()
|
user = User.query.filter_by(email='maria@example.com').first()
|
||||||
assert user.upgraded == False
|
assert user.plan == Plan.free
|
||||||
|
|
||||||
# subscribe with card through stripe
|
# subscribe with card through stripe
|
||||||
token = stripe.Token.create(card={
|
token = stripe.Token.create(card={
|
||||||
|
@ -414,7 +414,7 @@ def test_user_upgrade_and_downgrade(client, msend, mocker):
|
||||||
})
|
})
|
||||||
|
|
||||||
user = User.query.filter_by(email='maria@example.com').first()
|
user = User.query.filter_by(email='maria@example.com').first()
|
||||||
assert user.upgraded == True
|
assert user.plan == Plan.gold
|
||||||
|
|
||||||
# downgrade back to the free plan
|
# downgrade back to the free plan
|
||||||
r = client.post('/account/downgrade', follow_redirects=True)
|
r = client.post('/account/downgrade', follow_redirects=True)
|
||||||
|
@ -424,7 +424,7 @@ def test_user_upgrade_and_downgrade(client, msend, mocker):
|
||||||
assert "You've cancelled your subscription and it is ending on" in r.data.decode('utf-8')
|
assert "You've cancelled your subscription and it is ending on" in r.data.decode('utf-8')
|
||||||
|
|
||||||
user = User.query.filter_by(email='maria@example.com').first()
|
user = User.query.filter_by(email='maria@example.com').first()
|
||||||
assert user.upgraded == True
|
assert user.plan == Plan.gold
|
||||||
|
|
||||||
customer = stripe.Customer.retrieve(user.stripe_id)
|
customer = stripe.Customer.retrieve(user.stripe_id)
|
||||||
assert customer.subscriptions.data[0].cancel_at_period_end == True
|
assert customer.subscriptions.data[0].cancel_at_period_end == True
|
||||||
|
@ -445,7 +445,7 @@ def test_user_upgrade_and_downgrade(client, msend, mocker):
|
||||||
}), headers={'Content-type': 'application/json'})
|
}), headers={'Content-type': 'application/json'})
|
||||||
|
|
||||||
user = User.query.filter_by(email='maria@example.com').first()
|
user = User.query.filter_by(email='maria@example.com').first()
|
||||||
assert user.upgraded == False
|
assert user.plan == Plan.free
|
||||||
assert m_senddowngraded.called
|
assert m_senddowngraded.called
|
||||||
|
|
||||||
# delete the stripe customer
|
# delete the stripe customer
|
||||||
|
@ -465,7 +465,7 @@ def test_user_card_management(client, msend):
|
||||||
assert r.status_code == 302
|
assert r.status_code == 302
|
||||||
|
|
||||||
user = User.query.filter_by(email='maria@example.com').first()
|
user = User.query.filter_by(email='maria@example.com').first()
|
||||||
assert user.upgraded == False
|
assert user.plan == Plan.free
|
||||||
|
|
||||||
# subscribe with card through stripe
|
# subscribe with card through stripe
|
||||||
token = stripe.Token.create(card={
|
token = stripe.Token.create(card={
|
||||||
|
@ -479,7 +479,7 @@ def test_user_card_management(client, msend):
|
||||||
})
|
})
|
||||||
|
|
||||||
user = User.query.filter_by(email='maria@example.com').first()
|
user = User.query.filter_by(email='maria@example.com').first()
|
||||||
assert user.upgraded == True
|
assert user.plan == Plan.gold
|
||||||
|
|
||||||
# add another card
|
# add another card
|
||||||
token = stripe.Token.create(card={
|
token = stripe.Token.create(card={
|
||||||
|
|
Loading…
Reference in New Issue