Skip to content

Commit e2116b3

Browse files
committed
Add a username field to the users table (deploy 3?)
Right now, this will always have the same value as gh_login on the users table and login on the linked accounts table. All of these values will get updated when we get a new gh_login value. Eventually, we're going to have to decouple the concept of crates.io "username" from the logins of the various account(s), which you may or may not want to update when you update your GitHub or other login, and which may or may not conflict with other users' crates.io usernames. But for now, set up for that future and defer the harder decisions until later by making this field always get the same value as gh_login. This adds a `username` field to the JSON views returned from the API but does not use that field anywhere yet. Question: should team owner JSON also have a field named `username` as done in this commit? it's a little weird for a team to have a username because it's not a user. but it's consistent. something more generic like `name` might also be confusing. something more specific like `crates_io_identifier` is more verbose but less confusable. shrug
1 parent 7ba4532 commit e2116b3

File tree

44 files changed

+190
-40
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+190
-40
lines changed

crates/crates_io_database/src/models/user.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ pub struct User {
2525
pub account_lock_until: Option<DateTime<Utc>>,
2626
pub is_admin: bool,
2727
pub publish_notifications: bool,
28+
pub username: Option<String>,
2829
}
2930

3031
impl User {
@@ -85,6 +86,7 @@ pub struct NewUser<'a> {
8586
pub gh_id: i32,
8687
pub gh_login: &'a str,
8788
pub name: Option<&'a str>,
89+
pub username: Option<&'a str>,
8890
pub gh_avatar: Option<&'a str>,
8991
pub gh_access_token: &'a str,
9092
}
@@ -114,6 +116,7 @@ impl NewUser<'_> {
114116
.do_update()
115117
.set((
116118
users::gh_login.eq(excluded(users::gh_login)),
119+
users::username.eq(excluded(users::username)),
117120
users::name.eq(excluded(users::name)),
118121
users::gh_avatar.eq(excluded(users::gh_avatar)),
119122
users::gh_access_token.eq(excluded(users::gh_access_token)),

crates/crates_io_database/src/schema.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -870,6 +870,12 @@ diesel::table! {
870870
is_admin -> Bool,
871871
/// Whether or not the user wants to receive notifications when a package they own is published
872872
publish_notifications -> Bool,
873+
/// The `username` column of the `users` table.
874+
///
875+
/// Its SQL type is `Nullable<Varchar>`.
876+
///
877+
/// (Automatically generated by Diesel.)
878+
username -> Nullable<Varchar>,
873879
}
874880
}
875881

crates/crates_io_database_dump/src/dump-db.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,7 @@ account_lock_reason = "private"
216216
account_lock_until = "private"
217217
is_admin = "private"
218218
publish_notifications = "private"
219+
username = "public"
219220
[users.column_defaults]
220221
gh_access_token = "''"
221222

crates/crates_io_database_dump/src/snapshots/[email protected]

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ BEGIN ISOLATION LEVEL REPEATABLE READ, READ ONLY;
1313
\copy "metadata" ("total_downloads") TO 'data/metadata.csv' WITH CSV HEADER
1414
\copy "reserved_crate_names" ("name") TO 'data/reserved_crate_names.csv' WITH CSV HEADER
1515
\copy "teams" ("avatar", "github_id", "id", "login", "name", "org_id") TO 'data/teams.csv' WITH CSV HEADER
16-
\copy (SELECT "gh_avatar", "gh_id", "gh_login", "id", "name" FROM "users" WHERE id in ( SELECT owner_id AS user_id FROM crate_owners WHERE NOT deleted AND owner_kind = 0 UNION SELECT published_by as user_id FROM versions )) TO 'data/users.csv' WITH CSV HEADER
16+
\copy (SELECT "gh_avatar", "gh_id", "gh_login", "id", "name", "username" FROM "users" WHERE id in ( SELECT owner_id AS user_id FROM crate_owners WHERE NOT deleted AND owner_kind = 0 UNION SELECT published_by as user_id FROM versions )) TO 'data/users.csv' WITH CSV HEADER
1717

1818
\copy "crates_categories" ("category_id", "crate_id") TO 'data/crates_categories.csv' WITH CSV HEADER
1919
\copy "crates_keywords" ("crate_id", "keyword_id") TO 'data/crates_keywords.csv' WITH CSV HEADER

crates/crates_io_database_dump/src/snapshots/[email protected]

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ BEGIN;
6060
\copy "metadata" ("total_downloads") FROM 'data/metadata.csv' WITH CSV HEADER
6161
\copy "reserved_crate_names" ("name") FROM 'data/reserved_crate_names.csv' WITH CSV HEADER
6262
\copy "teams" ("avatar", "github_id", "id", "login", "name", "org_id") FROM 'data/teams.csv' WITH CSV HEADER
63-
\copy "users" ("gh_avatar", "gh_id", "gh_login", "id", "name") FROM 'data/users.csv' WITH CSV HEADER
63+
\copy "users" ("gh_avatar", "gh_id", "gh_login", "id", "name", "username") FROM 'data/users.csv' WITH CSV HEADER
6464
\copy "crates_categories" ("category_id", "crate_id") FROM 'data/crates_categories.csv' WITH CSV HEADER
6565
\copy "crates_keywords" ("crate_id", "keyword_id") FROM 'data/crates_keywords.csv' WITH CSV HEADER
6666
\copy "crate_owners" ("crate_id", "created_at", "created_by", "owner_id", "owner_kind") FROM 'data/crate_owners.csv' WITH CSV HEADER
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
DROP INDEX IF EXISTS lower_username;
2+
3+
ALTER TABLE users
4+
DROP COLUMN username;
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
ALTER TABLE users
2+
-- The column needs to be nullable for this migration to be fast; can be changed to non-nullable
3+
-- after backfill of all records.
4+
ADD COLUMN username VARCHAR;
5+
6+
CREATE INDEX lower_username ON users (lower(username));

src/controllers/crate_owner_invitation.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ pub async fn list_crate_owner_invitations_for_user(
6363
.iter()
6464
.find(|u| u.id == private.inviter_id)
6565
.ok_or_else(|| internal(format!("missing user {}", private.inviter_id)))?
66-
.login
66+
.username
6767
.clone(),
6868
invitee_id: private.invitee_id,
6969
inviter_id: private.inviter_id,

src/controllers/session.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,7 @@ pub async fn save_user_to_database(
132132
let new_user = NewUser::builder()
133133
.gh_id(user.id)
134134
.gh_login(&user.login)
135+
.username(&user.login)
135136
.maybe_name(user.name.as_deref())
136137
.maybe_gh_avatar(user.avatar_url.as_deref())
137138
.gh_access_token(access_token)

src/index.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,7 @@ mod tests {
153153
let user_id = diesel::insert_into(users::table)
154154
.values((
155155
users::name.eq("user1"),
156+
users::username.eq("user1"),
156157
users::gh_login.eq("user1"),
157158
users::gh_id.eq(42),
158159
users::gh_access_token.eq("some random token"),

src/rate_limiter.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -706,6 +706,7 @@ mod tests {
706706
NewUser::builder()
707707
.gh_id(0)
708708
.gh_login(gh_login)
709+
.username(gh_login)
709710
.gh_access_token("some random token")
710711
.build()
711712
.insert(conn)

src/snapshots/crates_io__openapi__tests__openapi_snapshot.snap

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
---
22
source: src/openapi.rs
33
expression: response.json()
4+
snapshot_kind: text
45
---
56
{
67
"components": {
@@ -117,7 +118,7 @@ expression: response.json()
117118
"type": "boolean"
118119
},
119120
"login": {
120-
"description": "The user's login name.",
121+
"description": "The user's GitHub login.",
121122
"example": "ghost",
122123
"type": "string"
123124
},
@@ -141,11 +142,17 @@ expression: response.json()
141142
"string",
142143
"null"
143144
]
145+
},
146+
"username": {
147+
"description": "The user's crates.io username.",
148+
"example": "ghost",
149+
"type": "string"
144150
}
145151
},
146152
"required": [
147153
"id",
148154
"login",
155+
"username",
149156
"email_verified",
150157
"email_verification_sent",
151158
"is_admin",
@@ -707,7 +714,7 @@ expression: response.json()
707714
"type": "string"
708715
},
709716
"login": {
710-
"description": "The login name of the team or user.",
717+
"description": "The GitHub login of the team or user.",
711718
"example": "ghost",
712719
"type": "string"
713720
},
@@ -726,11 +733,17 @@ expression: response.json()
726733
"string",
727734
"null"
728735
]
736+
},
737+
"username": {
738+
"description": "The crates.io username of the team or user.",
739+
"example": "ghost",
740+
"type": "string"
729741
}
730742
},
731743
"required": [
732744
"id",
733745
"login",
746+
"username",
734747
"kind"
735748
],
736749
"type": "object"
@@ -853,7 +866,7 @@ expression: response.json()
853866
"type": "integer"
854867
},
855868
"login": {
856-
"description": "The user's login name.",
869+
"description": "The user's GitHub login name.",
857870
"example": "ghost",
858871
"type": "string"
859872
},
@@ -869,11 +882,17 @@ expression: response.json()
869882
"description": "The user's GitHub profile URL.",
870883
"example": "https://github.com/ghost",
871884
"type": "string"
885+
},
886+
"username": {
887+
"description": "The user's crates.io username.",
888+
"example": "ghost",
889+
"type": "string"
872890
}
873891
},
874892
"required": [
875893
"id",
876894
"login",
895+
"username",
877896
"url"
878897
],
879898
"type": "object"

