Skip to content

Commit ab89c5a

Browse files
committed
Warn when a crate publisher doesn't have a verified email address
See: rust-lang/crates-io-cargo-teams#8
1 parent 4652179 commit ab89c5a

File tree

7 files changed

+306
-1
lines changed

7 files changed

+306
-1
lines changed

src/controllers/krate/publish.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,16 @@ pub fn publish(req: &mut dyn Request) -> CargoResult<Response> {
6464
let categories: Vec<_> = categories.iter().map(|k| &***k).collect();
6565

6666
let conn = req.db_conn()?;
67+
68+
let mut other_warnings = vec![];
69+
if !user.has_verified_email(&conn)? {
70+
other_warnings.push(String::from(
71+
"You do not currently have a verified email address associated with your crates.io \
72+
account. Starting 2019-02-28, a verified email will be required to publish crates. \
73+
Visit https://crates.io/me to set and verify your email address.",
74+
));
75+
}
76+
6777
// Create a transaction on the database, if there are no errors,
6878
// commit the transactions to record a new or updated crate.
6979
conn.transaction(|| {
@@ -199,6 +209,7 @@ pub fn publish(req: &mut dyn Request) -> CargoResult<Response> {
199209
let warnings = PublishWarnings {
200210
invalid_categories: ignored_invalid_categories,
201211
invalid_badges: ignored_invalid_badges,
212+
other: other_warnings,
202213
};
203214

204215
Ok(req.json(&GoodCrate {

src/models/user.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,16 @@ impl User {
154154
Ok(best)
155155
}
156156

157+
pub fn has_verified_email(&self, conn: &PgConnection) -> CargoResult<bool> {
158+
use diesel::dsl::exists;
159+
let email_exists = diesel::select(exists(
160+
emails::table
161+
.filter(emails::user_id.eq(self.id))
162+
.filter(emails::verified.eq(true)),
163+
)).get_result(&*conn)?;
164+
Ok(email_exists)
165+
}
166+
157167
/// Converts this `User` model into an `EncodablePrivateUser` for JSON serialization.
158168
pub fn encodable_private(
159169
self,
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
[
2+
{
3+
"request": {
4+
"uri": "http://alexcrichton-test.s3.amazonaws.com/crates/foo_unverified_email/foo_unverified_email-1.0.0.crate",
5+
"method": "PUT",
6+
"headers": [
7+
[
8+
"accept",
9+
"*/*"
10+
],
11+
[
12+
"content-length",
13+
"35"
14+
],
15+
[
16+
"host",
17+
"alexcrichton-test.s3.amazonaws.com"
18+
],
19+
[
20+
"accept-encoding",
21+
"gzip"
22+
],
23+
[
24+
"user-agent",
25+
"reqwest/0.9.1"
26+
],
27+
[
28+
"content-type",
29+
"application/x-tar"
30+
],
31+
[
32+
"authorization",
33+
"AWS AKIAICL5IWUZYWWKA7JA:uDc39eNdF6CcwB+q+JwKsoDLQc4="
34+
],
35+
[
36+
"date",
37+
"Fri, 15 Sep 2017 07:53:06 -0700"
38+
]
39+
],
40+
"body": "H4sIAAAAAAAA/+3AAQEAAACCIP+vbkhQwKsBLq+17wAEAAA="
41+
},
42+
"response": {
43+
"status": 200,
44+
"headers": [
45+
[
46+
"x-amz-request-id",
47+
"26589A5E52F8395C"
48+
],
49+
[
50+
"ETag",
51+
"\"f9016ad360cebb4fe2e6e96e5949f022\""
52+
],
53+
[
54+
"date",
55+
"Fri, 15 Sep 2017 14:53:07 GMT"
56+
],
57+
[
58+
"content-length",
59+
"0"
60+
],
61+
[
62+
"x-amz-id-2",
63+
"JdIvnNTw53aqXjBIqBLNuN4kxf/w1XWX+xuIiGBDYy7yzOSDuAMtBSrTW4ZWetcCIdqCUHuQ51A="
64+
],
65+
[
66+
"Server",
67+
"AmazonS3"
68+
]
69+
],
70+
"body": ""
71+
}
72+
}
73+
]
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
[
2+
{
3+
"request": {
4+
"uri": "http://alexcrichton-test.s3.amazonaws.com/crates/foo_verified_email/foo_verified_email-1.0.0.crate",
5+
"method": "PUT",
6+
"headers": [
7+
[
8+
"accept",
9+
"*/*"
10+
],
11+
[
12+
"content-length",
13+
"35"
14+
],
15+
[
16+
"host",
17+
"alexcrichton-test.s3.amazonaws.com"
18+
],
19+
[
20+
"accept-encoding",
21+
"gzip"
22+
],
23+
[
24+
"user-agent",
25+
"reqwest/0.9.1"
26+
],
27+
[
28+
"content-type",
29+
"application/x-tar"
30+
],
31+
[
32+
"authorization",
33+
"AWS AKIAICL5IWUZYWWKA7JA:uDc39eNdF6CcwB+q+JwKsoDLQc4="
34+
],
35+
[
36+
"date",
37+
"Fri, 15 Sep 2017 07:53:06 -0700"
38+
]
39+
],
40+
"body": "H4sIAAAAAAAA/+3AAQEAAACCIP+vbkhQwKsBLq+17wAEAAA="
41+
},
42+
"response": {
43+
"status": 200,
44+
"headers": [
45+
[
46+
"x-amz-request-id",
47+
"26589A5E52F8395C"
48+
],
49+
[
50+
"ETag",
51+
"\"f9016ad360cebb4fe2e6e96e5949f022\""
52+
],
53+
[
54+
"date",
55+
"Fri, 15 Sep 2017 14:53:07 GMT"
56+
],
57+
[
58+
"content-length",
59+
"0"
60+
],
61+
[
62+
"x-amz-id-2",
63+
"JdIvnNTw53aqXjBIqBLNuN4kxf/w1XWX+xuIiGBDYy7yzOSDuAMtBSrTW4ZWetcCIdqCUHuQ51A="
64+
],
65+
[
66+
"Server",
67+
"AmazonS3"
68+
]
69+
],
70+
"body": ""
71+
}
72+
}
73+
]
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
[
2+
{
3+
"request": {
4+
"uri": "http://alexcrichton-test.s3.amazonaws.com/crates/foo_no_email/foo_no_email-1.0.0.crate",
5+
"method": "PUT",
6+
"headers": [
7+
[
8+
"accept",
9+
"*/*"
10+
],
11+
[
12+
"content-length",
13+
"35"
14+
],
15+
[
16+
"host",
17+
"alexcrichton-test.s3.amazonaws.com"
18+
],
19+
[
20+
"accept-encoding",
21+
"gzip"
22+
],
23+
[
24+
"user-agent",
25+
"reqwest/0.9.1"
26+
],
27+
[
28+
"content-type",
29+
"application/x-tar"
30+
],
31+
[
32+
"authorization",
33+
"AWS AKIAICL5IWUZYWWKA7JA:uDc39eNdF6CcwB+q+JwKsoDLQc4="
34+
],
35+
[
36+
"date",
37+
"Fri, 15 Sep 2017 07:53:06 -0700"
38+
]
39+
],
40+
"body": "H4sIAAAAAAAA/+3AAQEAAACCIP+vbkhQwKsBLq+17wAEAAA="
41+
},
42+
"response": {
43+
"status": 200,
44+
"headers": [
45+
[
46+
"x-amz-request-id",
47+
"26589A5E52F8395C"
48+
],
49+
[
50+
"ETag",
51+
"\"f9016ad360cebb4fe2e6e96e5949f022\""
52+
],
53+
[
54+
"date",
55+
"Fri, 15 Sep 2017 14:53:07 GMT"
56+
],
57+
[
58+
"content-length",
59+
"0"
60+
],
61+
[
62+
"x-amz-id-2",
63+
"JdIvnNTw53aqXjBIqBLNuN4kxf/w1XWX+xuIiGBDYy7yzOSDuAMtBSrTW4ZWetcCIdqCUHuQ51A="
64+
],
65+
[
66+
"Server",
67+
"AmazonS3"
68+
]
69+
],
70+
"body": ""
71+
}
72+
}
73+
]

src/tests/krate.rs

Lines changed: 65 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ use cargo_registry::models::krate::MAX_NAME_LENGTH;
2222

2323
use builders::{CrateBuilder, DependencyBuilder, PublishBuilder, VersionBuilder};
2424
use models::{Category, Crate};
25-
use schema::{api_tokens, crates, metadata, versions};
25+
use schema::{api_tokens, crates, emails, metadata, versions};
2626
use views::{
2727
EncodableCategory, EncodableCrate, EncodableDependency, EncodableKeyword, EncodableVersion,
2828
EncodableVersionDownload,
@@ -1020,6 +1020,70 @@ fn new_krate_with_readme() {
10201020
assert_eq!(json.krate.max_version, "1.0.0");
10211021
}
10221022

1023+
// This warning will soon become a hard error.
1024+
// See https://github.com/rust-lang/crates-io-cargo-teams/issues/8
1025+
#[test]
1026+
fn new_krate_without_any_email_warns() {
1027+
let (_, _, _, token) = TestApp::with_proxy().with_token();
1028+
1029+
let crate_to_publish = PublishBuilder::new("foo_no_email");
1030+
1031+
let json = token.publish(crate_to_publish).good();
1032+
assert_eq!(json.warnings.other.len(), 1);
1033+
assert_eq!(json.warnings.other[0], "You do not currently have a verified email address \
1034+
associated with your crates.io account. Starting 2019-02-28, a verified email will be required \
1035+
to publish crates. Visit https://crates.io/me to set and verify your email address.");
1036+
}
1037+
1038+
// This warning will soon become a hard error.
1039+
// See https://github.com/rust-lang/crates-io-cargo-teams/issues/8
1040+
#[test]
1041+
fn new_krate_with_unverified_email_warns() {
1042+
let (app, _, user, token) = TestApp::with_proxy().with_token();
1043+
let user = user.as_model();
1044+
1045+
app.db(|conn| {
1046+
insert_into(emails::table)
1047+
.values((
1048+
emails::user_id.eq(user.id),
1049+
emails::email.eq("something@example.com"),
1050+
)).execute(conn)
1051+
.unwrap();
1052+
});
1053+
1054+
let crate_to_publish = PublishBuilder::new("foo_unverified_email");
1055+
1056+
let json = token.publish(crate_to_publish).good();
1057+
assert_eq!(json.warnings.other.len(), 1);
1058+
assert_eq!(json.warnings.other[0], "You do not currently have a verified email address \
1059+
associated with your crates.io account. Starting 2019-02-28, a verified email will be required \
1060+
to publish crates. Visit https://crates.io/me to set and verify your email address.");
1061+
}
1062+
1063+
#[test]
1064+
fn new_krate_with_verified_email_doesnt_warn() {
1065+
let (app, _, user, token) = TestApp::with_proxy().with_token();
1066+
let user = user.as_model();
1067+
1068+
// TODO: Move this to TestApp setup for user so we don't have to do this for every test
1069+
// that publishes a crate; then edit the test for the user without a verified email to
1070+
// remove the verified email
1071+
app.db(|conn| {
1072+
insert_into(emails::table)
1073+
.values((
1074+
emails::user_id.eq(user.id),
1075+
emails::email.eq("something@example.com"),
1076+
emails::verified.eq(true),
1077+
)).execute(conn)
1078+
.unwrap();
1079+
});
1080+
1081+
let crate_to_publish = PublishBuilder::new("foo_verified_email");
1082+
1083+
let json = token.publish(crate_to_publish).good();
1084+
assert_eq!(json.warnings.other.len(), 0);
1085+
}
1086+
10231087
#[test]
10241088
fn summary_doesnt_die() {
10251089
let (_, anon) = TestApp::init().empty();

src/views/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,7 @@ pub struct GoodCrate {
221221
pub struct PublishWarnings {
222222
pub invalid_categories: Vec<String>,
223223
pub invalid_badges: Vec<String>,
224+
pub other: Vec<String>,
224225
}
225226

226227
// TODO: Prefix many of these with `Encodable` then clean up the reexports

0 commit comments

Comments
 (0)