Skip to content

Commit f5a61f7

Browse files
Feat/profile v3 (#67)
* feat(profile): profile posts tabs endpoints * fix(profile): fix update user response * fix(profile): return user birthdate in profile response * fix(profile): clean unused files after update profile * refactor(profile): convert sql posts query to typeorm * feat(profile): add user data to user posts view * fix(profile): remove reply from user posts + fix repost type * feat(profile): add quote parent data in user posts --------- Co-authored-by: Amira Khalid <149877108+AmiraKhalid04@users.noreply.github.com>
1 parent b1a90f3 commit f5a61f7

15 files changed

+664
-139
lines changed
Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
import { MigrationInterface, QueryRunner } from 'typeorm';
2+
3+
export class AddUserToTweetsView1763506160264 implements MigrationInterface {
4+
name = 'AddUserToTweetsView1763506160264';
5+
6+
public async up(query_runner: QueryRunner): Promise<void> {
7+
await query_runner.query(
8+
`DELETE FROM "typeorm_metadata" WHERE "type" = $1 AND "name" = $2 AND "schema" = $3`,
9+
['VIEW', 'user_posts_view', 'public']
10+
);
11+
await query_runner.query(`DROP VIEW "user_posts_view"`);
12+
await query_runner.query(`CREATE VIEW "user_posts_view" AS
13+
SELECT
14+
t.tweet_id::text AS id,
15+
t.user_id AS profile_user_id,
16+
t.user_id AS tweet_author_id,
17+
t.tweet_id,
18+
NULL::uuid AS repost_id,
19+
'tweet' AS post_type,
20+
t.created_at AS post_date,
21+
t.type::text AS type,
22+
t.content,
23+
t.images,
24+
t.videos,
25+
t.num_likes,
26+
t.num_reposts,
27+
t.num_views,
28+
t.num_quotes,
29+
t.num_replies,
30+
t.created_at,
31+
t.updated_at,
32+
u.username,
33+
u.name,
34+
u.followers,
35+
u.following,
36+
u.avatar_url,
37+
u.cover_url,
38+
u.verified,
39+
u.bio
40+
FROM tweets t
41+
INNER JOIN "user" u ON t.user_id = u.id
42+
43+
UNION ALL
44+
45+
SELECT
46+
(tr.tweet_id::text || '_' || tr.user_id::text) AS id,
47+
tr.user_id AS profile_user_id,
48+
t.user_id AS tweet_author_id,
49+
tr.tweet_id,
50+
tr.tweet_id AS repost_id,
51+
'repost' AS post_type,
52+
tr.created_at AS post_date,
53+
t.type::text AS type,
54+
t.content,
55+
t.images,
56+
t.videos,
57+
t.num_likes,
58+
t.num_reposts,
59+
t.num_views,
60+
t.num_quotes,
61+
t.num_replies,
62+
t.created_at,
63+
t.updated_at,
64+
u.username,
65+
u.name,
66+
u.followers,
67+
u.following,
68+
u.avatar_url,
69+
u.cover_url,
70+
u.verified,
71+
u.bio
72+
FROM tweet_reposts tr
73+
INNER JOIN tweets t ON tr.tweet_id = t.tweet_id
74+
INNER JOIN "user" u ON t.user_id = u.id
75+
`);
76+
await query_runner.query(
77+
`INSERT INTO "typeorm_metadata"("database", "schema", "table", "type", "name", "value") VALUES (DEFAULT, $1, DEFAULT, $2, $3, $4)`,
78+
[
79+
'public',
80+
'VIEW',
81+
'user_posts_view',
82+
"SELECT \n t.tweet_id::text AS id,\n t.user_id AS profile_user_id,\n t.user_id AS tweet_author_id,\n t.tweet_id,\n NULL::uuid AS repost_id,\n 'tweet' AS post_type,\n t.created_at AS post_date,\n t.type::text AS type,\n t.content,\n t.images,\n t.videos,\n t.num_likes,\n t.num_reposts,\n t.num_views,\n t.num_quotes,\n t.num_replies,\n t.created_at,\n t.updated_at,\n u.username,\n u.name,\n u.followers,\n u.following,\n u.avatar_url,\n u.cover_url,\n u.verified,\n u.bio\n FROM tweets t\n INNER JOIN \"user\" u ON t.user_id = u.id\n \n UNION ALL\n \n SELECT \n (tr.tweet_id::text || '_' || tr.user_id::text) AS id,\n tr.user_id AS profile_user_id,\n t.user_id AS tweet_author_id,\n tr.tweet_id,\n tr.tweet_id AS repost_id,\n 'repost' AS post_type,\n tr.created_at AS post_date,\n t.type::text AS type,\n t.content,\n t.images,\n t.videos,\n t.num_likes,\n t.num_reposts,\n t.num_views,\n t.num_quotes,\n t.num_replies,\n t.created_at,\n t.updated_at,\n u.username,\n u.name,\n u.followers,\n u.following,\n u.avatar_url,\n u.cover_url,\n u.verified,\n u.bio\n FROM tweet_reposts tr\n INNER JOIN tweets t ON tr.tweet_id = t.tweet_id\n INNER JOIN \"user\" u ON t.user_id = u.id",
83+
]
84+
);
85+
}
86+
87+
public async down(query_runner: QueryRunner): Promise<void> {
88+
await query_runner.query(
89+
`DELETE FROM "typeorm_metadata" WHERE "type" = $1 AND "name" = $2 AND "schema" = $3`,
90+
['VIEW', 'user_posts_view', 'public']
91+
);
92+
await query_runner.query(`DROP VIEW "user_posts_view"`);
93+
await query_runner.query(`CREATE VIEW "user_posts_view" AS SELECT
94+
t.tweet_id::text AS id,
95+
t.user_id AS profile_user_id,
96+
t.user_id AS tweet_author_id,
97+
t.tweet_id,
98+
NULL::uuid AS repost_id,
99+
'tweet' AS post_type,
100+
t.created_at AS post_date,
101+
t.type::text AS type,
102+
t.content,
103+
t.images,
104+
t.videos,
105+
t.num_likes,
106+
t.num_reposts,
107+
t.num_views,
108+
t.num_quotes,
109+
t.num_replies,
110+
t.created_at,
111+
t.updated_at
112+
FROM tweets t
113+
114+
UNION ALL
115+
116+
SELECT
117+
(tr.tweet_id::text || '_' || tr.user_id::text) AS id,
118+
tr.user_id AS profile_user_id,
119+
t.user_id AS tweet_author_id,
120+
tr.tweet_id,
121+
tr.tweet_id AS repost_id,
122+
'repost' AS post_type,
123+
tr.created_at AS post_date,
124+
t.type::text AS type,
125+
t.content,
126+
t.images,
127+
t.videos,
128+
t.num_likes,
129+
t.num_reposts,
130+
t.num_views,
131+
t.num_quotes,
132+
t.num_replies,
133+
t.created_at,
134+
t.updated_at
135+
FROM tweet_reposts tr
136+
INNER JOIN tweets t ON tr.tweet_id = t.tweet_id`);
137+
await query_runner.query(
138+
`INSERT INTO "typeorm_metadata"("database", "schema", "table", "type", "name", "value") VALUES (DEFAULT, $1, DEFAULT, $2, $3, $4)`,
139+
[
140+
'public',
141+
'VIEW',
142+
'user_posts_view',
143+
"SELECT \n t.tweet_id::text AS id,\n t.user_id AS profile_user_id,\n t.user_id AS tweet_author_id,\n t.tweet_id,\n NULL::uuid AS repost_id,\n 'tweet' AS post_type,\n t.created_at AS post_date,\n t.type::text AS type,\n t.content,\n t.images,\n t.videos,\n t.num_likes,\n t.num_reposts,\n t.num_views,\n t.num_quotes,\n t.num_replies,\n t.created_at,\n t.updated_at\n FROM tweets t\n \n UNION ALL\n \n SELECT \n (tr.tweet_id::text || '_' || tr.user_id::text) AS id,\n tr.user_id AS profile_user_id,\n t.user_id AS tweet_author_id,\n tr.tweet_id,\n tr.tweet_id AS repost_id,\n 'repost' AS post_type,\n tr.created_at AS post_date,\n t.type::text AS type,\n t.content,\n t.images,\n t.videos,\n t.num_likes,\n t.num_reposts,\n t.num_views,\n t.num_quotes,\n t.num_replies,\n t.created_at,\n t.updated_at\n FROM tweet_reposts tr\n INNER JOIN tweets t ON tr.tweet_id = t.tweet_id",
144+
]
145+
);
146+
}
147+
}
Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
import { MigrationInterface, QueryRunner } from 'typeorm';
2+
3+
export class FixRepostTypeInPostsView1763557066040 implements MigrationInterface {
4+
name = 'FixRepostTypeInPostsView1763557066040';
5+
6+
public async up(query_runner: QueryRunner): Promise<void> {
7+
await query_runner.query(
8+
`DELETE FROM "typeorm_metadata" WHERE "type" = $1 AND "name" = $2 AND "schema" = $3`,
9+
['VIEW', 'user_posts_view', 'public']
10+
);
11+
await query_runner.query(`DROP VIEW "user_posts_view"`);
12+
await query_runner.query(`CREATE VIEW "user_posts_view" AS
13+
SELECT
14+
t.tweet_id::text AS id,
15+
t.user_id AS profile_user_id,
16+
t.user_id AS tweet_author_id,
17+
t.tweet_id,
18+
NULL::uuid AS repost_id,
19+
'tweet' AS post_type,
20+
t.created_at AS post_date,
21+
t.type::text AS type,
22+
t.content,
23+
t.images,
24+
t.videos,
25+
t.num_likes,
26+
t.num_reposts,
27+
t.num_views,
28+
t.num_quotes,
29+
t.num_replies,
30+
t.created_at,
31+
t.updated_at,
32+
u.username,
33+
u.name,
34+
u.followers,
35+
u.following,
36+
u.avatar_url,
37+
u.cover_url,
38+
u.verified,
39+
u.bio
40+
FROM tweets t
41+
INNER JOIN "user" u ON t.user_id = u.id
42+
43+
UNION ALL
44+
45+
SELECT
46+
(tr.tweet_id::text || '_' || tr.user_id::text) AS id,
47+
tr.user_id AS profile_user_id,
48+
t.user_id AS tweet_author_id,
49+
tr.tweet_id,
50+
tr.tweet_id AS repost_id,
51+
t.type::text AS post_type,
52+
tr.created_at AS post_date,
53+
'repost' AS type,
54+
t.content,
55+
t.images,
56+
t.videos,
57+
t.num_likes,
58+
t.num_reposts,
59+
t.num_views,
60+
t.num_quotes,
61+
t.num_replies,
62+
t.created_at,
63+
t.updated_at,
64+
u.username,
65+
u.name,
66+
u.followers,
67+
u.following,
68+
u.avatar_url,
69+
u.cover_url,
70+
u.verified,
71+
u.bio
72+
FROM tweet_reposts tr
73+
INNER JOIN tweets t ON tr.tweet_id = t.tweet_id
74+
INNER JOIN "user" u ON t.user_id = u.id
75+
`);
76+
await query_runner.query(
77+
`INSERT INTO "typeorm_metadata"("database", "schema", "table", "type", "name", "value") VALUES (DEFAULT, $1, DEFAULT, $2, $3, $4)`,
78+
[
79+
'public',
80+
'VIEW',
81+
'user_posts_view',
82+
"SELECT \n t.tweet_id::text AS id,\n t.user_id AS profile_user_id,\n t.user_id AS tweet_author_id,\n t.tweet_id,\n NULL::uuid AS repost_id,\n 'tweet' AS post_type,\n t.created_at AS post_date,\n t.type::text AS type,\n t.content,\n t.images,\n t.videos,\n t.num_likes,\n t.num_reposts,\n t.num_views,\n t.num_quotes,\n t.num_replies,\n t.created_at,\n t.updated_at,\n u.username,\n u.name,\n u.followers,\n u.following,\n u.avatar_url,\n u.cover_url,\n u.verified,\n u.bio\n FROM tweets t\n INNER JOIN \"user\" u ON t.user_id = u.id\n \n UNION ALL\n \n SELECT \n (tr.tweet_id::text || '_' || tr.user_id::text) AS id,\n tr.user_id AS profile_user_id,\n t.user_id AS tweet_author_id,\n tr.tweet_id,\n tr.tweet_id AS repost_id,\n t.type::text AS post_type,\n tr.created_at AS post_date,\n 'repost' AS type,\n t.content,\n t.images,\n t.videos,\n t.num_likes,\n t.num_reposts,\n t.num_views,\n t.num_quotes,\n t.num_replies,\n t.created_at,\n t.updated_at,\n u.username,\n u.name,\n u.followers,\n u.following,\n u.avatar_url,\n u.cover_url,\n u.verified,\n u.bio\n FROM tweet_reposts tr\n INNER JOIN tweets t ON tr.tweet_id = t.tweet_id\n INNER JOIN \"user\" u ON t.user_id = u.id",
83+
]
84+
);
85+
}
86+
87+
public async down(query_runner: QueryRunner): Promise<void> {
88+
await query_runner.query(
89+
`DELETE FROM "typeorm_metadata" WHERE "type" = $1 AND "name" = $2 AND "schema" = $3`,
90+
['VIEW', 'user_posts_view', 'public']
91+
);
92+
await query_runner.query(`DROP VIEW "user_posts_view"`);
93+
await query_runner.query(`CREATE VIEW "user_posts_view" AS SELECT
94+
t.tweet_id::text AS id,
95+
t.user_id AS profile_user_id,
96+
t.user_id AS tweet_author_id,
97+
t.tweet_id,
98+
NULL::uuid AS repost_id,
99+
'tweet' AS post_type,
100+
t.created_at AS post_date,
101+
t.type::text AS type,
102+
t.content,
103+
t.images,
104+
t.videos,
105+
t.num_likes,
106+
t.num_reposts,
107+
t.num_views,
108+
t.num_quotes,
109+
t.num_replies,
110+
t.created_at,
111+
t.updated_at,
112+
u.username,
113+
u.name,
114+
u.followers,
115+
u.following,
116+
u.avatar_url,
117+
u.cover_url,
118+
u.verified,
119+
u.bio
120+
FROM tweets t
121+
INNER JOIN "user" u ON t.user_id = u.id
122+
123+
UNION ALL
124+
125+
SELECT
126+
(tr.tweet_id::text || '_' || tr.user_id::text) AS id,
127+
tr.user_id AS profile_user_id,
128+
t.user_id AS tweet_author_id,
129+
tr.tweet_id,
130+
tr.tweet_id AS repost_id,
131+
'repost' AS post_type,
132+
tr.created_at AS post_date,
133+
t.type::text AS type,
134+
t.content,
135+
t.images,
136+
t.videos,
137+
t.num_likes,
138+
t.num_reposts,
139+
t.num_views,
140+
t.num_quotes,
141+
t.num_replies,
142+
t.created_at,
143+
t.updated_at,
144+
u.username,
145+
u.name,
146+
u.followers,
147+
u.following,
148+
u.avatar_url,
149+
u.cover_url,
150+
u.verified,
151+
u.bio
152+
FROM tweet_reposts tr
153+
INNER JOIN tweets t ON tr.tweet_id = t.tweet_id
154+
INNER JOIN "user" u ON t.user_id = u.id`);
155+
await query_runner.query(
156+
`INSERT INTO "typeorm_metadata"("database", "schema", "table", "type", "name", "value") VALUES (DEFAULT, $1, DEFAULT, $2, $3, $4)`,
157+
[
158+
'public',
159+
'VIEW',
160+
'user_posts_view',
161+
"SELECT \n t.tweet_id::text AS id,\n t.user_id AS profile_user_id,\n t.user_id AS tweet_author_id,\n t.tweet_id,\n NULL::uuid AS repost_id,\n 'tweet' AS post_type,\n t.created_at AS post_date,\n t.type::text AS type,\n t.content,\n t.images,\n t.videos,\n t.num_likes,\n t.num_reposts,\n t.num_views,\n t.num_quotes,\n t.num_replies,\n t.created_at,\n t.updated_at,\n u.username,\n u.name,\n u.followers,\n u.following,\n u.avatar_url,\n u.cover_url,\n u.verified,\n u.bio\n FROM tweets t\n INNER JOIN \"user\" u ON t.user_id = u.id\n \n UNION ALL\n \n SELECT \n (tr.tweet_id::text || '_' || tr.user_id::text) AS id,\n tr.user_id AS profile_user_id,\n t.user_id AS tweet_author_id,\n tr.tweet_id,\n tr.tweet_id AS repost_id,\n 'repost' AS post_type,\n tr.created_at AS post_date,\n t.type::text AS type,\n t.content,\n t.images,\n t.videos,\n t.num_likes,\n t.num_reposts,\n t.num_views,\n t.num_quotes,\n t.num_replies,\n t.created_at,\n t.updated_at,\n u.username,\n u.name,\n u.followers,\n u.following,\n u.avatar_url,\n u.cover_url,\n u.verified,\n u.bio\n FROM tweet_reposts tr\n INNER JOIN tweets t ON tr.tweet_id = t.tweet_id\n INNER JOIN \"user\" u ON t.user_id = u.id",
162+
]
163+
);
164+
}
165+
}

src/timeline/timeline.module.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,10 @@ import { TweetsRepository } from 'src/tweets/tweets.repository';
55
import { TypeOrmModule } from '@nestjs/typeorm';
66
import { Tweet, TweetLike, TweetRepost } from 'src/tweets/entities';
77
import { PaginationService } from 'src/shared/services/pagination/pagination.service';
8+
import { UserPostsView } from 'src/tweets/entities/user-posts-view.entity';
89

910
@Module({
10-
imports: [TypeOrmModule.forFeature([Tweet, TweetLike, TweetRepost])],
11+
imports: [TypeOrmModule.forFeature([Tweet, TweetLike, TweetRepost, UserPostsView])],
1112
controllers: [TimelineController],
1213
providers: [TimelineService, TweetsRepository, PaginationService],
1314
})

src/tweets/dto/tweet-response.dto.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -126,15 +126,15 @@ export class TweetResponseDTO {
126126
bookmarks_count: number;
127127

128128
@Expose()
129-
@Transform(({ obj }) => !!obj.current_user_like)
129+
@Transform(({ obj }) => !!obj.current_user_like || obj.is_liked)
130130
@ApiProperty({
131131
description: 'Whether the current user has liked this tweet',
132132
example: true,
133133
})
134134
is_liked: boolean;
135135

136136
@Expose()
137-
@Transform(({ obj }) => !!obj.current_user_repost)
137+
@Transform(({ obj }) => !!obj.current_user_repost || obj.is_reposted)
138138
@ApiProperty({
139139
description: 'Whether the current user has reposted this tweet',
140140
example: false,

0 commit comments

Comments
 (0)