src/tests/krate/publish/snapshots/crates_io__tests__krate__publish__edition__edition_is_saved-2.snap

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
---
22
source: src/tests/krate/publish/edition.rs
33
expression: response.json()
4+
snapshot_kind: text
45
---
56
{
67
"version": {
@@ -13,7 +14,8 @@ expression: response.json()
1314
"id": "[id]",
1415
"login": "foo",
1516
"name": null,
16-
"url": "https://github.com/foo"
17+
"url": "https://github.com/foo",
18+
"username": "foo"
1719
}
1820
}
1921
],
@@ -44,7 +46,8 @@ expression: response.json()
4446
"id": "[id]",
4547
"login": "foo",
4648
"name": null,
47-
"url": "https://github.com/foo"
49+
"url": "https://github.com/foo",
50+
"username": "foo"
4851
},
4952
"readme_path": "/api/v1/crates/foo/1.0.0/readme",
5053
"repository": null,

src/tests/krate/publish/snapshots/crates_io__tests__krate__publish__links__crate_with_links_field-2.snap

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
---
22
source: src/tests/krate/publish/links.rs
33
expression: response.json()
4+
snapshot_kind: text
45
---
56
{
67
"version": {
@@ -13,7 +14,8 @@ expression: response.json()
1314
"id": 1,
1415
"login": "foo",
1516
"name": null,
16-
"url": "https://github.com/foo"
17+
"url": "https://github.com/foo",
18+
"username": "foo"
1719
}
1820
}
1921
],
@@ -44,7 +46,8 @@ expression: response.json()
4446
"id": "[id]",
4547
"login": "foo",
4648
"name": null,
47-
"url": "https://github.com/foo"
49+
"url": "https://github.com/foo",
50+
"username": "foo"
4851
},
4952
"readme_path": "/api/v1/crates/foo/1.0.0/readme",
5053
"repository": null,

