switch ActivityPub upstream from Takahe to Incarnator
This commit is contained in:
parent
c52ac69ae9
commit
9654e84568
9 changed files with 345 additions and 371 deletions
2
.gitmodules
vendored
2
.gitmodules
vendored
|
@ -1,4 +1,4 @@
|
||||||
[submodule "neodb-takahe"]
|
[submodule "neodb-takahe"]
|
||||||
path = neodb-takahe
|
path = neodb-takahe
|
||||||
url = https://github.com/neodb-social/neodb-takahe.git
|
url = https://github.com/neodb-social/neodb-incarnator.git
|
||||||
branch = neodb
|
branch = neodb
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# syntax=docker/dockerfile:1
|
# syntax=docker/dockerfile:1
|
||||||
FROM python:3.11-slim as build
|
FROM python:3.12-slim as build
|
||||||
ENV PYTHONDONTWRITEBYTECODE=1
|
ENV PYTHONDONTWRITEBYTECODE=1
|
||||||
ENV PYTHONUNBUFFERED=1
|
ENV PYTHONUNBUFFERED=1
|
||||||
|
|
||||||
|
@ -21,10 +21,10 @@ RUN --mount=type=cache,sharing=locked,target=/root/.cache /neodb-venv/bin/python
|
||||||
|
|
||||||
WORKDIR /takahe
|
WORKDIR /takahe
|
||||||
RUN python -m venv /takahe-venv
|
RUN python -m venv /takahe-venv
|
||||||
RUN --mount=type=cache,sharing=locked,target=/root/.cache /takahe-venv/bin/python3 -m pip install --upgrade -r requirements.txt
|
RUN --mount=type=cache,sharing=locked,target=/root/.cache /takahe-venv/bin/python3 -m pip install --upgrade -r requirements.lock
|
||||||
|
|
||||||
# runtime stage
|
# runtime stage
|
||||||
FROM python:3.11-slim as runtime
|
FROM python:3.12-slim as runtime
|
||||||
ENV PYTHONDONTWRITEBYTECODE=1
|
ENV PYTHONDONTWRITEBYTECODE=1
|
||||||
ENV PYTHONUNBUFFERED=1
|
ENV PYTHONUNBUFFERED=1
|
||||||
|
|
||||||
|
|
|
@ -188,7 +188,7 @@ services:
|
||||||
|
|
||||||
neodb-worker-extra:
|
neodb-worker-extra:
|
||||||
<<: *neodb-service
|
<<: *neodb-service
|
||||||
command: neodb-manage rqworker mastodon fetch crawl ap
|
command: neodb-manage rqworker-pool --num-workers ${NEODB_RQ_WORKER_NUM:-4} mastodon fetch crawl ap
|
||||||
depends_on:
|
depends_on:
|
||||||
migration:
|
migration:
|
||||||
condition: service_completed_successfully
|
condition: service_completed_successfully
|
||||||
|
|
|
@ -8,7 +8,7 @@ NeoDB is a Django project, and it runs side by side with a [modified version](ht
|
||||||
|
|
||||||
Prerequisite
|
Prerequisite
|
||||||
------------
|
------------
|
||||||
- Python 3.11.x
|
- Python 3.12.x
|
||||||
- Docker Compose v2 or newer
|
- Docker Compose v2 or newer
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -142,6 +142,6 @@ It's possible to run multiple clusters in one host server, as long as `NEODB_SIT
|
||||||
|
|
||||||
## Scaling
|
## Scaling
|
||||||
|
|
||||||
For high-traffic instance, spin up `NEODB_WEB_WORKER_NUM`, `TAKAHE_WEB_WORKER_NUM`, `TAKAHE_STATOR_CONCURRENCY` and `TAKAHE_STATOR_CONCURRENCY_PER_MODEL` as long as the host server can handle them.
|
For high-traffic instance, spin up `NEODB_WEB_WORKER_NUM`, `NEODB_API_WORKER_NUM`, `NEODB_RQ_WORKER_NUM`, `TAKAHE_WEB_WORKER_NUM`, `TAKAHE_STATOR_CONCURRENCY` and `TAKAHE_STATOR_CONCURRENCY_PER_MODEL` as long as the host server can handle them.
|
||||||
|
|
||||||
Further scaling up with multiple nodes (e.g. via Kubernetes) is beyond the scope of this document, but consider run db/redis/typesense separately, and then duplicate web/worker/stator containers as long as connections and mounts are properly configured; `migration` only runs once when start or upgrade, it should be kept that way.
|
Further scaling up with multiple nodes (e.g. via Kubernetes) is beyond the scope of this document, but consider run db/redis/typesense separately, and then duplicate web/worker/stator containers as long as connections and mounts are properly configured; `migration` only runs once when start or upgrade, it should be kept that way.
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit bf2db828b2ae0a6847155ef25f283ebfab75cb23
|
Subproject commit f474e46fa1661460bc2443b7845395afe89b5503
|
|
@ -2,6 +2,10 @@
|
||||||
|
|
||||||
# copy along with compose.yml, rename this file to .env
|
# copy along with compose.yml, rename this file to .env
|
||||||
|
|
||||||
|
# Must uncomment these if you are doing development
|
||||||
|
# NEODB_DEBUG=True
|
||||||
|
# NEODB_IMAGE=neodb/neodb:edge
|
||||||
|
|
||||||
# Change these before start the instance for the first time!!
|
# Change these before start the instance for the first time!!
|
||||||
NEODB_SECRET_KEY=change_me
|
NEODB_SECRET_KEY=change_me
|
||||||
NEODB_SITE_NAME=Example Site
|
NEODB_SITE_NAME=Example Site
|
||||||
|
@ -13,9 +17,9 @@ NEODB_SITE_LOGO=/logo.png
|
||||||
NEODB_SITE_ICON=/icon.png
|
NEODB_SITE_ICON=/icon.png
|
||||||
NEODB_SITE_LINKS=@NiceDB=https://donotban.com/@testie,@NeoDB=https://mastodon.social/@neodb
|
NEODB_SITE_LINKS=@NiceDB=https://donotban.com/@testie,@NeoDB=https://mastodon.social/@neodb
|
||||||
|
|
||||||
# Uncomment these if you are doing development
|
# To enable push notification, generate a keypair from https://web-push-codelab.glitch.me
|
||||||
# NEODB_DEBUG=True
|
# TAKAHE_VAPID_PUBLIC_KEY=
|
||||||
# NEODB_IMAGE=neodb/neodb:edge
|
# TAKAHE_VAPID_PRIVATE_KEY=tEPrD2JJkibcDC1G_sE8ZgZGTbd5w64spEJ7h2fGgxk
|
||||||
|
|
||||||
# HTTP port your reverse proxy should send request to
|
# HTTP port your reverse proxy should send request to
|
||||||
# NEODB_PORT=8000
|
# NEODB_PORT=8000
|
||||||
|
@ -28,6 +32,8 @@ NEODB_SITE_LINKS=@NiceDB=https://donotban.com/@testie,@NeoDB=https://mastodon.so
|
||||||
|
|
||||||
# Scaling parameters
|
# Scaling parameters
|
||||||
# NEODB_WEB_WORKER_NUM=32
|
# NEODB_WEB_WORKER_NUM=32
|
||||||
|
# NEODB_API_WORKER_NUM=16
|
||||||
|
# NEODB_RQ_WORKER_NUM=8
|
||||||
# TAKAHE_WEB_WORKER_NUM=32
|
# TAKAHE_WEB_WORKER_NUM=32
|
||||||
# TAKAHE_STATOR_CONCURRENCY=10
|
# TAKAHE_STATOR_CONCURRENCY=10
|
||||||
# TAKAHE_STATOR_CONCURRENCY_PER_MODEL=10
|
# TAKAHE_STATOR_CONCURRENCY_PER_MODEL=10
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
# Generated by Django 4.2.4 on 2023-08-12 16:48
|
# Generated by Django 4.2.13 on 2024-06-01 05:38
|
||||||
|
|
||||||
import functools
|
import functools
|
||||||
|
|
||||||
|
@ -10,33 +10,12 @@ import takahe.models
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
initial = True
|
initial = True
|
||||||
|
|
||||||
dependencies = []
|
dependencies = []
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
migrations.CreateModel(
|
|
||||||
name="TakaheSession",
|
|
||||||
fields=[
|
|
||||||
(
|
|
||||||
"session_key",
|
|
||||||
models.CharField(
|
|
||||||
max_length=40,
|
|
||||||
primary_key=True,
|
|
||||||
serialize=False,
|
|
||||||
verbose_name="session key",
|
|
||||||
),
|
|
||||||
),
|
|
||||||
("session_data", models.TextField(verbose_name="session data")),
|
|
||||||
(
|
|
||||||
"expire_date",
|
|
||||||
models.DateTimeField(db_index=True, verbose_name="expire date"),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
options={
|
|
||||||
"db_table": "django_session",
|
|
||||||
},
|
|
||||||
),
|
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name="Domain",
|
name="Domain",
|
||||||
fields=[
|
fields=[
|
||||||
|
@ -148,22 +127,38 @@ class Migration(migrations.Migration):
|
||||||
("actor_uri", models.CharField(max_length=500, unique=True)),
|
("actor_uri", models.CharField(max_length=500, unique=True)),
|
||||||
("state", models.CharField(default="outdated", max_length=100)),
|
("state", models.CharField(default="outdated", max_length=100)),
|
||||||
("state_changed", models.DateTimeField(auto_now_add=True)),
|
("state_changed", models.DateTimeField(auto_now_add=True)),
|
||||||
|
("state_next_attempt", models.DateTimeField(blank=True, null=True)),
|
||||||
|
(
|
||||||
|
"state_locked_until",
|
||||||
|
models.DateTimeField(blank=True, db_index=True, null=True),
|
||||||
|
),
|
||||||
("local", models.BooleanField(db_index=True)),
|
("local", models.BooleanField(db_index=True)),
|
||||||
("username", models.CharField(blank=True, max_length=500, null=True)),
|
("username", models.CharField(blank=True, max_length=500, null=True)),
|
||||||
(
|
(
|
||||||
"name",
|
"name",
|
||||||
models.CharField(
|
models.CharField(
|
||||||
blank=True, max_length=500, null=True, verbose_name="昵称"
|
blank=True,
|
||||||
|
max_length=500,
|
||||||
|
null=True,
|
||||||
|
verbose_name="Display Name",
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
("summary", models.TextField(blank=True, null=True, verbose_name="简介")),
|
(
|
||||||
|
"summary",
|
||||||
|
models.TextField(blank=True, null=True, verbose_name="Bio"),
|
||||||
|
),
|
||||||
(
|
(
|
||||||
"manually_approves_followers",
|
"manually_approves_followers",
|
||||||
models.BooleanField(default=False, verbose_name="手工审核关注者"),
|
models.BooleanField(
|
||||||
|
default=False, verbose_name="Manually approve new followers"
|
||||||
|
),
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"discoverable",
|
"discoverable",
|
||||||
models.BooleanField(default=True, verbose_name="允许被发现或推荐"),
|
models.BooleanField(
|
||||||
|
default=True,
|
||||||
|
verbose_name="Include profile and posts in search and discovery",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"profile_uri",
|
"profile_uri",
|
||||||
|
@ -190,6 +185,30 @@ class Migration(migrations.Migration):
|
||||||
models.CharField(blank=True, max_length=500, null=True),
|
models.CharField(blank=True, max_length=500, null=True),
|
||||||
),
|
),
|
||||||
("actor_type", models.CharField(default="person", max_length=100)),
|
("actor_type", models.CharField(default="person", max_length=100)),
|
||||||
|
(
|
||||||
|
"icon",
|
||||||
|
models.ImageField(
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
storage=takahe.models.upload_store,
|
||||||
|
upload_to=functools.partial(
|
||||||
|
takahe.models.upload_namer, *("profile_images",), **{}
|
||||||
|
),
|
||||||
|
verbose_name="Profile picture",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"image",
|
||||||
|
models.ImageField(
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
storage=takahe.models.upload_store,
|
||||||
|
upload_to=functools.partial(
|
||||||
|
takahe.models.upload_namer, *("background_images",), **{}
|
||||||
|
),
|
||||||
|
verbose_name="Header picture",
|
||||||
|
),
|
||||||
|
),
|
||||||
("metadata", models.JSONField(blank=True, null=True)),
|
("metadata", models.JSONField(blank=True, null=True)),
|
||||||
("pinned", models.JSONField(blank=True, null=True)),
|
("pinned", models.JSONField(blank=True, null=True)),
|
||||||
("sensitive", models.BooleanField(default=False)),
|
("sensitive", models.BooleanField(default=False)),
|
||||||
|
@ -225,40 +244,48 @@ class Migration(migrations.Migration):
|
||||||
"db_table": "users_identity",
|
"db_table": "users_identity",
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
migrations.AddField(
|
migrations.CreateModel(
|
||||||
model_name="identity",
|
name="InboxMessage",
|
||||||
name="icon",
|
fields=[
|
||||||
field=models.ImageField(
|
(
|
||||||
blank=True,
|
"id",
|
||||||
null=True,
|
models.BigAutoField(
|
||||||
storage=takahe.models.upload_store,
|
auto_created=True,
|
||||||
upload_to=functools.partial(
|
primary_key=True,
|
||||||
takahe.models.upload_namer, *("profile_images",), **{}
|
serialize=False,
|
||||||
|
verbose_name="ID",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
verbose_name="头像",
|
("message", models.JSONField()),
|
||||||
),
|
("state", models.CharField(default="received", max_length=100)),
|
||||||
|
("state_changed", models.DateTimeField(auto_now_add=True)),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
"db_table": "users_inboxmessage",
|
||||||
|
},
|
||||||
),
|
),
|
||||||
migrations.AddField(
|
migrations.CreateModel(
|
||||||
model_name="identity",
|
name="Invite",
|
||||||
name="image",
|
fields=[
|
||||||
field=models.ImageField(
|
(
|
||||||
blank=True,
|
"id",
|
||||||
null=True,
|
models.BigAutoField(
|
||||||
storage=takahe.models.upload_store,
|
auto_created=True,
|
||||||
upload_to=functools.partial(
|
primary_key=True,
|
||||||
takahe.models.upload_namer, *("background_images",), **{}
|
serialize=False,
|
||||||
|
verbose_name="ID",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
("token", models.CharField(max_length=500, unique=True)),
|
||||||
),
|
("note", models.TextField(blank=True, null=True)),
|
||||||
migrations.AddField(
|
("uses", models.IntegerField(blank=True, null=True)),
|
||||||
model_name="identity",
|
("expires", models.DateTimeField(blank=True, null=True)),
|
||||||
name="state_locked_until",
|
("created", models.DateTimeField(auto_now_add=True)),
|
||||||
field=models.DateTimeField(blank=True, db_index=True, null=True),
|
("updated", models.DateTimeField(auto_now=True)),
|
||||||
),
|
],
|
||||||
migrations.AddField(
|
options={
|
||||||
model_name="identity",
|
"db_table": "users_invite",
|
||||||
name="state_next_attempt",
|
},
|
||||||
field=models.DateTimeField(blank=True, null=True),
|
|
||||||
),
|
),
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name="Post",
|
name="Post",
|
||||||
|
@ -294,6 +321,7 @@ class Migration(migrations.Migration):
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
("content", models.TextField()),
|
("content", models.TextField()),
|
||||||
|
("language", models.CharField(blank=True, default="")),
|
||||||
(
|
(
|
||||||
"type",
|
"type",
|
||||||
models.CharField(
|
models.CharField(
|
||||||
|
@ -360,38 +388,6 @@ class Migration(migrations.Migration):
|
||||||
"db_table": "activities_post",
|
"db_table": "activities_post",
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
migrations.CreateModel(
|
|
||||||
name="User",
|
|
||||||
fields=[
|
|
||||||
(
|
|
||||||
"id",
|
|
||||||
models.BigAutoField(
|
|
||||||
auto_created=True,
|
|
||||||
primary_key=True,
|
|
||||||
serialize=False,
|
|
||||||
verbose_name="ID",
|
|
||||||
),
|
|
||||||
),
|
|
||||||
("password", models.CharField(max_length=128, verbose_name="password")),
|
|
||||||
(
|
|
||||||
"last_login",
|
|
||||||
models.DateTimeField(
|
|
||||||
blank=True, null=True, verbose_name="last login"
|
|
||||||
),
|
|
||||||
),
|
|
||||||
("email", models.EmailField(max_length=254, unique=True)),
|
|
||||||
("admin", models.BooleanField(default=False)),
|
|
||||||
("moderator", models.BooleanField(default=False)),
|
|
||||||
("banned", models.BooleanField(default=False)),
|
|
||||||
("deleted", models.BooleanField(default=False)),
|
|
||||||
("created", models.DateTimeField(auto_now_add=True)),
|
|
||||||
("updated", models.DateTimeField(auto_now=True)),
|
|
||||||
("last_seen", models.DateTimeField(auto_now_add=True)),
|
|
||||||
],
|
|
||||||
options={
|
|
||||||
"db_table": "users_user",
|
|
||||||
},
|
|
||||||
),
|
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name="PostInteraction",
|
name="PostInteraction",
|
||||||
fields=[
|
fields=[
|
||||||
|
@ -448,22 +444,67 @@ class Migration(migrations.Migration):
|
||||||
"db_table": "activities_postinteraction",
|
"db_table": "activities_postinteraction",
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
migrations.AddField(
|
migrations.CreateModel(
|
||||||
model_name="identity",
|
name="Relay",
|
||||||
name="users",
|
fields=[
|
||||||
field=models.ManyToManyField(
|
(
|
||||||
blank=True, related_name="identities", to="takahe.user"
|
"id",
|
||||||
),
|
models.BigAutoField(
|
||||||
),
|
auto_created=True,
|
||||||
migrations.AddField(
|
primary_key=True,
|
||||||
model_name="domain",
|
serialize=False,
|
||||||
name="users",
|
verbose_name="ID",
|
||||||
field=models.ManyToManyField(
|
),
|
||||||
blank=True, related_name="domains", to="takahe.user"
|
),
|
||||||
),
|
("inbox_uri", models.CharField(max_length=500, unique=True)),
|
||||||
|
("state", models.CharField(default="new", max_length=100)),
|
||||||
|
("state_changed", models.DateTimeField(auto_now_add=True)),
|
||||||
|
("state_next_attempt", models.DateTimeField(blank=True, null=True)),
|
||||||
|
(
|
||||||
|
"state_locked_until",
|
||||||
|
models.DateTimeField(blank=True, db_index=True, null=True),
|
||||||
|
),
|
||||||
|
("created", models.DateTimeField(auto_now_add=True)),
|
||||||
|
("updated", models.DateTimeField(auto_now=True)),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
"db_table": "users_relay",
|
||||||
|
},
|
||||||
),
|
),
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name="Block",
|
name="User",
|
||||||
|
fields=[
|
||||||
|
(
|
||||||
|
"id",
|
||||||
|
models.BigAutoField(
|
||||||
|
auto_created=True,
|
||||||
|
primary_key=True,
|
||||||
|
serialize=False,
|
||||||
|
verbose_name="ID",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
("password", models.CharField(max_length=128, verbose_name="password")),
|
||||||
|
(
|
||||||
|
"last_login",
|
||||||
|
models.DateTimeField(
|
||||||
|
blank=True, null=True, verbose_name="last login"
|
||||||
|
),
|
||||||
|
),
|
||||||
|
("email", models.EmailField(max_length=254, unique=True)),
|
||||||
|
("admin", models.BooleanField(default=False)),
|
||||||
|
("moderator", models.BooleanField(default=False)),
|
||||||
|
("banned", models.BooleanField(default=False)),
|
||||||
|
("deleted", models.BooleanField(default=False)),
|
||||||
|
("created", models.DateTimeField(auto_now_add=True)),
|
||||||
|
("updated", models.DateTimeField(auto_now=True)),
|
||||||
|
("last_seen", models.DateTimeField(auto_now_add=True)),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
"db_table": "users_user",
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name="PostAttachment",
|
||||||
fields=[
|
fields=[
|
||||||
(
|
(
|
||||||
"id",
|
"id",
|
||||||
|
@ -476,176 +517,71 @@ class Migration(migrations.Migration):
|
||||||
),
|
),
|
||||||
("state", models.CharField(default="new", max_length=100)),
|
("state", models.CharField(default="new", max_length=100)),
|
||||||
("state_changed", models.DateTimeField(auto_now_add=True)),
|
("state_changed", models.DateTimeField(auto_now_add=True)),
|
||||||
("uri", models.CharField(blank=True, max_length=500, null=True)),
|
("mimetype", models.CharField(max_length=200)),
|
||||||
("mute", models.BooleanField()),
|
(
|
||||||
("include_notifications", models.BooleanField(default=False)),
|
"file",
|
||||||
("expires", models.DateTimeField(blank=True, null=True)),
|
models.FileField(
|
||||||
("note", models.TextField(blank=True, null=True)),
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
storage=takahe.models.upload_store,
|
||||||
|
upload_to=functools.partial(
|
||||||
|
takahe.models.upload_namer, *("attachments",), **{}
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"thumbnail",
|
||||||
|
models.ImageField(
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
storage=takahe.models.upload_store,
|
||||||
|
upload_to=functools.partial(
|
||||||
|
takahe.models.upload_namer,
|
||||||
|
*("attachment_thumbnails",),
|
||||||
|
**{}
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
("remote_url", models.CharField(blank=True, max_length=500, null=True)),
|
||||||
|
("name", models.TextField(blank=True, null=True)),
|
||||||
|
("width", models.IntegerField(blank=True, null=True)),
|
||||||
|
("height", models.IntegerField(blank=True, null=True)),
|
||||||
|
("focal_x", models.FloatField(blank=True, null=True)),
|
||||||
|
("focal_y", models.FloatField(blank=True, null=True)),
|
||||||
|
("blurhash", models.TextField(blank=True, null=True)),
|
||||||
("created", models.DateTimeField(auto_now_add=True)),
|
("created", models.DateTimeField(auto_now_add=True)),
|
||||||
("updated", models.DateTimeField(auto_now=True)),
|
("updated", models.DateTimeField(auto_now=True)),
|
||||||
(
|
(
|
||||||
"source",
|
"author",
|
||||||
models.ForeignKey(
|
|
||||||
on_delete=django.db.models.deletion.CASCADE,
|
|
||||||
related_name="outbound_blocks",
|
|
||||||
to="takahe.identity",
|
|
||||||
),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"target",
|
|
||||||
models.ForeignKey(
|
|
||||||
on_delete=django.db.models.deletion.CASCADE,
|
|
||||||
related_name="inbound_blocks",
|
|
||||||
to="takahe.identity",
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
options={
|
|
||||||
"db_table": "users_block",
|
|
||||||
},
|
|
||||||
),
|
|
||||||
migrations.AlterUniqueTogether(
|
|
||||||
name="identity",
|
|
||||||
unique_together={("username", "domain")},
|
|
||||||
),
|
|
||||||
migrations.CreateModel(
|
|
||||||
name="Follow",
|
|
||||||
fields=[
|
|
||||||
(
|
|
||||||
"id",
|
|
||||||
models.BigIntegerField(
|
|
||||||
default=takahe.models.Snowflake.generate_follow,
|
|
||||||
primary_key=True,
|
|
||||||
serialize=False,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"boosts",
|
|
||||||
models.BooleanField(
|
|
||||||
default=True, help_text="Also follow boosts from this user"
|
|
||||||
),
|
|
||||||
),
|
|
||||||
("uri", models.CharField(blank=True, max_length=500, null=True)),
|
|
||||||
("note", models.TextField(blank=True, null=True)),
|
|
||||||
("state", models.CharField(default="unrequested", max_length=100)),
|
|
||||||
("state_changed", models.DateTimeField(auto_now_add=True)),
|
|
||||||
("created", models.DateTimeField(auto_now_add=True)),
|
|
||||||
("updated", models.DateTimeField(auto_now=True)),
|
|
||||||
(
|
|
||||||
"source",
|
|
||||||
models.ForeignKey(
|
|
||||||
on_delete=django.db.models.deletion.CASCADE,
|
|
||||||
related_name="outbound_follows",
|
|
||||||
to="takahe.identity",
|
|
||||||
),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"target",
|
|
||||||
models.ForeignKey(
|
|
||||||
on_delete=django.db.models.deletion.CASCADE,
|
|
||||||
related_name="inbound_follows",
|
|
||||||
to="takahe.identity",
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
options={
|
|
||||||
"db_table": "users_follow",
|
|
||||||
"unique_together": {("source", "target")},
|
|
||||||
},
|
|
||||||
),
|
|
||||||
migrations.CreateModel(
|
|
||||||
name="InboxMessage",
|
|
||||||
fields=[
|
|
||||||
(
|
|
||||||
"id",
|
|
||||||
models.BigAutoField(
|
|
||||||
auto_created=True,
|
|
||||||
primary_key=True,
|
|
||||||
serialize=False,
|
|
||||||
verbose_name="ID",
|
|
||||||
),
|
|
||||||
),
|
|
||||||
("message", models.JSONField()),
|
|
||||||
("state", models.CharField(default="received", max_length=100)),
|
|
||||||
("state_changed", models.DateTimeField(auto_now_add=True)),
|
|
||||||
],
|
|
||||||
options={
|
|
||||||
"db_table": "users_inboxmessage",
|
|
||||||
},
|
|
||||||
),
|
|
||||||
migrations.CreateModel(
|
|
||||||
name="Config",
|
|
||||||
fields=[
|
|
||||||
(
|
|
||||||
"id",
|
|
||||||
models.BigAutoField(
|
|
||||||
auto_created=True,
|
|
||||||
primary_key=True,
|
|
||||||
serialize=False,
|
|
||||||
verbose_name="ID",
|
|
||||||
),
|
|
||||||
),
|
|
||||||
("key", models.CharField(max_length=500)),
|
|
||||||
("json", models.JSONField(blank=True, null=True)),
|
|
||||||
("image", models.ImageField(blank=True, null=True, upload_to="")),
|
|
||||||
(
|
|
||||||
"domain",
|
|
||||||
models.ForeignKey(
|
models.ForeignKey(
|
||||||
blank=True,
|
blank=True,
|
||||||
null=True,
|
null=True,
|
||||||
on_delete=django.db.models.deletion.CASCADE,
|
on_delete=django.db.models.deletion.CASCADE,
|
||||||
related_name="configs",
|
related_name="attachments",
|
||||||
to="takahe.domain",
|
|
||||||
),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"identity",
|
|
||||||
models.ForeignKey(
|
|
||||||
blank=True,
|
|
||||||
null=True,
|
|
||||||
on_delete=django.db.models.deletion.CASCADE,
|
|
||||||
related_name="configs",
|
|
||||||
to="takahe.identity",
|
to="takahe.identity",
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"user",
|
"post",
|
||||||
models.ForeignKey(
|
models.ForeignKey(
|
||||||
blank=True,
|
blank=True,
|
||||||
null=True,
|
null=True,
|
||||||
on_delete=django.db.models.deletion.CASCADE,
|
on_delete=django.db.models.deletion.CASCADE,
|
||||||
related_name="configs",
|
related_name="attachments",
|
||||||
to="takahe.user",
|
to="takahe.post",
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
options={
|
options={
|
||||||
"db_table": "core_config",
|
"db_table": "activities_postattachment",
|
||||||
"unique_together": {("key", "user", "identity", "domain")},
|
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
migrations.CreateModel(
|
migrations.AddField(
|
||||||
name="Invite",
|
model_name="identity",
|
||||||
fields=[
|
name="users",
|
||||||
(
|
field=models.ManyToManyField(
|
||||||
"id",
|
blank=True, related_name="identities", to="takahe.user"
|
||||||
models.BigAutoField(
|
),
|
||||||
auto_created=True,
|
|
||||||
primary_key=True,
|
|
||||||
serialize=False,
|
|
||||||
verbose_name="ID",
|
|
||||||
),
|
|
||||||
),
|
|
||||||
("token", models.CharField(max_length=500, unique=True)),
|
|
||||||
("note", models.TextField(blank=True, null=True)),
|
|
||||||
("uses", models.IntegerField(blank=True, null=True)),
|
|
||||||
("expires", models.DateTimeField(blank=True, null=True)),
|
|
||||||
("created", models.DateTimeField(auto_now_add=True)),
|
|
||||||
("updated", models.DateTimeField(auto_now=True)),
|
|
||||||
],
|
|
||||||
options={
|
|
||||||
"db_table": "users_invite",
|
|
||||||
},
|
|
||||||
),
|
),
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name="FanOut",
|
name="FanOut",
|
||||||
|
@ -723,6 +659,80 @@ class Migration(migrations.Migration):
|
||||||
"db_table": "activities_fanout",
|
"db_table": "activities_fanout",
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name="domain",
|
||||||
|
name="users",
|
||||||
|
field=models.ManyToManyField(
|
||||||
|
blank=True, related_name="domains", to="takahe.user"
|
||||||
|
),
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name="Block",
|
||||||
|
fields=[
|
||||||
|
(
|
||||||
|
"id",
|
||||||
|
models.BigAutoField(
|
||||||
|
auto_created=True,
|
||||||
|
primary_key=True,
|
||||||
|
serialize=False,
|
||||||
|
verbose_name="ID",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
("state", models.CharField(default="new", max_length=100)),
|
||||||
|
("state_changed", models.DateTimeField(auto_now_add=True)),
|
||||||
|
("uri", models.CharField(blank=True, max_length=500, null=True)),
|
||||||
|
("mute", models.BooleanField()),
|
||||||
|
("include_notifications", models.BooleanField(default=False)),
|
||||||
|
("expires", models.DateTimeField(blank=True, null=True)),
|
||||||
|
("note", models.TextField(blank=True, null=True)),
|
||||||
|
("created", models.DateTimeField(auto_now_add=True)),
|
||||||
|
("updated", models.DateTimeField(auto_now=True)),
|
||||||
|
(
|
||||||
|
"source",
|
||||||
|
models.ForeignKey(
|
||||||
|
on_delete=django.db.models.deletion.CASCADE,
|
||||||
|
related_name="outbound_blocks",
|
||||||
|
to="takahe.identity",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"target",
|
||||||
|
models.ForeignKey(
|
||||||
|
on_delete=django.db.models.deletion.CASCADE,
|
||||||
|
related_name="inbound_blocks",
|
||||||
|
to="takahe.identity",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
"db_table": "users_block",
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name="Announcement",
|
||||||
|
fields=[
|
||||||
|
(
|
||||||
|
"id",
|
||||||
|
models.BigAutoField(
|
||||||
|
auto_created=True,
|
||||||
|
primary_key=True,
|
||||||
|
serialize=False,
|
||||||
|
verbose_name="ID",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
("text", models.TextField()),
|
||||||
|
("published", models.BooleanField(default=False)),
|
||||||
|
("start", models.DateTimeField(blank=True, null=True)),
|
||||||
|
("end", models.DateTimeField(blank=True, null=True)),
|
||||||
|
("include_unauthenticated", models.BooleanField(default=False)),
|
||||||
|
("created", models.DateTimeField(auto_now_add=True)),
|
||||||
|
("updated", models.DateTimeField(auto_now=True)),
|
||||||
|
("seen", models.ManyToManyField(blank=True, to="takahe.user")),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
"db_table": "users_announcement",
|
||||||
|
},
|
||||||
|
),
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name="TimelineEvent",
|
name="TimelineEvent",
|
||||||
fields=[
|
fields=[
|
||||||
|
@ -813,149 +823,104 @@ class Migration(migrations.Migration):
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
migrations.AlterUniqueTogether(
|
||||||
|
name="identity",
|
||||||
|
unique_together={("username", "domain")},
|
||||||
|
),
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name="PostAttachment",
|
name="Follow",
|
||||||
fields=[
|
fields=[
|
||||||
(
|
(
|
||||||
"id",
|
"id",
|
||||||
models.BigAutoField(
|
models.BigIntegerField(
|
||||||
auto_created=True,
|
default=takahe.models.Snowflake.generate_follow,
|
||||||
primary_key=True,
|
primary_key=True,
|
||||||
serialize=False,
|
serialize=False,
|
||||||
verbose_name="ID",
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
("state", models.CharField(default="new", max_length=100)),
|
(
|
||||||
|
"boosts",
|
||||||
|
models.BooleanField(
|
||||||
|
default=True, help_text="Also follow boosts from this user"
|
||||||
|
),
|
||||||
|
),
|
||||||
|
("uri", models.CharField(blank=True, max_length=500, null=True)),
|
||||||
|
("note", models.TextField(blank=True, null=True)),
|
||||||
|
("state", models.CharField(default="unrequested", max_length=100)),
|
||||||
("state_changed", models.DateTimeField(auto_now_add=True)),
|
("state_changed", models.DateTimeField(auto_now_add=True)),
|
||||||
("mimetype", models.CharField(max_length=200)),
|
|
||||||
(
|
|
||||||
"file",
|
|
||||||
models.FileField(
|
|
||||||
blank=True,
|
|
||||||
null=True,
|
|
||||||
storage=takahe.models.upload_store,
|
|
||||||
upload_to=functools.partial(
|
|
||||||
takahe.models.upload_namer, *("attachments",), **{}
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"thumbnail",
|
|
||||||
models.ImageField(
|
|
||||||
blank=True,
|
|
||||||
null=True,
|
|
||||||
storage=takahe.models.upload_store,
|
|
||||||
upload_to=functools.partial(
|
|
||||||
takahe.models.upload_namer,
|
|
||||||
*("attachment_thumbnails",),
|
|
||||||
**{}
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
("remote_url", models.CharField(blank=True, max_length=500, null=True)),
|
|
||||||
("name", models.TextField(blank=True, null=True)),
|
|
||||||
("width", models.IntegerField(blank=True, null=True)),
|
|
||||||
("height", models.IntegerField(blank=True, null=True)),
|
|
||||||
("focal_x", models.FloatField(blank=True, null=True)),
|
|
||||||
("focal_y", models.FloatField(blank=True, null=True)),
|
|
||||||
("blurhash", models.TextField(blank=True, null=True)),
|
|
||||||
("created", models.DateTimeField(auto_now_add=True)),
|
("created", models.DateTimeField(auto_now_add=True)),
|
||||||
("updated", models.DateTimeField(auto_now=True)),
|
("updated", models.DateTimeField(auto_now=True)),
|
||||||
(
|
(
|
||||||
"author",
|
"source",
|
||||||
models.ForeignKey(
|
models.ForeignKey(
|
||||||
blank=True,
|
|
||||||
null=True,
|
|
||||||
on_delete=django.db.models.deletion.CASCADE,
|
on_delete=django.db.models.deletion.CASCADE,
|
||||||
related_name="attachments",
|
related_name="outbound_follows",
|
||||||
to="takahe.identity",
|
to="takahe.identity",
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"post",
|
"target",
|
||||||
|
models.ForeignKey(
|
||||||
|
on_delete=django.db.models.deletion.CASCADE,
|
||||||
|
related_name="inbound_follows",
|
||||||
|
to="takahe.identity",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
"db_table": "users_follow",
|
||||||
|
"unique_together": {("source", "target")},
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name="Config",
|
||||||
|
fields=[
|
||||||
|
(
|
||||||
|
"id",
|
||||||
|
models.BigAutoField(
|
||||||
|
auto_created=True,
|
||||||
|
primary_key=True,
|
||||||
|
serialize=False,
|
||||||
|
verbose_name="ID",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
("key", models.CharField(max_length=500)),
|
||||||
|
("json", models.JSONField(blank=True, null=True)),
|
||||||
|
("image", models.ImageField(blank=True, null=True, upload_to="")),
|
||||||
|
(
|
||||||
|
"domain",
|
||||||
models.ForeignKey(
|
models.ForeignKey(
|
||||||
blank=True,
|
blank=True,
|
||||||
null=True,
|
null=True,
|
||||||
on_delete=django.db.models.deletion.CASCADE,
|
on_delete=django.db.models.deletion.CASCADE,
|
||||||
related_name="attachments",
|
related_name="configs",
|
||||||
to="takahe.post",
|
to="takahe.domain",
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
options={
|
|
||||||
"db_table": "activities_postattachment",
|
|
||||||
},
|
|
||||||
),
|
|
||||||
migrations.CreateModel(
|
|
||||||
name="Relay",
|
|
||||||
fields=[
|
|
||||||
(
|
|
||||||
"id",
|
|
||||||
models.BigAutoField(
|
|
||||||
auto_created=True,
|
|
||||||
primary_key=True,
|
|
||||||
serialize=False,
|
|
||||||
verbose_name="ID",
|
|
||||||
),
|
|
||||||
),
|
|
||||||
("inbox_uri", models.CharField(max_length=500, unique=True)),
|
|
||||||
("state", models.CharField(default="new", max_length=100)),
|
|
||||||
("state_changed", models.DateTimeField(auto_now_add=True)),
|
|
||||||
("state_next_attempt", models.DateTimeField(blank=True, null=True)),
|
|
||||||
(
|
|
||||||
"state_locked_until",
|
|
||||||
models.DateTimeField(blank=True, db_index=True, null=True),
|
|
||||||
),
|
|
||||||
("created", models.DateTimeField(auto_now_add=True)),
|
|
||||||
("updated", models.DateTimeField(auto_now=True)),
|
|
||||||
],
|
|
||||||
options={
|
|
||||||
"db_table": "users_relay",
|
|
||||||
},
|
|
||||||
),
|
|
||||||
migrations.CreateModel(
|
|
||||||
name="Announcement",
|
|
||||||
fields=[
|
|
||||||
(
|
|
||||||
"id",
|
|
||||||
models.BigAutoField(
|
|
||||||
auto_created=True,
|
|
||||||
primary_key=True,
|
|
||||||
serialize=False,
|
|
||||||
verbose_name="ID",
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"text",
|
"identity",
|
||||||
models.TextField(),
|
models.ForeignKey(
|
||||||
),
|
|
||||||
(
|
|
||||||
"published",
|
|
||||||
models.BooleanField(
|
|
||||||
default=False,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"start",
|
|
||||||
models.DateTimeField(
|
|
||||||
blank=True,
|
blank=True,
|
||||||
null=True,
|
null=True,
|
||||||
|
on_delete=django.db.models.deletion.CASCADE,
|
||||||
|
related_name="configs",
|
||||||
|
to="takahe.identity",
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"end",
|
"user",
|
||||||
models.DateTimeField(
|
models.ForeignKey(
|
||||||
blank=True,
|
blank=True,
|
||||||
null=True,
|
null=True,
|
||||||
|
on_delete=django.db.models.deletion.CASCADE,
|
||||||
|
related_name="configs",
|
||||||
|
to="takahe.user",
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
("include_unauthenticated", models.BooleanField(default=False)),
|
|
||||||
("created", models.DateTimeField(auto_now_add=True)),
|
|
||||||
("updated", models.DateTimeField(auto_now=True)),
|
|
||||||
("seen", models.ManyToManyField(blank=True, to="takahe.user")),
|
|
||||||
],
|
],
|
||||||
options={
|
options={
|
||||||
"db_table": "users_announcement",
|
"db_table": "core_config",
|
||||||
|
"unique_together": {("key", "user", "identity", "domain")},
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
|
@ -919,6 +919,9 @@ class Post(models.Model):
|
||||||
# The main (HTML) content
|
# The main (HTML) content
|
||||||
content = models.TextField()
|
content = models.TextField()
|
||||||
|
|
||||||
|
# The language of the content
|
||||||
|
language = models.CharField(default="", blank=True)
|
||||||
|
|
||||||
type = models.CharField(
|
type = models.CharField(
|
||||||
max_length=20,
|
max_length=20,
|
||||||
choices=Types.choices,
|
choices=Types.choices,
|
||||||
|
|
Loading…
Add table
Reference in a new issue