forked from rust-lang/crates.io
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathuser.rs
More file actions
132 lines (118 loc) · 3.84 KB
/
Copy pathuser.rs
File metadata and controls
132 lines (118 loc) · 3.84 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
use crate::github::next_gh_id;
use chrono::Utc;
use crates_io_database::models::{NewUser, User};
use crates_io_database::schema::oauth_github;
use crates_io_encryption::TokenEncryption;
use diesel::prelude::*;
use diesel::upsert::excluded;
use diesel_async::{AsyncPgConnection, RunQueryDsl};
use std::sync::LazyLock;
static ENCRYPTED_TOKEN: LazyLock<Vec<u8>> = LazyLock::new(|| {
TokenEncryption::for_testing()
.encrypt("some random token")
.unwrap()
});
/// A builder to create user instances for the purpose of not using the database or inserting
/// directly into the database.
///
/// If you want to test logic that happens as part of signing up or logging in,
pub struct UserBuilder<'a> {
username: &'a str,
display_name: Option<&'a str>,
}
impl<'a> UserBuilder<'a> {
/// Create a new instance of the builder. To get a `User`, call `build` (creates an instance in
/// memory only) or `insert` (creates a record in the database).
pub fn new() -> Self {
Self {
username: "octocat",
display_name: None,
}
}
pub fn with_username(self, username: &'a str) -> Self {
Self { username, ..self }
}
pub fn with_display_name(self, display_name: &'a str) -> Self {
Self {
display_name: Some(display_name),
..self
}
}
pub fn build(self) -> User {
User {
id: 1,
gh_login: self.username.into(),
name: self.display_name.map(ToString::to_string),
gh_id: 123,
gh_avatar: None,
gh_encrypted_token: vec![],
account_lock_reason: None,
account_lock_until: None,
is_admin: false,
publish_notifications: true,
username: self.username.into(),
created_at: None,
}
}
pub fn new_user(self) -> NewUser<'a> {
NewUser::builder()
.gh_id(next_gh_id())
.gh_login(self.username)
.username(self.username)
.maybe_name(self.display_name)
.gh_encrypted_token(&ENCRYPTED_TOKEN)
.build()
}
}
impl Default for UserBuilder<'_> {
fn default() -> Self {
Self::new()
}
}
/// A builder to create linked GitHub accounts for a user without having to use `GitHubUser`.
pub struct OauthGithubBuilder<'a> {
user_id: i32,
account_id: i64,
encrypted_token: &'a [u8],
login: &'a str,
avatar: Option<&'a str>,
}
impl<'a> OauthGithubBuilder<'a> {
pub fn for_user(user: &'a User) -> Self {
Self {
user_id: user.id,
account_id: user.gh_id as i64,
encrypted_token: &user.gh_encrypted_token,
login: &user.username,
avatar: None,
}
}
pub fn with_avatar(self, avatar: &'a str) -> Self {
Self {
avatar: Some(avatar),
..self
}
}
pub async fn insert(self, mut conn: &AsyncPgConnection) {
diesel::insert_into(oauth_github::table)
.values((
oauth_github::user_id.eq(self.user_id),
oauth_github::account_id.eq(self.account_id),
oauth_github::encrypted_token.eq(self.encrypted_token),
oauth_github::login.eq(self.login),
oauth_github::avatar.eq(self.avatar),
oauth_github::last_sync.eq(Utc::now()),
))
.on_conflict(oauth_github::account_id)
.do_update()
.set((
oauth_github::encrypted_token.eq(excluded(oauth_github::encrypted_token)),
oauth_github::login.eq(excluded(oauth_github::login)),
oauth_github::avatar.eq(excluded(oauth_github::avatar)),
oauth_github::last_sync.eq(Utc::now()),
))
.execute(&mut conn)
.await
.unwrap();
}
}