From 7473ea1ae9f34423b761baa94c344e07ad40fd35 Mon Sep 17 00:00:00 2001 From: Vasile Popescu Date: Fri, 6 Sep 2024 14:32:39 +0200 Subject: [PATCH] Migrate and show question co-authors --- front_end/messages/en.json | 1 + .../sidebar/sidebar_question_info.tsx | 25 ++++++++++----- front_end/src/types/post.ts | 1 + migrator/services/migrate_questions.py | 31 +++++++++++++++++++ posts/migrations/0023_post_coauthors.py | 25 +++++++++++++++ posts/migrations/0026_merge_20240906_1234.py | 13 ++++++++ posts/models.py | 3 ++ posts/serializers.py | 5 +++ 8 files changed, 97 insertions(+), 7 deletions(-) create mode 100644 posts/migrations/0023_post_coauthors.py create mode 100644 posts/migrations/0026_merge_20240906_1234.py diff --git a/front_end/messages/en.json b/front_end/messages/en.json index 4ddaa7a4da..4a770cdfe0 100644 --- a/front_end/messages/en.json +++ b/front_end/messages/en.json @@ -376,6 +376,7 @@ "predicted": "Predicted", "notPredicted": "Not Predicted", "author": "Author", + "authorWithCount": "{count, plural, =1 {Author} other {Authors} }", "authored": "Authored", "upvoted": "Upvoted", "moderating": "Moderating", diff --git a/front_end/src/app/(main)/questions/[id]/components/sidebar/sidebar_question_info.tsx b/front_end/src/app/(main)/questions/[id]/components/sidebar/sidebar_question_info.tsx index 3a5329d60a..05e7a8bca3 100644 --- a/front_end/src/app/(main)/questions/[id]/components/sidebar/sidebar_question_info.tsx +++ b/front_end/src/app/(main)/questions/[id]/components/sidebar/sidebar_question_info.tsx @@ -19,14 +19,25 @@ const SidebarQuestionInfo: FC = ({ postData }) => {
- {t("author")}: + {t("authorWithCount", { count: postData.coauthors.length > 0 })}: - - {postData.author_username} - +
+ + {postData.author_username} + + + {postData.coauthors.map((coauthor) => ( + + {coauthor.username} + + ))} +
diff --git a/front_end/src/types/post.ts b/front_end/src/types/post.ts index ee97a1ec3a..5b92e2310e 100644 --- a/front_end/src/types/post.ts +++ b/front_end/src/types/post.ts @@ -121,6 +121,7 @@ export type Post = { vote: PostVote; nr_forecasters: number; author_username: string; + coauthors: { id: number; username: string }[]; author_id: number; question?: QT; conditional?: PostConditional; diff --git a/migrator/services/migrate_questions.py b/migrator/services/migrate_questions.py index a1475eacd7..29c512dcd1 100644 --- a/migrator/services/migrate_questions.py +++ b/migrator/services/migrate_questions.py @@ -163,6 +163,33 @@ def migrate_questions(site_ids: list[int] = None): migrate_questions__composite(site_ids=site_ids) +def add_coauthors_for_post(post: Post): + for obj in paginated_query( + """ + WITH shared_projects AS ( + SELECT project_id + FROM metac_project_questionprojectpermissions + WHERE question_id = %s + AND project_id IN ( + SELECT id + FROM metac_project_project + WHERE type = 'PP' + ) + ) + SELECT upp.user_id AS id, u.username + FROM metac_project_userprojectpermissions upp + JOIN metac_account_user u ON upp.user_id = u.id + WHERE upp.project_id IN (SELECT project_id FROM shared_projects) + AND upp.user_id != (SELECT author_id + FROM metac_question_question + WHERE id = %s); + """, + [post.id, post.id], + ): + user_id = obj["id"] + post.coauthors.add(user_id) + + def migrate_questions__simple(site_ids: list[int] = None): questions = [] posts = [] @@ -208,6 +235,10 @@ def migrate_questions__simple(site_ids: list[int] = None): ) Question.objects.bulk_create(questions) Post.objects.bulk_create(posts) + + for post in posts: + add_coauthors_for_post(post) + print( f"\033[Kmigrating questions/posts: {i}. " f"dur:{str(timezone.now() - start).split('.')[0]} " diff --git a/posts/migrations/0023_post_coauthors.py b/posts/migrations/0023_post_coauthors.py new file mode 100644 index 0000000000..1cf66f62d8 --- /dev/null +++ b/posts/migrations/0023_post_coauthors.py @@ -0,0 +1,25 @@ +# Generated by Django 5.0.8 on 2024-09-05 12:33 + +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ( + "posts", + "0022_remove_postsubscription_postsubscription_unique_type_user_post_and_more", + ), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.AddField( + model_name="post", + name="coauthors", + field=models.ManyToManyField( + blank=True, related_name="coauthored_posts", to=settings.AUTH_USER_MODEL + ), + ), + ] diff --git a/posts/migrations/0026_merge_20240906_1234.py b/posts/migrations/0026_merge_20240906_1234.py new file mode 100644 index 0000000000..6dc5148a93 --- /dev/null +++ b/posts/migrations/0026_merge_20240906_1234.py @@ -0,0 +1,13 @@ +# Generated by Django 5.0.8 on 2024-09-06 12:34 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ("posts", "0023_post_coauthors"), + ("posts", "0025_remove_post_preview_image"), + ] + + operations = [] diff --git a/posts/models.py b/posts/models.py index db75047b2a..eed91b6d52 100644 --- a/posts/models.py +++ b/posts/models.py @@ -339,6 +339,9 @@ class CurationStatus(models.TextChoices): title = models.CharField(max_length=2000) url_title = models.CharField(max_length=2000, default="") author = models.ForeignKey(User, models.CASCADE, related_name="posts") + coauthors = models.ManyToManyField( + User, related_name="coauthored_posts", blank=True + ) curated_last_by = models.ForeignKey( User, diff --git a/posts/serializers.py b/posts/serializers.py index f77067c97a..8d869bfef0 100644 --- a/posts/serializers.py +++ b/posts/serializers.py @@ -37,6 +37,7 @@ class PostSerializer(serializers.ModelSerializer): author_username = serializers.SerializerMethodField() status = serializers.SerializerMethodField() open_time = serializers.SerializerMethodField() + coauthors = serializers.SerializerMethodField() class Meta: model = Post @@ -46,6 +47,7 @@ class Meta: "url_title", "author_id", "author_username", + "coauthors", "projects", "created_at", "published_at", @@ -66,6 +68,9 @@ def get_projects(self, obj: Post): def get_author_username(self, obj: Post): return obj.author.username + def get_coauthors(self, obj: Post): + return [{"id": u.id, "username": u.username} for u in obj.coauthors.all()] + def get_status(self, obj: Post): if obj.resolved: return "resolved"