src/tests/krate/publish/snapshots/crates_io__tests__krate__publish__manifest__boolean_readme-2.snap

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
---
22
source: src/tests/krate/publish/manifest.rs
33
expression: response.json()
4+
snapshot_kind: text
45
---
56
{
67
"version": {
@@ -13,7 +14,8 @@ expression: response.json()
1314
"id": "[id]",
1415
"login": "foo",
1516
"name": null,
16-
"url": "https://github.com/foo"
17+
"url": "https://github.com/foo",
18+
"username": "foo"
1719
}
1820
}
1921
],
@@ -44,7 +46,8 @@ expression: response.json()
4446
"id": "[id]",
4547
"login": "foo",
4648
"name": null,
47-
"url": "https://github.com/foo"
49+
"url": "https://github.com/foo",
50+
"username": "foo"
4851
},
4952
"readme_path": "/api/v1/crates/foo/1.0.0/readme",
5053
"repository": null,

src/tests/krate/publish/snapshots/crates_io__tests__krate__publish__manifest__lib_and_bin_crate-2.snap

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
---
22
source: src/tests/krate/publish/manifest.rs
33
expression: response.json()
4+
snapshot_kind: text
45
---
56
{
67
"version": {
@@ -13,7 +14,8 @@ expression: response.json()
1314
"id": "[id]",
1415
"login": "foo",
1516
"name": null,
16-
"url": "https://github.com/foo"
17+
"url": "https://github.com/foo",
18+
"username": "foo"
1719
}
1820
}
1921
],
@@ -47,7 +49,8 @@ expression: response.json()
4749
"id": "[id]",
4850
"login": "foo",
4951
"name": null,
50-
"url": "https://github.com/foo"
52+
"url": "https://github.com/foo",
53+
"username": "foo"
5154
},
5255
"readme_path": "/api/v1/crates/foo/1.0.0/readme",
5356
"repository": null,

