File size: 3,322 Bytes
8450c71
b856986
 
 
8450c71
b856986
 
 
8450c71
 
b856986
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8450c71
b856986
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
import asyncio
import uuid
from tortoise import fields, Tortoise
from tortoise.models import Model
from passlib.context import CryptContext
import datetime
import random
import string
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")

def generate_short_uuid() -> str:
    """Generate a random 5-character alphanumeric string."""
    return ''.join(random.choices(string.ascii_letters + string.digits, k=5))


class User(Model):
    id = fields.CharField(primary_key=True, max_length=5, default=generate_short_uuid)
    name = fields.CharField(max_length=100, db_index=True)
    email = fields.CharField(max_length=100, db_index=True, unique=True)
    password = fields.CharField(max_length=100)
    phoneNumber = fields.CharField(max_length=100, null=True)
    account_type = fields.IntField(default=1)
    balance = fields.DecimalField(max_digits=10, decimal_places=2, default=0.00)
    ip_address = fields.CharField(max_length=45, null=True)
    mac_address = fields.CharField(max_length=17, null=True)
    createdAt = fields.DatetimeField(default=datetime.datetime.now)
    updatedAt = fields.DatetimeField(default=datetime.datetime.now)
    lastLogin = fields.DatetimeField(default=datetime.datetime.now)
    failed_attempts = fields.IntField(default=0)
    account_locked = fields.BooleanField(default=False)
    reset_token = fields.CharField(max_length=100, null=True, unique=True)
    reset_token_expiration = fields.DatetimeField(null=True)

    class Meta:
        table = "users"

    def verify_password(self, plain_password: str) -> bool:
        if self.account_locked:
            print("Account is locked due to too many failed attempts.")
            return False

        if pwd_context.verify(plain_password, self.password):
            self.failed_attempts = 0  # Reset failed attempts on success
            self.account_locked = False
            self.save()  # Save changes to reset the failed attempts count
            return True
        else:
            self.failed_attempts += 1
            if self.failed_attempts >= 5:
                self.account_locked = True
                print("Account locked due to too many failed attempts.")
            self.save()  # Save changes to update the failed attempts count
            return False

    async def initiate_password_reset(self):
        # Generate a unique reset token
        self.reset_token = str(uuid.uuid4())
        self.reset_token_expiration = datetime.datetime.now() + datetime.timedelta(hours=1)  # Token expires in 1 hour
        await self.save()

        # In a real application, send this token to the user's email or phone
        print(f"Password reset token for {self.email}: {self.reset_token}")

    async def reset_password(self, reset_token, new_password):
        # Check if the reset token is valid and not expired
        if self.reset_token != reset_token or datetime.datetime.now() > self.reset_token_expiration:
            print("Invalid or expired reset token.")
            return False

        # Set the new password
        self.password = pwd_context.hash(new_password)
        self.reset_token = None  # Clear the token after successful reset
        self.reset_token_expiration = None
        await self.save()
        print("Password has been reset successfully.")
        return True