Skip to content

Remove the tokens table #1090

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 1 commit into from
Oct 10, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions migrations/2017-09-23-182408_move_tokens_to_emails_table/down.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
DROP TRIGGER trigger_emails_reconfirm ON emails;
DROP TRIGGER trigger_emails_set_token_generated_at ON emails;
DROP FUNCTION reconfirm_email_on_email_change();
DROP FUNCTION emails_set_token_generated_at();

CREATE TABLE tokens (
id SERIAL PRIMARY KEY,
email_id INTEGER NOT NULL UNIQUE REFERENCES emails (id),
token TEXT NOT NULL,
created_at TIMESTAMP NOT NULL DEFAULT NOW()
);

INSERT INTO tokens (email_id, token, created_at)
SELECT id, token, token_generated_at FROM emails WHERE token_generated_at IS NOT NULL;

ALTER TABLE emails DROP COLUMN token;
ALTER TABLE emails DROP COLUMN token_generated_at;
30 changes: 30 additions & 0 deletions migrations/2017-09-23-182408_move_tokens_to_emails_table/up.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
ALTER TABLE emails ADD COLUMN token TEXT NOT NULL DEFAULT random_string(26);
ALTER TABLE emails ADD COLUMN token_generated_at TIMESTAMP;
UPDATE emails SET token = tokens.token, token_generated_at = tokens.created_at
FROM tokens WHERE tokens.email_id = emails.id;
DROP TABLE tokens;

CREATE FUNCTION emails_set_token_generated_at() RETURNS trigger AS $$
BEGIN
NEW.token_generated_at := CURRENT_TIMESTAMP;
RETURN NEW;
END
$$ LANGUAGE plpgsql;

CREATE FUNCTION reconfirm_email_on_email_change() RETURNS trigger AS $$
BEGIN
IF NEW.email IS DISTINCT FROM OLD.email THEN
NEW.token := random_string(26);
NEW.verified := false;
END IF;
RETURN NEW;
END
$$ LANGUAGE plpgsql;

CREATE TRIGGER trigger_emails_set_token_generated_at BEFORE
INSERT OR UPDATE OF token ON emails
FOR EACH ROW EXECUTE PROCEDURE emails_set_token_generated_at();

CREATE TRIGGER trigger_emails_reconfirm BEFORE UPDATE
ON emails
FOR EACH ROW EXECUTE PROCEDURE reconfirm_email_on_email_change();
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ALTER TABLE emails DROP CONSTRAINT fk_emails_user_id;
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ALTER TABLE emails ADD CONSTRAINT fk_emails_user_id FOREIGN KEY (user_id) REFERENCES users (id);
64 changes: 22 additions & 42 deletions src/schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -437,6 +437,18 @@ table! {
///
/// (Automatically generated by Diesel.)
verified -> Bool,
/// The `token` column of the `emails` table.
///
/// Its SQL type is `Text`.
///
/// (Automatically generated by Diesel.)
token -> Text,
/// The `token_generated_at` column of the `emails` table.
///
/// Its SQL type is `Nullable<Timestamp>`.
///
/// (Automatically generated by Diesel.)
token_generated_at -> Nullable<Timestamp>,
}
}

Expand Down Expand Up @@ -558,38 +570,6 @@ table! {
}
}

table! {
/// Representation of the `tokens` table.
///
/// (Automatically generated by Diesel.)
tokens (id) {
/// The `id` column of the `tokens` table.
///
/// Its SQL type is `Int4`.
///
/// (Automatically generated by Diesel.)
id -> Int4,
/// The `email_id` column of the `tokens` table.
///
/// Its SQL type is `Int4`.
///
/// (Automatically generated by Diesel.)
email_id -> Int4,
/// The `token` column of the `tokens` table.
///
/// Its SQL type is `Varchar`.
///
/// (Automatically generated by Diesel.)
token -> Varchar,
/// The `created_at` column of the `tokens` table.
///
/// Its SQL type is `Timestamp`.
///
/// (Automatically generated by Diesel.)
created_at -> Timestamp,
}
}

table! {
/// Representation of the `users` table.
///
Expand Down Expand Up @@ -784,22 +764,22 @@ table! {
}
}

