Coverage for functions \ flipdare \ util \ public \ public_types.py: 97%
67 statements
« prev ^ index » next coverage.py v7.13.0, created at 2026-05-08 12:22 +1000
« prev ^ index » next coverage.py v7.13.0, created at 2026-05-08 12:22 +1000
1#!/usr/bin/env python
2# Copyright (c) 2026 Flipdare Pty Ltd. All rights reserved.
3#
4# This file is part of Flipdare's proprietary software and contains
5# confidential and copyrighted material. Unauthorised copying,
6# modification, distribution, or use of this file is strictly
7# prohibited without prior written permission from Flipdare Pty Ltd.
8#
9# This software includes third-party components licensed under MIT,
10# BSD, and Apache 2.0 licences. See THIRD_PARTY_NOTICES for details.
11#
12from __future__ import annotations
14from dataclasses import dataclass, field
15from enum import StrEnum
16from pathlib import Path
17from flipdare.constants import (
18 FIREBASE_TMP_EMAIL_PATH,
19 FIREBASE_EMAIL_RETENTION_DAYS,
20 FIREBASE_TMP_RECEIPT_PATH,
21 FIREBASE_RECEIPT_RETENTION_DAYS,
22)
24__all__ = [
25 "PublicContentType",
26 "PublicStoragePath",
27 "PublicUrl",
28 "PublicContent",
29]
32class PublicContentType(StrEnum):
33 VIDEO = "video/mp4"
34 # supported images
35 JPEG = "image/jpeg"
36 PNG = "image/png"
37 WEBP = "image/webp"
38 GIF = "image/gif"
39 # receipts etc
40 PDF = "application/pdf"
41 # fallback
42 OTHER = "application/octet-stream"
44 @staticmethod
45 def guess(filename: str) -> PublicContentType:
46 path = Path(filename)
47 ext = path.suffix.lower().lstrip(".")
48 match ext:
49 case "mp4":
50 return PublicContentType.VIDEO
51 case "jpg" | "jpeg":
52 return PublicContentType.JPEG
53 case "png":
54 return PublicContentType.PNG
55 case "webp":
56 return PublicContentType.WEBP
57 case "gif":
58 return PublicContentType.GIF
59 case "pdf":
60 return PublicContentType.PDF
61 case _:
62 return PublicContentType.OTHER
65class PublicStoragePath(StrEnum):
66 RECEIPTS = FIREBASE_TMP_RECEIPT_PATH
67 EMAILS = FIREBASE_TMP_EMAIL_PATH
69 @property
70 def retention_days(self) -> int:
71 match self:
72 case PublicStoragePath.RECEIPTS:
73 return FIREBASE_RECEIPT_RETENTION_DAYS
74 case PublicStoragePath.EMAILS:
75 return FIREBASE_EMAIL_RETENTION_DAYS
78@dataclass(frozen=True, kw_only=True)
79class PublicUrl:
80 file_name: str
81 content_type: PublicContentType
82 storage_path: PublicStoragePath
84 @property
85 def remote_path(self) -> str:
86 return f"{self.storage_path.value}/{self.file_name}"
89@dataclass(frozen=True, kw_only=True)
90class PublicContent:
91 url: PublicUrl
92 bytes_content: bytes = field(repr=False)
94 @property
95 def file_name(self) -> str:
96 return self.url.file_name
98 @property
99 def remote_path(self) -> str:
100 return self.url.remote_path
102 @property
103 def content_type(self) -> PublicContentType:
104 return self.url.content_type
106 @property
107 def storage_path(self) -> PublicStoragePath:
108 return self.url.storage_path