mirror of
https://github.com/simple-login/app.git
synced 2025-10-06 13:26:51 +08:00
create Metric2 model
This commit is contained in:
parent
e9e97cea61
commit
ec1633d0d7
3 changed files with 89 additions and 128 deletions
|
@ -2132,6 +2132,41 @@ class Metric(db.Model, ModelMixin):
|
||||||
NB_APP = "nb_app"
|
NB_APP = "nb_app"
|
||||||
|
|
||||||
|
|
||||||
|
class Metric2(db.Model, ModelMixin):
|
||||||
|
"""
|
||||||
|
For storing different metrics like number of users, etc
|
||||||
|
Store each metric as a column as opposed to having different rows as in Metric
|
||||||
|
"""
|
||||||
|
|
||||||
|
date = db.Column(ArrowType, default=arrow.utcnow, nullable=False)
|
||||||
|
name = db.Column(db.String(256), nullable=False)
|
||||||
|
|
||||||
|
nb_user = db.Column(db.Float, nullable=True)
|
||||||
|
nb_activated_user = db.Column(db.Float, nullable=True)
|
||||||
|
|
||||||
|
nb_premium = db.Column(db.Float, nullable=True)
|
||||||
|
nb_apple_premium = db.Column(db.Float, nullable=True)
|
||||||
|
nb_cancelled_premium = db.Column(db.Float, nullable=True)
|
||||||
|
nb_manual_premium = db.Column(db.Float, nullable=True)
|
||||||
|
nb_coinbase_premium = db.Column(db.Float, nullable=True)
|
||||||
|
|
||||||
|
# nb users who have been referred
|
||||||
|
nb_referred_user = db.Column(db.Float, nullable=True)
|
||||||
|
nb_referred_user_paid = db.Column(db.Float, nullable=True)
|
||||||
|
|
||||||
|
nb_alias = db.Column(db.Float, nullable=True)
|
||||||
|
|
||||||
|
nb_forward = db.Column(db.Float, nullable=True)
|
||||||
|
nb_block = db.Column(db.Float, nullable=True)
|
||||||
|
nb_reply = db.Column(db.Float, nullable=True)
|
||||||
|
nb_bounced = db.Column(db.Float, nullable=True)
|
||||||
|
nb_spam = db.Column(db.Float, nullable=True)
|
||||||
|
|
||||||
|
nb_verified_custom_domain = db.Column(db.Float, nullable=True)
|
||||||
|
|
||||||
|
nb_app = db.Column(db.Float, nullable=True)
|
||||||
|
|
||||||
|
|
||||||
class Bounce(db.Model, ModelMixin):
|
class Bounce(db.Model, ModelMixin):
|
||||||
"""Record all bounces. Deleted after 7 days"""
|
"""Record all bounces. Deleted after 7 days"""
|
||||||
|
|
||||||
|
|
129
cron.py
129
cron.py
|
@ -49,6 +49,7 @@ from app.models import (
|
||||||
Metric,
|
Metric,
|
||||||
TransactionalEmail,
|
TransactionalEmail,
|
||||||
Bounce,
|
Bounce,
|
||||||
|
Metric2,
|
||||||
)
|
)
|
||||||
from server import create_app
|
from server import create_app
|
||||||
|
|
||||||
|
@ -198,134 +199,6 @@ def poll_apple_subscription():
|
||||||
LOG.d("Finish poll_apple_subscription")
|
LOG.d("Finish poll_apple_subscription")
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class Stats:
|
|
||||||
nb_user: int
|
|
||||||
nb_alias: int
|
|
||||||
|
|
||||||
nb_forward: int
|
|
||||||
nb_block: int
|
|
||||||
nb_reply: int
|
|
||||||
nb_bounced: int
|
|
||||||
nb_spam: int
|
|
||||||
|
|
||||||
nb_custom_domain: int
|
|
||||||
nb_app: int
|
|
||||||
|
|
||||||
nb_premium: int
|
|
||||||
nb_apple_premium: int
|
|
||||||
nb_cancelled_premium: int
|
|
||||||
nb_manual_premium: int
|
|
||||||
nb_coinbase_premium: int
|
|
||||||
|
|
||||||
# nb users who have been referred
|
|
||||||
nb_referred_user: int
|
|
||||||
nb_referred_user_upgrade: int
|
|
||||||
|
|
||||||
|
|
||||||
def stats_before(moment: Arrow) -> Stats:
|
|
||||||
"""return the stats before a specific moment, ignoring all stats come from users in IGNORED_EMAILS"""
|
|
||||||
# nb user
|
|
||||||
q = User.query
|
|
||||||
for ie in IGNORED_EMAILS:
|
|
||||||
q = q.filter(~User.email.contains(ie), User.created_at < moment)
|
|
||||||
|
|
||||||
nb_user = q.count()
|
|
||||||
LOG.d("total number user %s", nb_user)
|
|
||||||
|
|
||||||
nb_referred_user = q.filter(User.referral_id.isnot(None)).count()
|
|
||||||
nb_referred_user_upgrade = 0
|
|
||||||
for user in q.filter(User.referral_id.isnot(None)):
|
|
||||||
if user.is_paid():
|
|
||||||
nb_referred_user_upgrade += 1
|
|
||||||
|
|
||||||
LOG.d(
|
|
||||||
"%s nb_referred_user:%s nb_referred_user_upgrade:%s",
|
|
||||||
moment,
|
|
||||||
nb_referred_user,
|
|
||||||
nb_referred_user_upgrade,
|
|
||||||
)
|
|
||||||
|
|
||||||
# nb alias
|
|
||||||
q = db.session.query(Alias, User).filter(
|
|
||||||
Alias.user_id == User.id, Alias.created_at < moment
|
|
||||||
)
|
|
||||||
for ie in IGNORED_EMAILS:
|
|
||||||
q = q.filter(~User.email.contains(ie))
|
|
||||||
|
|
||||||
nb_alias = q.count()
|
|
||||||
LOG.d("total number alias %s", nb_alias)
|
|
||||||
|
|
||||||
# email log stats
|
|
||||||
q = (
|
|
||||||
db.session.query(EmailLog)
|
|
||||||
.join(User, EmailLog.user_id == User.id)
|
|
||||||
.filter(
|
|
||||||
EmailLog.created_at < moment,
|
|
||||||
)
|
|
||||||
)
|
|
||||||
for ie in IGNORED_EMAILS:
|
|
||||||
q = q.filter(~User.email.contains(ie))
|
|
||||||
|
|
||||||
nb_spam = nb_bounced = nb_forward = nb_block = nb_reply = 0
|
|
||||||
for email_log in q.yield_per(500):
|
|
||||||
if email_log.bounced:
|
|
||||||
nb_bounced += 1
|
|
||||||
elif email_log.is_spam:
|
|
||||||
nb_spam += 1
|
|
||||||
elif email_log.is_reply:
|
|
||||||
nb_reply += 1
|
|
||||||
elif email_log.blocked:
|
|
||||||
nb_block += 1
|
|
||||||
else:
|
|
||||||
nb_forward += 1
|
|
||||||
|
|
||||||
LOG.d(
|
|
||||||
"nb_forward %s, nb_block %s, nb_reply %s, nb_bounced %s, nb_spam %s",
|
|
||||||
nb_forward,
|
|
||||||
nb_block,
|
|
||||||
nb_reply,
|
|
||||||
nb_bounced,
|
|
||||||
nb_spam,
|
|
||||||
)
|
|
||||||
|
|
||||||
nb_premium = Subscription.query.filter(
|
|
||||||
Subscription.created_at < moment, Subscription.cancelled.is_(False)
|
|
||||||
).count()
|
|
||||||
nb_apple_premium = AppleSubscription.query.filter(
|
|
||||||
AppleSubscription.created_at < moment
|
|
||||||
).count()
|
|
||||||
nb_cancelled_premium = Subscription.query.filter(
|
|
||||||
Subscription.created_at < moment, Subscription.cancelled.is_(True)
|
|
||||||
).count()
|
|
||||||
|
|
||||||
now = arrow.now()
|
|
||||||
nb_manual_premium = ManualSubscription.query.filter(
|
|
||||||
ManualSubscription.created_at < moment,
|
|
||||||
ManualSubscription.end_at > now,
|
|
||||||
ManualSubscription.is_giveaway.is_(False),
|
|
||||||
).count()
|
|
||||||
|
|
||||||
nb_coinbase_premium = CoinbaseSubscription.query.filter(
|
|
||||||
CoinbaseSubscription.created_at < moment, CoinbaseSubscription.end_at > now
|
|
||||||
).count()
|
|
||||||
|
|
||||||
nb_custom_domain = CustomDomain.query.filter(
|
|
||||||
CustomDomain.created_at < moment
|
|
||||||
).count()
|
|
||||||
|
|
||||||
nb_app = Client.query.filter(Client.created_at < moment).count()
|
|
||||||
|
|
||||||
data = locals()
|
|
||||||
# to keep only Stats field
|
|
||||||
data = {
|
|
||||||
k: v
|
|
||||||
for (k, v) in data.items()
|
|
||||||
if k in vars(Stats)["__dataclass_fields__"].keys()
|
|
||||||
}
|
|
||||||
return Stats(**data)
|
|
||||||
|
|
||||||
|
|
||||||
def compute_metrics():
|
def compute_metrics():
|
||||||
now = arrow.now()
|
now = arrow.now()
|
||||||
|
|
||||||
|
|
53
migrations/versions/2021_032310_9d6adad83936_.py
Normal file
53
migrations/versions/2021_032310_9d6adad83936_.py
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
"""empty message
|
||||||
|
|
||||||
|
Revision ID: 9d6adad83936
|
||||||
|
Revises: 94f14eb0fe5b
|
||||||
|
Create Date: 2021-03-23 10:23:17.879887
|
||||||
|
|
||||||
|
"""
|
||||||
|
import sqlalchemy_utils
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = '9d6adad83936'
|
||||||
|
down_revision = '94f14eb0fe5b'
|
||||||
|
branch_labels = None
|
||||||
|
depends_on = None
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade():
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
op.create_table('metric2',
|
||||||
|
sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
|
||||||
|
sa.Column('created_at', sqlalchemy_utils.types.arrow.ArrowType(), nullable=False),
|
||||||
|
sa.Column('updated_at', sqlalchemy_utils.types.arrow.ArrowType(), nullable=True),
|
||||||
|
sa.Column('date', sqlalchemy_utils.types.arrow.ArrowType(), nullable=False),
|
||||||
|
sa.Column('name', sa.String(length=256), nullable=False),
|
||||||
|
sa.Column('nb_user', sa.Float(), nullable=True),
|
||||||
|
sa.Column('nb_activated_user', sa.Float(), nullable=True),
|
||||||
|
sa.Column('nb_premium', sa.Float(), nullable=True),
|
||||||
|
sa.Column('nb_apple_premium', sa.Float(), nullable=True),
|
||||||
|
sa.Column('nb_cancelled_premium', sa.Float(), nullable=True),
|
||||||
|
sa.Column('nb_manual_premium', sa.Float(), nullable=True),
|
||||||
|
sa.Column('nb_coinbase_premium', sa.Float(), nullable=True),
|
||||||
|
sa.Column('nb_referred_user', sa.Float(), nullable=True),
|
||||||
|
sa.Column('nb_referred_user_paid', sa.Float(), nullable=True),
|
||||||
|
sa.Column('nb_alias', sa.Float(), nullable=True),
|
||||||
|
sa.Column('nb_forward', sa.Float(), nullable=True),
|
||||||
|
sa.Column('nb_block', sa.Float(), nullable=True),
|
||||||
|
sa.Column('nb_reply', sa.Float(), nullable=True),
|
||||||
|
sa.Column('nb_bounced', sa.Float(), nullable=True),
|
||||||
|
sa.Column('nb_spam', sa.Float(), nullable=True),
|
||||||
|
sa.Column('nb_verified_custom_domain', sa.Float(), nullable=True),
|
||||||
|
sa.Column('nb_app', sa.Float(), nullable=True),
|
||||||
|
sa.PrimaryKeyConstraint('id')
|
||||||
|
)
|
||||||
|
# ### end Alembic commands ###
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade():
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
op.drop_table('metric2')
|
||||||
|
# ### end Alembic commands ###
|
Loading…
Add table
Reference in a new issue