This commit is contained in:
parent
e9faf93878
commit
5b47bd1654
@ -214,6 +214,20 @@ class UserAdmin(SLModelView):
|
||||
|
||||
Session.commit()
|
||||
|
||||
@action(
|
||||
"remove trial",
|
||||
"Stop trial period",
|
||||
"Remove trial for this user?",
|
||||
)
|
||||
def stop_trial(self, ids):
|
||||
for user in User.filter(User.id.in_(ids)):
|
||||
user.trial_end = None
|
||||
|
||||
flash(f"Stopped trial for {user}", "success")
|
||||
AdminAuditLog.stop_trial(current_user.id, user.id)
|
||||
|
||||
Session.commit()
|
||||
|
||||
@action(
|
||||
"disable_otp_fido",
|
||||
"Disable OTP & FIDO",
|
||||
|
@ -17,9 +17,14 @@ from app.models import PlanEnum, AppleSubscription
|
||||
_MONTHLY_PRODUCT_ID = "io.simplelogin.ios_app.subscription.premium.monthly"
|
||||
_YEARLY_PRODUCT_ID = "io.simplelogin.ios_app.subscription.premium.yearly"
|
||||
|
||||
# SL Mac app used to be in SL account
|
||||
_MACAPP_MONTHLY_PRODUCT_ID = "io.simplelogin.macapp.subscription.premium.monthly"
|
||||
_MACAPP_YEARLY_PRODUCT_ID = "io.simplelogin.macapp.subscription.premium.yearly"
|
||||
|
||||
# SL Mac app is moved to Proton account
|
||||
_MACAPP_MONTHLY_PRODUCT_ID_NEW = "me.proton.simplelogin.macos.premium.monthly"
|
||||
_MACAPP_YEARLY_PRODUCT_ID_NEW = "me.proton.simplelogin.macos.premium.yearly"
|
||||
|
||||
# Apple API URL
|
||||
_SANDBOX_URL = "https://sandbox.itunes.apple.com/verifyReceipt"
|
||||
_PROD_URL = "https://buy.itunes.apple.com/verifyReceipt"
|
||||
@ -263,7 +268,11 @@ def apple_update_notification():
|
||||
plan = (
|
||||
PlanEnum.monthly
|
||||
if transaction["product_id"]
|
||||
in (_MONTHLY_PRODUCT_ID, _MACAPP_MONTHLY_PRODUCT_ID)
|
||||
in (
|
||||
_MONTHLY_PRODUCT_ID,
|
||||
_MACAPP_MONTHLY_PRODUCT_ID,
|
||||
_MACAPP_MONTHLY_PRODUCT_ID_NEW,
|
||||
)
|
||||
else PlanEnum.yearly
|
||||
)
|
||||
|
||||
@ -517,7 +526,11 @@ def verify_receipt(receipt_data, user, password) -> Optional[AppleSubscription]:
|
||||
plan = (
|
||||
PlanEnum.monthly
|
||||
if latest_transaction["product_id"]
|
||||
in (_MONTHLY_PRODUCT_ID, _MACAPP_MONTHLY_PRODUCT_ID)
|
||||
in (
|
||||
_MONTHLY_PRODUCT_ID,
|
||||
_MACAPP_MONTHLY_PRODUCT_ID,
|
||||
_MACAPP_MONTHLY_PRODUCT_ID_NEW,
|
||||
)
|
||||
else PlanEnum.yearly
|
||||
)
|
||||
|
||||
|
@ -235,6 +235,7 @@ class AuditLogActionEnum(EnumE):
|
||||
download_provider_complaint = 8
|
||||
disable_user = 9
|
||||
enable_user = 10
|
||||
stop_trial = 11
|
||||
|
||||
|
||||
class Phase(EnumE):
|
||||
@ -3339,6 +3340,15 @@ class AdminAuditLog(Base):
|
||||
},
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def stop_trial(cls, admin_user_id: int, user_id: int):
|
||||
cls.create(
|
||||
admin_user_id=admin_user_id,
|
||||
action=AuditLogActionEnum.stop_trial.value,
|
||||
model="User",
|
||||
model_id=user_id,
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def disable_otp_fido(
|
||||
cls, admin_user_id: int, user_id: int, had_otp: bool, had_fido: bool
|
||||
|
@ -1,6 +1,7 @@
|
||||
from datetime import datetime
|
||||
from typing import Optional
|
||||
|
||||
import newrelic.agent
|
||||
import redis.exceptions
|
||||
import werkzeug.exceptions
|
||||
from limits.storage import RedisStorage
|
||||
@ -23,9 +24,15 @@ def check_bucket_limit(
|
||||
# Calculate current bucket time
|
||||
bucket_id = int(datetime.utcnow().timestamp()) % bucket_seconds
|
||||
bucket_lock_name = f"bl:{lock_name}:{bucket_id}"
|
||||
if not lock_redis:
|
||||
return
|
||||
try:
|
||||
value = lock_redis.incr(bucket_lock_name, bucket_seconds)
|
||||
if value > max_hits:
|
||||
newrelic.agent.record_custom_event(
|
||||
"BucketRateLimit",
|
||||
{"lock_name": lock_name, "bucket_seconds": bucket_seconds},
|
||||
)
|
||||
raise werkzeug.exceptions.TooManyRequests()
|
||||
except redis.exceptions.RedisError:
|
||||
except (redis.exceptions.RedisError, AttributeError):
|
||||
log.e("Cannot connect to redis")
|
||||
|
@ -89,86 +89,87 @@
|
||||
Github repo
|
||||
<i class="fa fa-external-link" aria-hidden="true"></i>
|
||||
</a>
|
||||
<div class="dropdown-item">
|
||||
<a href="https://forum.simplelogin.io"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer">
|
||||
Forum
|
||||
<i class="fa fa-external-link" aria-hidden="true"></i>
|
||||
</a>
|
||||
</div>
|
||||
<div class="dropdown-item">
|
||||
<a href="/dashboard/support">Support</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="dropdown-item">
|
||||
<a href="https://forum.simplelogin.io"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer">
|
||||
Forum
|
||||
<i class="fa fa-external-link" aria-hidden="true"></i>
|
||||
</a>
|
||||
</div>
|
||||
<div class="dropdown-item">
|
||||
<a href="/dashboard/support">Support</a>
|
||||
</div>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="nav-item">
|
||||
<a href="https://simplelogin.io/docs/"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer">
|
||||
Docs
|
||||
<i class="fa fa-external-link" aria-hidden="true"></i>
|
||||
</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if current_user.should_show_upgrade_button() %}
|
||||
|
||||
<div class="nav-item">
|
||||
<a href="{{ url_for('dashboard.pricing') }}"
|
||||
class="btn btn-sm btn-outline-primary">Upgrade</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="dropdown">
|
||||
<a href="#" class="nav-link pr-0 leading-none" data-toggle="dropdown">
|
||||
{% if current_user.profile_picture_id %}
|
||||
|
||||
<span class="avatar"
|
||||
style="background-image: url('{{ current_user.profile_picture_url() }}')"></span>
|
||||
{% else %}
|
||||
<span class="avatar avatar-blue">{{ current_user.get_name_initial() or "👻" }}</span>
|
||||
{% endif %}
|
||||
<span class="ml-2 d-none d-lg-block">
|
||||
<span class="text-default text-break">{{ current_user.name or current_user.email }}</span>
|
||||
{% if current_user.in_trial() %}
|
||||
|
||||
<small class="text-success d-block mt-1"
|
||||
data-toggle="tooltip"
|
||||
title="When you signed up, you have a free 7-day Premium trial. After that your account will automatically be downgraded to the Free plan. During the trial, the only limit is you can't create more than {{ MAX_NB_EMAIL_FREE_PLAN }} aliases.">
|
||||
Premium expires {{ current_user.trial_end|dt }}
|
||||
<i class="fe fe-info"></i>
|
||||
</small>
|
||||
{% elif current_user.is_premium() %}
|
||||
<small class="text-success d-block mt-1">Premium</small>
|
||||
{% endif %}
|
||||
</span>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="nav-item">
|
||||
<a href="https://simplelogin.io/docs/"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer">
|
||||
Docs
|
||||
<i class="fa fa-external-link" aria-hidden="true"></i>
|
||||
</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if current_user.should_show_upgrade_button() %}
|
||||
|
||||
<div class="nav-item">
|
||||
<a href="{{ url_for('dashboard.pricing') }}"
|
||||
class="btn btn-sm btn-outline-primary">Upgrade</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="dropdown">
|
||||
<a href="#" class="nav-link pr-0 leading-none" data-toggle="dropdown">
|
||||
{% if current_user.profile_picture_id %}
|
||||
|
||||
<span class="avatar"
|
||||
style="background-image: url('{{ current_user.profile_picture_url() }}')"></span>
|
||||
{% else %}
|
||||
<span class="avatar avatar-blue">{{ current_user.get_name_initial() or "👻" }}</span>
|
||||
{% endif %}
|
||||
<span class="ml-2 d-none d-lg-block">
|
||||
<span class="text-default text-break">{{ current_user.name or current_user.email }}</span>
|
||||
{% if current_user.in_trial() %}
|
||||
|
||||
<small class="text-success d-block mt-1"
|
||||
data-toggle="tooltip"
|
||||
title="When you signed up, you have a free 7-day Premium trial. After that your account will automatically be downgraded to the Free plan. During the trial, the only limit is you can't create more than {{ MAX_NB_EMAIL_FREE_PLAN }} aliases.">
|
||||
Premium expires {{ current_user.trial_end|dt }}
|
||||
<i class="fe fe-info"></i>
|
||||
</small>
|
||||
{% elif current_user.is_premium() %}
|
||||
<small class="text-success d-block mt-1">Premium</small>
|
||||
{% endif %}
|
||||
</span>
|
||||
</a>
|
||||
<div class="dropdown-menu dropdown-menu-right dropdown-menu-arrow">
|
||||
<a class="dropdown-item mb-3" href="{{ url_for('dashboard.api_key') }}">
|
||||
<i class="dropdown-icon fa fa-key"></i> API Keys
|
||||
</a>
|
||||
<a class="dropdown-item" href="{{ url_for('auth.logout') }}">
|
||||
<i class="dropdown-icon fe fe-log-out"></i> Sign out
|
||||
</a>
|
||||
<div class="dropdown-menu dropdown-menu-right dropdown-menu-arrow">
|
||||
<a class="dropdown-item mb-3" href="{{ url_for('dashboard.api_key') }}">
|
||||
<i class="dropdown-icon fa fa-key"></i> API Keys
|
||||
</a>
|
||||
<a class="dropdown-item" href="{{ url_for('auth.logout') }}">
|
||||
<i class="dropdown-icon fe fe-log-out"></i> Sign out
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<a href="#"
|
||||
class="header-toggler d-lg-none ml-3 ml-lg-0"
|
||||
data-toggle="collapse"
|
||||
data-target="#headerMenuCollapse">
|
||||
<span class="header-toggler-icon"></span>
|
||||
</a>
|
||||
</div>
|
||||
<a href="#"
|
||||
class="header-toggler d-lg-none ml-3 ml-lg-0"
|
||||
data-toggle="collapse"
|
||||
data-target="#headerMenuCollapse">
|
||||
<span class="header-toggler-icon"></span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="header collapse d-lg-flex p-0" id="headerMenuCollapse">
|
||||
<div class="container">
|
||||
<div class="row align-items-center">
|
||||
<div class="col-lg order-lg-first">
|
||||
{% include "menu.html" %}
|
||||
</div>
|
||||
<div class="header collapse d-lg-flex p-0" id="headerMenuCollapse">
|
||||
<div class="container">
|
||||
<div class="row align-items-center">
|
||||
<div class="col-lg order-lg-first">
|
||||
{% include "menu.html" %}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
Loading…
x
Reference in New Issue
Block a user