Skip to content

Commit eed48f3

Browse files
authored
Merge pull request #352 from spoo-me/feat/link-tags
feat(links): tags as a per-account registry with ids, colours and icons
2 parents c71e5d6 + f9c701b commit eed48f3

52 files changed

Lines changed: 3906 additions & 37 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

dependencies/__init__.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@
7272
ProfilePictureSvc,
7373
ReportIntakeSvc,
7474
StatsSvc,
75+
TagSvc,
7576
UrlExpandSvc,
7677
UrlPolicy,
7778
UrlSvc,
@@ -97,6 +98,7 @@
9798
get_profile_picture_service,
9899
get_report_intake_service,
99100
get_stats_service,
101+
get_tag_service,
100102
get_url_policy,
101103
get_url_service,
102104
get_user_repo,
@@ -147,6 +149,7 @@
147149
"ReportIntakeSvc",
148150
"Settings",
149151
"StatsSvc",
152+
"TagSvc",
150153
"UrlExpandSvc",
151154
"UrlPolicy",
152155
"UrlSvc",
@@ -186,6 +189,7 @@
186189
"get_report_intake_service",
187190
"get_settings",
188191
"get_stats_service",
192+
"get_tag_service",
189193
"get_url_policy",
190194
"get_url_service",
191195
"get_user_repo",

dependencies/services.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
from services.report_intake_service import ReportIntakeService
4040
from services.safety.policy import UrlPolicyService
4141
from services.stats_service import StatsService
42+
from services.tag_service import TagService
4243
from services.url_expand_service import UrlExpandService
4344
from services.url_service import UrlService
4445
from services.webhooks.service import WebhookService
@@ -52,6 +53,10 @@ def get_url_policy(request: Request) -> UrlPolicyService:
5253
return request.app.state.url_policy
5354

5455

56+
def get_tag_service(request: Request) -> TagService:
57+
return request.app.state.tag_service
58+
59+
5560
def get_bulk_url_service(request: Request) -> BulkUrlService:
5661
return request.app.state.bulk_url_service
5762

@@ -169,6 +174,7 @@ def get_webhook_service(request: Request) -> WebhookService:
169174
UrlSvc = Annotated[UrlService, Depends(get_url_service)]
170175
UrlPolicy = Annotated[UrlPolicyService, Depends(get_url_policy)]
171176
BulkUrlSvc = Annotated[BulkUrlService, Depends(get_bulk_url_service)]
177+
TagSvc = Annotated[TagService, Depends(get_tag_service)]
172178
StatsSvc = Annotated[StatsService, Depends(get_stats_service)]
173179
PublicStatsSvc = Annotated[PublicStatsService, Depends(get_public_stats_service)]
174180
ExportSvc = Annotated[ExportService, Depends(get_export_service)]

dependencies/wiring.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
ReportSubmissionRepository,
4848
)
4949
from repositories.scheduled_task_repository import ScheduledTaskRepository
50+
from repositories.tag_repository import TagRepository
5051
from repositories.token_repository import TokenRepository
5152
from repositories.url_repository import UrlRepository
5253
from repositories.user_repository import UserRepository
@@ -123,6 +124,7 @@
123124
from services.scheduler import TaskScheduler
124125
from services.scheduler.tasks import build_task_registry
125126
from services.stats_service import StatsService
127+
from services.tag_service import TagService
126128
from services.tenant_resolver import CachedMongoTenantResolver
127129
from services.token_factory import TokenFactory
128130
from services.url_expand_service import UrlExpandService
@@ -358,6 +360,7 @@ def build_account_erasure_service(
358360
user_repo=user_repo,
359361
url_service=url_service,
360362
domain_service=domain_service,
363+
tag_service=TagService(TagRepository(db["tags"]), UrlRepository(db["urlsV2"])),
361364
click_repo=ClickRepository(db["clicks"]),
362365
api_key_repo=ApiKeyRepository(db["api-keys"]),
363366
token_repo=TokenRepository(db["verification-tokens"]),
@@ -668,6 +671,8 @@ def wire_services(app: FastAPI, settings: AppSettings, redis_client) -> None:
668671
)
669672
app.state.url_policy = url_policy
670673
# ── Services ─────────────────────────────────────────────────────────
674+
tag_repo = TagRepository(db["tags"])
675+
app.state.tag_service = TagService(tag_repo, url_repo)
671676
app.state.url_service = UrlService(
672677
url_repo,
673678
legacy_repo,
@@ -692,6 +697,7 @@ def wire_services(app: FastAPI, settings: AppSettings, redis_client) -> None:
692697
meta_key_secret=settings.secret_key,
693698
events=app.state.domain_event_sink,
694699
user_repo=user_repo,
700+
tag_service=app.state.tag_service,
695701
)
696702
app.state.bulk_url_service = BulkUrlService(
697703
url_repo,
@@ -701,11 +707,13 @@ def wire_services(app: FastAPI, settings: AppSettings, redis_client) -> None:
701707
system_default_domain=settings.system_default_domain,
702708
og_ttl_seconds=edge.og_ttl_seconds,
703709
events=app.state.domain_event_sink,
710+
tag_service=app.state.tag_service,
704711
)
705712
app.state.stats_service = StatsService(
706713
click_repo,
707714
url_repo,
708715
max_date_range_days=settings.max_date_range_days,
716+
tag_service=app.state.tag_service,
709717
)
710718
# One resolver serves BOTH public read-only surfaces (preview + stats)
711719
# so they can never disagree about which link a code names or what
@@ -988,6 +996,7 @@ def wire_services(app: FastAPI, settings: AppSettings, redis_client) -> None:
988996
user_repo=user_repo,
989997
url_service=app.state.url_service,
990998
domain_service=app.state.custom_domain_service,
999+
tag_service=app.state.tag_service,
9911000
click_repo=click_repo,
9921001
api_key_repo=api_key_repo,
9931002
token_repo=token_repo,

middleware/rate_limiter.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,10 @@ class Limits:
9999
URL_BULK_STATUS = "60 per minute; 200 per day"
100100
URL_BULK_EXPIRY = "60 per minute; 200 per day"
101101
URL_BULK_DOMAIN = "60 per minute; 200 per day"
102+
URL_BULK_TAGS = "60 per minute; 200 per day"
103+
# Tags: writes are cheap single-doc ops; delete fans out over every link.
104+
TAG_WRITE = "30 per minute"
105+
TAG_DELETE = "10 per minute"
102106
URL_BULK_MUTATE_DELETE = "30 per minute; 100 per day"
103107

104108
# Claim intake (POST /api/v1/urls/claim). Per submission, 16-item cap;

0 commit comments

Comments
 (0)