src/tests/krate/snapshots/crates_io__tests__krate__yanking__patch_version_yank_unyank-2.snap

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
---
22
source: src/tests/krate/yanking.rs
33
expression: json
4+
snapshot_kind: text
45
---
56
{
67
"version": {
@@ -26,6 +27,7 @@ expression: json
2627
"published_by": {
2728
"id": 1,
2829
"login": "foo",
30+
"username": "foo",
2931
"name": null,
3032
"avatar": null,
3133
"url": "https://github.com/foo"
@@ -36,6 +38,7 @@ expression: json
3638
"user": {
3739
"id": 1,
3840
"login": "foo",
41+
"username": "foo",
3942
"name": null,
4043
"avatar": null,
4144
"url": "https://github.com/foo"
@@ -47,6 +50,7 @@ expression: json
4750
"user": {
4851
"id": 1,
4952
"login": "foo",
53+
"username": "foo",
5054
"name": null,
5155
"avatar": null,
5256
"url": "https://github.com/foo"

src/tests/krate/snapshots/crates_io__tests__krate__yanking__patch_version_yank_unyank-3.snap

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
---
22
source: src/tests/krate/yanking.rs
33
expression: json
4+
snapshot_kind: text
45
---
56
{
67
"version": {
@@ -26,6 +27,7 @@ expression: json
2627
"published_by": {
2728
"id": 1,
2829
"login": "foo",
30+
"username": "foo",
2931
"name": null,
3032
"avatar": null,
3133
"url": "https://github.com/foo"
@@ -36,6 +38,7 @@ expression: json
3638
"user": {
3739
"id": 1,
3840
"login": "foo",
41+
"username": "foo",
3942
"name": null,
4043
"avatar": null,
4144
"url": "https://github.com/foo"
@@ -47,6 +50,7 @@ expression: json
4750
"user": {
4851
"id": 1,
4952
"login": "foo",
53+
"username": "foo",
5054
"name": null,
5155
"avatar": null,
5256
"url": "https://github.com/foo"
@@ -58,6 +62,7 @@ expression: json
5862
"user": {
5963
"id": 1,
6064
"login": "foo",
65+
"username": "foo",
6166
"name": null,
6267
"avatar": null,
6368
"url": "https://github.com/foo"

0 commit comments

Comments
 (0)