2026-07-04 21:22:11 +02:00
|
|
|
# retoor <retoor@molodetz.nl>
|
|
|
|
|
|
|
|
|
|
from .core import dataset, logging, Path, or_, defaultdict, datetime, timedelta, timezone, TTLCache, DATABASE_URL, DEFAULT_CORRECTION_PROMPT, DEFAULT_MODIFIER_PROMPT, INTERNAL_GATEWAY_URL, ensure_data_dirs, logger, db
|
|
|
|
|
from .core import refresh_snapshot, _local_cache_versions, _cache_version_cache, _cache_state_ready, _ensure_cache_state, get_cache_version, bump_cache_version, sync_local_cache, _index, _drop_index, _uid_index, get_table, _in_clause, _now_iso
|
2026-07-26 14:57:18 +02:00
|
|
|
from .atomic import conditional_update_row
|
2026-07-04 21:22:11 +02:00
|
|
|
from .settings import _settings_cache, get_setting, get_int_setting, set_setting, clear_settings_cache, internal_gateway_key
|
2026-07-05 00:08:20 +02:00
|
|
|
from .users import get_users_by_uids, _admins_cache, invalidate_admins_cache, get_admin_uids, set_user_timezone, set_last_seen, get_online_users, get_primary_admin_uid, search_users_by_username
|
2026-07-04 21:22:11 +02:00
|
|
|
from .relations import _relations_cache, get_user_relations, get_blocked_uids, get_muted_uids, get_silenced_uids, invalidate_user_relations
|
2026-07-19 18:57:43 +02:00
|
|
|
from .pagination import PAGE_SIZE, paginate, interleave_by_author, paginate_diverse, get_user_post_count, clear_user_post_count, build_pagination
|
2026-07-04 21:22:11 +02:00
|
|
|
from .soft_delete import SOFT_DELETE_TABLES, ensure_soft_delete_columns, soft_delete, soft_delete_in, restore, purge, list_deleted, count_deleted, restore_event, purge_event
|
Fix circular import, primary-admin NULL trap, and add gateway quota reset
Restores a working import graph and closes two data-correctness bugs, plus
adds a reset for the AI gateway's rolling 24h spend.
Circular import: database/__init__ -> engagement -> content -> utils ->
database made the package unimportable. get_project_devlog moves out of
database/engagement.py into content.py, where enrich_items already lives.
Primary administrator: _can_hold_primary_admin read is_active with
bool(row.get("is_active")), so an admin row whose is_active column is SQL
NULL (any row predating the column) was treated as deactivated and skipped.
Every other site defaults an unknown is_active to active; this one now does
too.
Profile JSON: xp_next_level and xp_progress_pct were computed but only put on
the top-level context, never on profile_user, so they serialised as null even
though UserOut declares them and the API docs document them as embedded there.
Gateway quota reset: a cap previously lifted only with the passage of time.
quota.reset upserts a watermark row into gateway_quota_resets, scoped by the
same three nullable dimensions as a quota rule, and spent_24h sums from
max(24h cutoff, watermark). No ledger row is deleted, so the cost analytics on
/admin/ai-usage stay intact. Reaches every surface: POST
/admin/gateway/quota-resets, a per-rule Reset spend button, the Devii tool
gateway_quota_reset (confirm-gated), devplace gateway quota reset, and the API
docs. Admin's Reset all quotas now stamps a global gateway watermark too,
which is what a caller stuck on "AI gateway daily quota exceeded" needed.
Startup: _backfill_gamification swept every xp=0 user on every boot in every
worker and could never converge, since a user with no content earns no XP.
It now intersects pending users with _milestone_candidates(). db.tables is a
live reflection, so it is hoisted out of the loops that probed it per row.
Docker: the dependency layer now depends on pyproject.toml only, so a source
edit no longer reinstalls every dependency and re-downloads Chromium.
Adds start_interval so the healthcheck probes during the start period, and a
docker-reload target, since docker-up does not restart an unchanged container.
Adds events.md, the audit event catalogue that README, CLAUDE.md, the quiz
docs and the tooling all referenced but which never existed: 288 keys across
28 categories, including the families built from a variable at the call site.
Test fixes: both devlog helpers dated post 0 as the newest while the tests
assumed post 2 was; a profile login posted username= to a form that takes
email=; a devlog assertion matched six buttons under strict mode; and the
primary-admin tests seeded founders newer than the back-dated fixture admin,
so they only passed without the api tier.
Full suite: 2989 passed, 1 skipped.
2026-07-27 11:17:48 +02:00
|
|
|
from .engagement import _comment_count_cache, get_comment_counts_by_post_uids, get_post_counts_by_user_uids, get_vote_counts, get_user_votes, get_reactions_by_targets, get_user_bookmarks, get_polls_by_post_uids, get_poll_for_post
|
2026-07-09 02:52:54 +02:00
|
|
|
from .usage import _add_usage, _get_usage, add_correction_usage, get_correction_usage, add_modifier_usage, get_modifier_usage, NEWS_USAGE_KEY, add_news_usage, get_news_usage, ISSUE_USAGE_KEY, add_issue_usage, get_issue_usage, SEO_USAGE_KEY, add_seo_usage, get_seo_usage, AWARD_USAGE_KEY, add_award_usage, get_award_usage
|
|
|
|
|
from .awards import (
|
|
|
|
|
AWARDS_PER_PAGE,
|
|
|
|
|
award_display_hours,
|
|
|
|
|
award_give_cooldown_hours,
|
|
|
|
|
award_receive_cooldown_hours,
|
|
|
|
|
award_is_prominent,
|
|
|
|
|
can_give_award,
|
|
|
|
|
can_receive_award,
|
|
|
|
|
count_published_awards,
|
|
|
|
|
enrich_award,
|
|
|
|
|
get_prominent_award,
|
|
|
|
|
get_user_awards,
|
|
|
|
|
has_giver_cooldown,
|
|
|
|
|
has_receiver_cooldown,
|
|
|
|
|
recompute_user_award_stats,
|
|
|
|
|
revoke_award,
|
|
|
|
|
)
|
2026-07-04 21:22:11 +02:00
|
|
|
from .seo_meta import SEO_META_TYPES, get_seo_metadata, get_seo_metadata_batch, has_fresh_seo_metadata, upsert_seo_metadata, mark_seo_metadata_stale
|
|
|
|
|
from .activity import record_activity, record_unique_activity, get_user_activity, _activity_cache, _ACTIVITY_TABLES, get_activity_calendar, _activity_level, get_first_activity_date, HEATMAP_WEEKS, get_activity_heatmap, get_activity_months, get_streaks
|
|
|
|
|
from .customization import CUSTOMIZATION_GLOBAL_SCOPE, CUSTOMIZATION_LANGS, _customizations_cache, _customization_key, CUSTOMIZATION_PREF_COLUMNS, get_customization_prefs, set_customization_pref, get_custom_overrides, get_custom_override, list_custom_overrides, set_custom_override, delete_custom_override
|
|
|
|
|
from .email import EMAIL_ACCOUNT_DEFAULTS, list_email_accounts, get_email_account, set_email_account, delete_email_account
|
|
|
|
|
from .notifications import NOTIFICATION_TYPES, NOTIFICATION_CHANNELS, _NOTIFICATION_CHANNEL_COLUMNS, _NOTIFICATION_CHANNEL_DEFAULTS, _NOTIFICATION_TYPE_KEYS, _notification_prefs_cache, _notification_default, get_notification_default, set_notification_default, _notification_overrides, notification_enabled, get_notification_prefs, set_notification_pref, reset_notification_prefs, mark_notifications_read_by_target
|
|
|
|
|
from .forks import record_fork, get_fork_parent, count_forks, soft_delete_fork_relations, delete_fork_relations
|
|
|
|
|
from .follows import get_follow_counts, get_follow_list, get_following_among
|
|
|
|
|
from .deepsearch import _ds_now, create_deepsearch_session, update_deepsearch_session, get_deepsearch_session, add_deepsearch_message, get_deepsearch_messages, get_cached_deepsearch_url, upsert_deepsearch_url_cache
|
2026-07-06 05:57:47 +02:00
|
|
|
from .ranking import VOTABLE_TARGETS, STAR_TARGETS, _authors_cache, _ranked_authors, _rank_map, get_top_authors, get_leaderboard, get_user_rank, get_user_stars, clear_user_stars, update_target_stars, soft_delete_engagement, delete_engagement, get_target_owner_uid
|
2026-07-04 21:22:11 +02:00
|
|
|
from .comments import _drop_blocked, _build_comment_items, load_comments, get_recent_comments_by_target_uids, get_recent_comments_by_post_uids, load_comments_by_target_uids
|
2026-07-19 18:57:43 +02:00
|
|
|
from .content import resolve_by_slug, resolve_object_url, get_uids_by_username_match, text_search_clause, get_daily_topic, get_featured_news, get_trending_topics
|
Add attachment management CRUD to the /uploads API
Complete the read and update faces of the signed-in user's attachment
management over the existing attachments table:
- GET /uploads: paginated list of the user's own attachments, newest
first, with an optional linked/orphaned filter
- GET /uploads/{uid}: fetch one attachment (owner or admin)
- PATCH /uploads/{uid}: rename the display filename, always preserving
the original extension (owner or admin, audited as attachment.rename)
Adds get_user_attachments/get_user_attachment data helpers, the
rename_attachment operation, AttachmentRenameForm, the UploadItemOut and
UploadsListOut schemas, the Devii tools list_attachments/get_attachment/
rename_attachment, expanded API reference documentation for the full
lifecycle including delete, and api-tier tests.
2026-07-24 20:30:49 +02:00
|
|
|
from .attachments_data import get_attachments, get_attachments_by_type, get_news_images_by_uids, delete_attachment_record, delete_attachments, _delete_attachment_file, get_user_media, get_user_attachments, get_user_attachment, get_deleted_media
|
2026-07-04 21:22:11 +02:00
|
|
|
from .stats import _stats_cache, get_site_stats, _analytics_cache, get_platform_analytics, _gist_languages_cache, get_gist_languages
|
|
|
|
|
from .schema import BUG_TABLE_RENAMES, migrate_bug_tables_to_issue_tables, init_db, _refresh_query_planner_stats, OLD_GATEWAY_URL, migrate_ai_gateway_settings, backfill_api_keys, _backfill_gamification
|
|
|
|
|
|
|
|
|
|
__all__ = [
|
|
|
|
|
"dataset",
|
|
|
|
|
"logging",
|
|
|
|
|
"Path",
|
|
|
|
|
"or_",
|
|
|
|
|
"defaultdict",
|
|
|
|
|
"datetime",
|
|
|
|
|
"timedelta",
|
|
|
|
|
"timezone",
|
|
|
|
|
"TTLCache",
|
|
|
|
|
"DATABASE_URL",
|
|
|
|
|
"DEFAULT_CORRECTION_PROMPT",
|
|
|
|
|
"DEFAULT_MODIFIER_PROMPT",
|
|
|
|
|
"INTERNAL_GATEWAY_URL",
|
|
|
|
|
"ensure_data_dirs",
|
|
|
|
|
"logger",
|
|
|
|
|
"db",
|
|
|
|
|
"refresh_snapshot",
|
|
|
|
|
"_local_cache_versions",
|
|
|
|
|
"_cache_version_cache",
|
|
|
|
|
"_cache_state_ready",
|
|
|
|
|
"_ensure_cache_state",
|
|
|
|
|
"get_cache_version",
|
|
|
|
|
"bump_cache_version",
|
|
|
|
|
"sync_local_cache",
|
|
|
|
|
"_index",
|
|
|
|
|
"_drop_index",
|
|
|
|
|
"_uid_index",
|
|
|
|
|
"get_table",
|
|
|
|
|
"_in_clause",
|
|
|
|
|
"_now_iso",
|
2026-07-26 14:57:18 +02:00
|
|
|
"conditional_update_row",
|
2026-07-04 21:22:11 +02:00
|
|
|
"_settings_cache",
|
|
|
|
|
"get_setting",
|
|
|
|
|
"get_int_setting",
|
|
|
|
|
"set_setting",
|
|
|
|
|
"clear_settings_cache",
|
|
|
|
|
"internal_gateway_key",
|
|
|
|
|
"get_users_by_uids",
|
|
|
|
|
"_admins_cache",
|
|
|
|
|
"invalidate_admins_cache",
|
|
|
|
|
"get_admin_uids",
|
|
|
|
|
"set_user_timezone",
|
2026-07-05 00:08:20 +02:00
|
|
|
"set_last_seen",
|
|
|
|
|
"get_online_users",
|
2026-07-04 21:22:11 +02:00
|
|
|
"get_primary_admin_uid",
|
|
|
|
|
"search_users_by_username",
|
|
|
|
|
"_relations_cache",
|
|
|
|
|
"get_user_relations",
|
|
|
|
|
"get_blocked_uids",
|
|
|
|
|
"get_muted_uids",
|
|
|
|
|
"get_silenced_uids",
|
|
|
|
|
"invalidate_user_relations",
|
|
|
|
|
"PAGE_SIZE",
|
|
|
|
|
"paginate",
|
|
|
|
|
"interleave_by_author",
|
|
|
|
|
"paginate_diverse",
|
|
|
|
|
"get_user_post_count",
|
2026-07-19 18:57:43 +02:00
|
|
|
"clear_user_post_count",
|
2026-07-04 21:22:11 +02:00
|
|
|
"build_pagination",
|
|
|
|
|
"SOFT_DELETE_TABLES",
|
|
|
|
|
"ensure_soft_delete_columns",
|
|
|
|
|
"soft_delete",
|
|
|
|
|
"soft_delete_in",
|
|
|
|
|
"restore",
|
|
|
|
|
"purge",
|
|
|
|
|
"list_deleted",
|
|
|
|
|
"count_deleted",
|
|
|
|
|
"restore_event",
|
|
|
|
|
"purge_event",
|
|
|
|
|
"_comment_count_cache",
|
|
|
|
|
"get_comment_counts_by_post_uids",
|
|
|
|
|
"get_post_counts_by_user_uids",
|
|
|
|
|
"get_vote_counts",
|
|
|
|
|
"get_user_votes",
|
|
|
|
|
"get_reactions_by_targets",
|
|
|
|
|
"get_user_bookmarks",
|
|
|
|
|
"get_polls_by_post_uids",
|
|
|
|
|
"get_poll_for_post",
|
|
|
|
|
"_add_usage",
|
|
|
|
|
"_get_usage",
|
|
|
|
|
"add_correction_usage",
|
|
|
|
|
"get_correction_usage",
|
|
|
|
|
"add_modifier_usage",
|
|
|
|
|
"get_modifier_usage",
|
|
|
|
|
"NEWS_USAGE_KEY",
|
|
|
|
|
"add_news_usage",
|
|
|
|
|
"get_news_usage",
|
|
|
|
|
"ISSUE_USAGE_KEY",
|
|
|
|
|
"add_issue_usage",
|
|
|
|
|
"get_issue_usage",
|
|
|
|
|
"SEO_USAGE_KEY",
|
|
|
|
|
"add_seo_usage",
|
|
|
|
|
"get_seo_usage",
|
|
|
|
|
"SEO_META_TYPES",
|
|
|
|
|
"get_seo_metadata",
|
|
|
|
|
"get_seo_metadata_batch",
|
|
|
|
|
"has_fresh_seo_metadata",
|
|
|
|
|
"upsert_seo_metadata",
|
|
|
|
|
"mark_seo_metadata_stale",
|
|
|
|
|
"record_activity",
|
|
|
|
|
"record_unique_activity",
|
|
|
|
|
"get_user_activity",
|
|
|
|
|
"_activity_cache",
|
|
|
|
|
"_ACTIVITY_TABLES",
|
|
|
|
|
"get_activity_calendar",
|
|
|
|
|
"_activity_level",
|
|
|
|
|
"get_first_activity_date",
|
|
|
|
|
"HEATMAP_WEEKS",
|
|
|
|
|
"get_activity_heatmap",
|
|
|
|
|
"get_activity_months",
|
|
|
|
|
"get_streaks",
|
|
|
|
|
"CUSTOMIZATION_GLOBAL_SCOPE",
|
|
|
|
|
"CUSTOMIZATION_LANGS",
|
|
|
|
|
"_customizations_cache",
|
|
|
|
|
"_customization_key",
|
|
|
|
|
"CUSTOMIZATION_PREF_COLUMNS",
|
|
|
|
|
"get_customization_prefs",
|
|
|
|
|
"set_customization_pref",
|
|
|
|
|
"get_custom_overrides",
|
|
|
|
|
"get_custom_override",
|
|
|
|
|
"list_custom_overrides",
|
|
|
|
|
"set_custom_override",
|
|
|
|
|
"delete_custom_override",
|
|
|
|
|
"EMAIL_ACCOUNT_DEFAULTS",
|
|
|
|
|
"list_email_accounts",
|
|
|
|
|
"get_email_account",
|
|
|
|
|
"set_email_account",
|
|
|
|
|
"delete_email_account",
|
|
|
|
|
"NOTIFICATION_TYPES",
|
|
|
|
|
"NOTIFICATION_CHANNELS",
|
|
|
|
|
"_NOTIFICATION_CHANNEL_COLUMNS",
|
|
|
|
|
"_NOTIFICATION_CHANNEL_DEFAULTS",
|
|
|
|
|
"_NOTIFICATION_TYPE_KEYS",
|
|
|
|
|
"_notification_prefs_cache",
|
|
|
|
|
"_notification_default",
|
|
|
|
|
"get_notification_default",
|
|
|
|
|
"set_notification_default",
|
|
|
|
|
"_notification_overrides",
|
|
|
|
|
"notification_enabled",
|
|
|
|
|
"get_notification_prefs",
|
|
|
|
|
"set_notification_pref",
|
|
|
|
|
"reset_notification_prefs",
|
|
|
|
|
"mark_notifications_read_by_target",
|
|
|
|
|
"record_fork",
|
|
|
|
|
"get_fork_parent",
|
|
|
|
|
"count_forks",
|
|
|
|
|
"soft_delete_fork_relations",
|
|
|
|
|
"delete_fork_relations",
|
|
|
|
|
"get_follow_counts",
|
|
|
|
|
"get_follow_list",
|
|
|
|
|
"get_following_among",
|
|
|
|
|
"_ds_now",
|
|
|
|
|
"create_deepsearch_session",
|
|
|
|
|
"update_deepsearch_session",
|
|
|
|
|
"get_deepsearch_session",
|
|
|
|
|
"add_deepsearch_message",
|
|
|
|
|
"get_deepsearch_messages",
|
|
|
|
|
"get_cached_deepsearch_url",
|
|
|
|
|
"upsert_deepsearch_url_cache",
|
|
|
|
|
"VOTABLE_TARGETS",
|
|
|
|
|
"STAR_TARGETS",
|
|
|
|
|
"_authors_cache",
|
|
|
|
|
"_ranked_authors",
|
|
|
|
|
"_rank_map",
|
|
|
|
|
"get_top_authors",
|
|
|
|
|
"get_leaderboard",
|
|
|
|
|
"get_user_rank",
|
|
|
|
|
"get_user_stars",
|
2026-07-06 05:57:47 +02:00
|
|
|
"clear_user_stars",
|
2026-07-04 21:22:11 +02:00
|
|
|
"update_target_stars",
|
|
|
|
|
"soft_delete_engagement",
|
|
|
|
|
"delete_engagement",
|
|
|
|
|
"get_target_owner_uid",
|
|
|
|
|
"_drop_blocked",
|
|
|
|
|
"_build_comment_items",
|
|
|
|
|
"load_comments",
|
|
|
|
|
"get_recent_comments_by_target_uids",
|
|
|
|
|
"get_recent_comments_by_post_uids",
|
|
|
|
|
"load_comments_by_target_uids",
|
|
|
|
|
"resolve_by_slug",
|
|
|
|
|
"resolve_object_url",
|
|
|
|
|
"get_uids_by_username_match",
|
|
|
|
|
"text_search_clause",
|
|
|
|
|
"get_daily_topic",
|
|
|
|
|
"get_featured_news",
|
2026-07-19 18:57:43 +02:00
|
|
|
"get_trending_topics",
|
2026-07-04 21:22:11 +02:00
|
|
|
"get_attachments",
|
|
|
|
|
"get_attachments_by_type",
|
|
|
|
|
"get_news_images_by_uids",
|
|
|
|
|
"delete_attachment_record",
|
|
|
|
|
"delete_attachments",
|
|
|
|
|
"_delete_attachment_file",
|
|
|
|
|
"get_user_media",
|
Add attachment management CRUD to the /uploads API
Complete the read and update faces of the signed-in user's attachment
management over the existing attachments table:
- GET /uploads: paginated list of the user's own attachments, newest
first, with an optional linked/orphaned filter
- GET /uploads/{uid}: fetch one attachment (owner or admin)
- PATCH /uploads/{uid}: rename the display filename, always preserving
the original extension (owner or admin, audited as attachment.rename)
Adds get_user_attachments/get_user_attachment data helpers, the
rename_attachment operation, AttachmentRenameForm, the UploadItemOut and
UploadsListOut schemas, the Devii tools list_attachments/get_attachment/
rename_attachment, expanded API reference documentation for the full
lifecycle including delete, and api-tier tests.
2026-07-24 20:30:49 +02:00
|
|
|
"get_user_attachments",
|
|
|
|
|
"get_user_attachment",
|
2026-07-04 21:22:11 +02:00
|
|
|
"get_deleted_media",
|
|
|
|
|
"_stats_cache",
|
|
|
|
|
"get_site_stats",
|
|
|
|
|
"_analytics_cache",
|
|
|
|
|
"get_platform_analytics",
|
|
|
|
|
"_gist_languages_cache",
|
|
|
|
|
"get_gist_languages",
|
|
|
|
|
"BUG_TABLE_RENAMES",
|
|
|
|
|
"migrate_bug_tables_to_issue_tables",
|
|
|
|
|
"init_db",
|
|
|
|
|
"_refresh_query_planner_stats",
|
|
|
|
|
"OLD_GATEWAY_URL",
|
|
|
|
|
"migrate_ai_gateway_settings",
|
|
|
|
|
"backfill_api_keys",
|
|
|
|
|
"_backfill_gamification",
|
|
|
|
|
]
|
feat(nadia): Add database index and devlog query helper
Outcome: done
Changed: devplacepy/database/schema.py:45, devplacepy/database/engagement.py:3-5,194-210, devplacepy/database/__init__.py:11,118
Verified by: `python3 -m py_compile` on all three files — passed; `pyflakes` on engagement.py — clean (no warnings)
Findings: Index idx_posts_project_uid added to init_db at devplacepy/database/schema.py:45 (CREATE INDEX IF NOT EXISTS on posts.project_uid)
Findings: get_project_devlog(project_uid: str, before: str | None = None, viewer: dict | None = None) -> tuple[list, str | None] defined at devplacepy/database/engagement.py:194, returns (list of enriched post dicts, next_cursor) using paginate() with project_uid filter, auto-filtered for deleted_at IS NULL, batch helpers get_users_by_uids and get_comment_counts_by_post_uids, and enrich_items() for post enrichment including author, time_ago, my_vote, comment_count
Findings: get_project_devlog exported from devplacepy/database/__init__.py via import (line 11) and __all__ (line 118)
Open: None
Confidence: high - all acceptance criteria met, syntax verified, no warnings introduced
Typosaurus-Run: 45c0aee6df2649ffaa248729bdfd5841
Typosaurus-Node: 17f01a1e325e40ecb73ffe423f78c4a9
Typosaurus-Agent: @nadia
Refs: #135
2026-07-26 22:50:56 +02:00
|
|
|
|
|
|
|
|
|