Skip to content

Form support for Email Field #286

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

Merged
merged 18 commits into from
Apr 27, 2025
Merged

Conversation

ElijahAhianyo
Copy link
Contributor

@ElijahAhianyo ElijahAhianyo commented Apr 15, 2025

Add support for form email fields. This wraps over the EmailAddress type in the email_address crate.

Also refactors and deprecates cot::auth::Password which is replaced by cot::form::types::Passsword.

Example usage:

use cot::db::{model, Auto, Model};
use cot::form::types::{Email, Password};
use cot::auth::PasswordHash

[derive(Debug, Form)]
struct SignupForm {
    fullname: String,
    email: Email,
    username: String,
    password1: Password,
    password2: Password,
}

#[derive(Debug, Clone)]
#[model]
struct User {
    #[model(primary_key)]
    id: Auto<i32>,
    name: String,
    username: String,
    email: Email,
    password: PasswordHash,
}

@github-actions github-actions bot added the C-lib Crate: cot (main library crate) label Apr 15, 2025
Copy link

codecov bot commented Apr 15, 2025

Codecov Report

Attention: Patch coverage is 86.15917% with 40 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
cot/src/common_types.rs 79.66% 24 Missing ⚠️
cot/src/form/fields.rs 90.18% 8 Missing and 8 partials ⚠️
Flag Coverage Δ
rust 83.10% <86.15%> (+0.12%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
cot/src/admin.rs 0.00% <ø> (ø)
cot/src/auth.rs 91.73% <100.00%> (+0.56%) ⬆️
cot/src/auth/db.rs 78.12% <ø> (ø)
cot/src/form.rs 77.35% <100.00%> (+10.35%) ⬆️
cot/src/form/fields.rs 78.57% <90.18%> (+4.94%) ⬆️
cot/src/common_types.rs 79.66% <79.66%> (ø)

... and 1 file with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@@ -0,0 +1,351 @@
//! Form Field Types for Cot
Copy link
Contributor Author

@ElijahAhianyo ElijahAhianyo Apr 16, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

still deliberating on whether it's useful to have this file than put everything in fields.rs(open to ideas on this)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it will be useful, but perhaps we could move it directly to crate::types, given it's useful not only in forms, but also in auth. I'm not 100% sold on the name types, though; it's very generic. I'm thinking about something in the lines of value_types or data.

@seqre do you have any additional views on this?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it will be useful, but perhaps we could move it directly to crate::types, given it's useful not only in forms, but also in auth.

I agree, Password and Email (and other similar types) are so common that it makes sense to extract them to their own place, so they can be reused in different situations.

I'm not 100% sold on the name types, though; it's very generic. I'm thinking about something in the lines of value_types or data.

I'm bad at naming as well, but some other ideas that come to my mind: common_types, user_types, or user_data. I'd be against plain data as it's too generic like types.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

common_types sounds good to me, but I also like value_types 🤔

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ended up going with common_types. Anyone with an objection, speak now or forever hold your peace 😅

@ElijahAhianyo ElijahAhianyo marked this pull request as ready for review April 16, 2025 02:01
@ElijahAhianyo ElijahAhianyo changed the title [WIP]Form support for Email Field Form support for Email Field Apr 16, 2025
@ElijahAhianyo
Copy link
Contributor Author

@m4tx I'm definitely doing something wrong, which makes the CI fail, that is not obvious to me. Do you have any pointers on what that may be?

@m4tx
Copy link
Member

m4tx commented Apr 22, 2025

@m4tx I'm definitely doing something wrong, which makes the CI fail, that is not obvious to me. Do you have any pointers on what that may be?

Yes, the #[cfg(feature)] attributes seem to be wrong - see my review comment. The CI is failing on cargo build --features mysql essentially, so you should be able to test this locally, too.

Copy link
Member

@m4tx m4tx left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall looks good, please have a look at the comments and this will be ready to merge soon!

@@ -0,0 +1,351 @@
//! Form Field Types for Cot
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it will be useful, but perhaps we could move it directly to crate::types, given it's useful not only in forms, but also in auth. I'm not 100% sold on the name types, though; it's very generic. I'm thinking about something in the lines of value_types or data.

@seqre do you have any additional views on this?

/// assert_eq!(domain, "example.com");
/// ```
#[must_use]
pub fn as_inner(&self) -> &EmailAddress {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you think it makes sense to remove this as_inner method and instead expose the methods that could be potentially useful for users (like domain(), local_part(), etc.) instead? We generally try not to expose crates we depend on unnecessarily, as it makes it harder to swap these crates for different ones in the future, or even upgrade their versions (because every major version bump of an exposed crate results in a breaking change for us, too).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

EmailAddress does not have many methods, so I'd agree on getting rid of as_inner and just exposing those methods via our interface. An alternative option is to replace it with the implementation of Into<EmailAddress> for it, which might be arguably a bit nicer to get rid of/deprecate in the future.

Copy link
Contributor Author

@ElijahAhianyo ElijahAhianyo Apr 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the suggestion—I think that makes sense. I originally added as_inner() as an escape hatch for anyone needing extra functionality, but exposing the specific methods we actually use on Email sounds great. We’ll just need to update those forwards if we ever swap out the underlying crate, which shouldn’t be too burdensome.

@seqre As for the Into<EmailAddress> escape hatch, on second thought, my main concern is version conflicts: if consumers import EmailAddress directly from the email_address crate, bumping our dependency could suddenly break their builds. Do you think this will be a genuine concern, or do you propose we go with the first approach?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@seqre I ended up going with the first approach, I'm still unsure what the idiomatic approach is, or if the second approach is a genuine concern. If it isn't, let me know and I'll be happy to go in that direction.

/// assert_eq!(domain, "example.com");
/// ```
#[must_use]
pub fn as_inner(&self) -> &EmailAddress {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

EmailAddress does not have many methods, so I'd agree on getting rid of as_inner and just exposing those methods via our interface. An alternative option is to replace it with the implementation of Into<EmailAddress> for it, which might be arguably a bit nicer to get rid of/deprecate in the future.

@@ -0,0 +1,351 @@
//! Form Field Types for Cot
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it will be useful, but perhaps we could move it directly to crate::types, given it's useful not only in forms, but also in auth.

I agree, Password and Email (and other similar types) are so common that it makes sense to extract them to their own place, so they can be reused in different situations.

I'm not 100% sold on the name types, though; it's very generic. I'm thinking about something in the lines of value_types or data.

I'm bad at naming as well, but some other ideas that come to my mind: common_types, user_types, or user_data. I'd be against plain data as it's too generic like types.

Copy link
Member

@m4tx m4tx left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me, thanks for this high-quality contribution!

I'll leave the last word to @seqre in case he has any outstanding comments, but from my side this should be ready to be merged.

Comment on lines +249 to +253
if min > max {
return Err(FormFieldValidationError::from_string(format!(
"min_length ({min}) exceeds max_length ({max})"
)));
}
Copy link
Member

@m4tx m4tx Apr 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, it would probably make sense to have some sort of mechanism to enforce this when constructing the field, rather than when cleaning the value. This is obviously out of scope of this PR, but I'll create an issue to keep this in the roadmap. EDIT: done #294

Copy link
Member

@seqre seqre left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great work, just one last thing and I'll gladly approve!

@ElijahAhianyo ElijahAhianyo requested a review from seqre April 27, 2025 11:19
Copy link
Member

@seqre seqre left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Once again, great work and thank you for your contribution!

@seqre seqre force-pushed the elijah/email-field branch from aea98ff to e24d530 Compare April 27, 2025 11:20
@seqre seqre changed the title Form support for Email Field feat: add form support for Email Field Apr 27, 2025
@seqre seqre enabled auto-merge (squash) April 27, 2025 11:21
@seqre seqre disabled auto-merge April 27, 2025 11:22
@seqre seqre changed the title feat: add form support for Email Field Form support for Email Field Apr 27, 2025
@seqre seqre enabled auto-merge (squash) April 27, 2025 11:28
@seqre seqre merged commit bfbfdad into cot-rs:master Apr 27, 2025
19 checks passed
@cotbot cotbot bot mentioned this pull request Apr 27, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
C-lib Crate: cot (main library crate)
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants