1from __future__ import annotations
 2
 3import binascii
 4import os
 5import uuid
 6from datetime import datetime
 7from uuid import UUID
 8
 9from plain import postgres
10from plain.postgres import types
11
12__all__ = ["APIKey"]
13
14
15def generate_token() -> str:
16    return binascii.hexlify(os.urandom(20)).decode()
17
18
19@postgres.register_model
20class APIKey(postgres.Model):
21    uuid: UUID = types.UUIDField(default=uuid.uuid4)
22    created_at: datetime = types.DateTimeField(auto_now_add=True)
23    updated_at: datetime = types.DateTimeField(auto_now=True)
24    expires_at: datetime | None = types.DateTimeField(required=False, allow_null=True)
25    last_used_at: datetime | None = types.DateTimeField(required=False, allow_null=True)
26
27    name: str = types.TextField(max_length=255, required=False)
28
29    token: str = types.TextField(max_length=40, default=generate_token)
30
31    api_version: str = types.TextField(max_length=255, required=False)
32
33    query: postgres.QuerySet[APIKey] = postgres.QuerySet()
34
35    model_options = postgres.Options(
36        constraints=[
37            postgres.UniqueConstraint(
38                fields=["uuid"], name="plainapi_apikey_unique_uuid"
39            ),
40            postgres.UniqueConstraint(
41                fields=["token"], name="plainapi_apikey_unique_token"
42            ),
43        ],
44    )
45
46    def __str__(self) -> str:
47        return self.name or str(self.uuid)