joinable!(follows -> users (user_id));
joinable!(version_authors -> users (user_id));
joinable!(crates_keywords -> keywords (keyword_id));
joinable!(crates_categories -> categories (category_id));
joinable!(api_tokens -> users (user_id));
joinable!(crate_downloads -> crates (crate_id));
joinable!(crate_owner_invitations -> crates (crate_id));
joinable!(crate_owners -> crates (crate_id));
joinable!(crate_owners -> teams (owner_id));
joinable!(crate_owners -> users (owner_id));
joinable!(crates_categories -> categories (category_id));
joinable!(crates_categories -> crates (crate_id));
joinable!(crates_keywords -> crates (crate_id));
joinable!(crates_keywords -> keywords (keyword_id));
joinable!(dependencies -> crates (crate_id));
joinable!(follows -> crates (crate_id));
joinable!(versions -> crates (crate_id));
joinable!(dependencies -> versions (version_id));
joinable!(emails -> users (user_id));
joinable!(follows -> crates (crate_id));
joinable!(follows -> users (user_id));
joinable!(version_authors -> users (user_id));
joinable!(version_authors -> versions (version_id));
joinable!(version_downloads -> versions (version_id));
joinable!(crate_owners -> teams (owner_id));
joinable!(crate_owners -> users (owner_id));
joinable!(crate_owner_invitations -> crates (crate_id));
joinable!(tokens -> emails (email_id));
joinable!(versions -> crates (crate_id));
54 changes: 21 additions & 33 deletions src/tests/user.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@ use conduit::{Handler, Method};

use cargo_registry::token::ApiToken;
use cargo_registry::krate::EncodableCrate;
use cargo_registry::user::{Email, EncodablePrivateUser, EncodablePublicUser, NewEmail, NewUser,
Token, User};
use cargo_registry::user::{Email, EncodablePrivateUser, EncodablePublicUser, NewUser, User};
use cargo_registry::version::EncodableVersion;

use diesel::prelude::*;
Expand Down Expand Up @@ -658,7 +657,7 @@ fn test_insert_into_email_table_with_email_change() {
*/
#[test]
fn test_confirm_user_email() {
use cargo_registry::schema::{emails, tokens};
use cargo_registry::schema::emails;

#[derive(Deserialize)]
struct R {
Expand All @@ -675,7 +674,7 @@ fn test_confirm_user_email() {
let user = {
let conn = app.diesel_database.get().unwrap();
let user = NewUser {
email: Some("potato@example.com"),
email: Some("potato2@example.com"),
..::new_user("potato")
};

Expand All @@ -686,15 +685,10 @@ fn test_confirm_user_email() {

let email_token = {
let conn = app.diesel_database.get().unwrap();
let email_info = emails::table
.filter(emails::user_id.eq(user.id))
.first::<Email>(&*conn)
.unwrap();
let token_info = tokens::table
.filter(tokens::email_id.eq(email_info.id))
.first::<Token>(&*conn)
.unwrap();
token_info.token
Email::belonging_to(&user)
.select(emails::token)
.first::<String>(&*conn)
.unwrap()
};

let mut response = ok_resp!(
Expand All @@ -707,7 +701,7 @@ fn test_confirm_user_email() {

let mut response = ok_resp!(middle.call(req.with_path("/api/v1/me").with_method(Method::Get),));
let r = ::json::<R>(&mut response);
assert_eq!(r.user.email.unwrap(), "potato@example.com");
assert_eq!(r.user.email.unwrap(), "potato2@example.com");
assert_eq!(r.user.login, "potato");
assert!(r.user.email_verified);
assert!(r.user.email_verification_sent);
Expand All @@ -719,8 +713,9 @@ fn test_confirm_user_email() {
*/
#[test]
fn test_existing_user_email() {
use cargo_registry::schema::{emails, users};
use diesel::insert;
use cargo_registry::schema::emails;
use chrono::NaiveDateTime;
use diesel::update;

#[derive(Deserialize)]
struct R {
Expand All @@ -731,24 +726,17 @@ fn test_existing_user_email() {
let mut req = ::req(app.clone(), Method::Get, "/me");
{
let conn = app.diesel_database.get().unwrap();
let user = ::new_user("potahto");

// Deliberately not using User::create_or_update since that
// will try to send a verification email; we want to simulate
// a user who already had an email before we added verification.
let user = insert(&user)
.into(users::table)
.get_result::<User>(&*conn)
.unwrap();

let email = NewEmail {
user_id: user.id,
email: "[email protected]",
verified: false,
let new_user = NewUser {
email: Some("[email protected]"),
..::new_user("potahto")
};

insert(&email).into(emails::table).execute(&*conn).unwrap();

let user = new_user.create_or_update(&conn).unwrap();
update(Email::belonging_to(&user))
// Users created before we added verification will have
// `NULL` in the `token_generated_at` column.
.set(emails::token_generated_at.eq(None::<NaiveDateTime>))
.execute(&*conn)
.unwrap();
::sign_in_as(&mut req, &user);
}

Expand Down
Loading