-
-
Notifications
You must be signed in to change notification settings - Fork 902
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Community post tags (part 2: API methods) #5389
base: main
Are you sure you want to change the base?
Conversation
Ready for review. the API tests pass locally for me, but require merging LemmyNet/lemmy-js-client#483 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's the slug thing about? The tag already has a name and an ap_id.
Do the re-request review when you want me to have another look. I thought about going through it but I'm guessing its still WIP. |
222d18f
to
1b3e8b0
Compare
I've updated the PR
I'll merge main after reviews are green |
Api tests are failing, looks like you need to merge changes from main branch here. |
let tag_name_lower = tag_name.to_lowercase(); | ||
let id_slug = VALID_ID_SLUG.replace_all(&tag_name_lower, "-"); | ||
// limit length to 40 chars | ||
let id_slug: String = id_slug.chars().take(40).collect(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You should limit length of the tag itself when it is created.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I still don't know why id_slug needs to be separate from name. Aren't tags always just simple strings? If that's so, then its the tag name that needs to be validated before inserted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
how would you propose to construct the AP URL then?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
{domain}/tag/{name}, just like community and person.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
name is a human readable and updateable name, with spaces, special characters, etc. not an id.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Still it doesnt need a separate length limit, tag create/edit already has a limit.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
name is a human readable and updateable name, with spaces, special characters, etc. not an id.
Then we should adopt what's done for either person or community, on the tag table.
- Have an unchanging, lowercase
name
column. - Have a
title
/display_name
column, that can have spaces and other funky characters.
b6013a1
to
8d8a2ad
Compare
i've temporarily set the lemmy-js-client lib to point to this pr LemmyNet/lemmy-js-client#483 so that the tests pass. please re-review |
if !(3..=100).contains(&length) { | ||
return Err(LemmyErrorType::InvalidBodyField.into()); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This check should be externalized like all the others, and a specific error made for it. Check site_name_length_check
for an example
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also there is no length check in update.
published: None, // defaults to now | ||
updated: None, | ||
deleted: false, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
..Default::default()
, or better, the insert form shouldn't need these at all, they already have defaults.
Check how PostInsertForm
uses derive_new
to do this.
// Update the tag | ||
let tag_form = TagUpdateForm { | ||
name: Some(data.name.clone()), | ||
updated: Some(Some(chrono::Utc::now())), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would be better to import this, so you can just use Utc::now()
like all the other examples.
delete(post_tag::table.filter(post_tag::post_id.eq(post_id))) | ||
.execute(conn) | ||
.await?; | ||
Ok(()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
have the output of this be Result<usize, diesel::result::Error>
, and delete this Ok(())
line.
.values(forms) | ||
.execute(conn) | ||
.await?; | ||
Ok(()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same, delete this Ok(())
line, and have the output be Result<Vec<Self>, ..
use crate::schema::tag::dsl::*; | ||
let conn = &mut get_conn(pool).await?; | ||
tag | ||
.filter(community_id.eq(search_community_id)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
tag::community_id
) -> Result<Vec<Self>, Error> { | ||
use crate::schema::tag::dsl::*; | ||
let conn = &mut get_conn(pool).await?; | ||
tag |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
tag::table
let conn = &mut get_conn(pool).await?; | ||
tag | ||
.filter(community_id.eq(search_community_id)) | ||
.filter(deleted.eq(false)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
tag::deleted
tag | ||
.filter(community_id.eq(search_community_id)) | ||
.filter(deleted.eq(false)) | ||
.load::<Tag>(conn) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Self
#[cfg(feature = "full")] | ||
#[diesel::dsl::auto_type] | ||
fn tag_fragment() -> _ { | ||
let sel: SqlLiteral<Json> = diesel::dsl::sql::<diesel::sql_types::Json>("json_agg(tag.*)"); | ||
tag::table | ||
.select(sel) | ||
.filter(tag::community_id.eq(community::id)) | ||
.filter(tag::deleted.eq(false)) | ||
.single_value() | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice, thx that's going to make things a lot easier.
}) | ||
.collect(), | ||
) | ||
.await?; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Merge these into a single method PostTag::set()
which deletes old tags and sets new ones in a transaction.
.await?; | ||
} | ||
// validate tags | ||
let valid_tags: std::collections::HashSet<TagId> = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Import Hashset
Ok(Json(tag)) | ||
} | ||
|
||
#[tracing::instrument(skip(context))] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove these macros, see #5368
|
||
// List tags | ||
let listRes = await alpha.getCommunity({ id: communityId }); | ||
expect(listRes.community_view.post_tags.length).toBeGreaterThan(0); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
expect(listRes.community_view.post_tags.length).toBeGreaterThan(0); | |
expect(listRes.community_view.post_tags.length).toBe(1); |
expect( | ||
listRes.community_view.post_tags.find(t => t.id === createRes.id), | ||
).toBeUndefined(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
expect( | |
listRes.community_view.post_tags.find(t => t.id === createRes.id), | |
).toBeUndefined(); | |
expect(listRes.community_view.post_tags.length).toBe(0); |
@phiresky The discussion at the top about table names is not resolved yet. If you have better ideas how to name them thats fine, but right now the names dont make it clear what these tables and structs are for. |
@Nutomic the discussion you linked is about the API path, which is resolved. Tables are not even part of this PR. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes the tables were in #4997 which is part of the same feature. In that PR it wasnt clear yet how it all works, only now is it possible to review properly. So Im repeating my request again:
Yes it all needs to be made more consistent. For the main tags table community_tags makes sense, while the relation tag-post can be represented by a table community_tags_for_post.
Here's that discussion, and I believe that we agreed on leaving a generic So I don't believe any tag table changes (or new tables) are necessary, outside of possibly adding a |
This is the second part of post tags, implementing the API methods.
Database PR (merged): #4997
Original RFC: LemmyNet/rfcs#4