wip after changing email show confirmation page within new website

This commit is contained in:
Nuwan 2025-08-13 13:51:54 +05:30
parent b7a41c6465
commit 67fd15c75c
11 changed files with 147 additions and 41 deletions

View File

@ -0,0 +1,24 @@
/// <reference types="cypress" />
import makeFakeUser from '../../factories/user';
describe('Change Email Confirm Page', () => {
beforeEach(() => {
// Log in to the application or navigate to the account page
// where the change email feature is available
const currentUser = makeFakeUser({
email: 'sam@example.com'
});
cy.stubAuthenticate({ ...currentUser });
});
it('should display the confirm page when visiting the confirm URL', () => {
// Replace with a realistic token for your app if needed
const token = 'dummy-confirm-token';
// Visit the confirm URL
cy.visit(`/public/confirm-email-change?token=${token}`);
// Assert that the JKChangeEmailConfirm page is rendered
// Adjust selectors/texts as per your actual component
cy.contains('Change Email Confirmation').should('be.visible');
});
});

View File

@ -0,0 +1,47 @@
import React from 'react'
import { useLocation } from "react-router-dom";
import { Card, CardBody, CardText, CardTitle } from 'reactstrap';
import PropTypes from 'prop-types';
import { useState, useEffect } from 'react';
import { updateEmail } from '../../helpers/rest';
const JKConfirmEmailChange = () => {
const location = useLocation();
const params = new URLSearchParams(location.search);
const token = params.get('token');
const [success, setSuccess] = useState(false);
useEffect(() => {
if (token) {
updateEmail(token)
.then(response => {
if (response.status === 200) {
setSuccess(true);
} else {
setSuccess(false);
}
})
.catch(() => {
setSuccess(false);
});
}
}, [token]);
return (
<Card style={{ width: '25rem', margin: '2rem auto' }}>
<CardBody>
<CardTitle className="mb-2">Unsubscribe from JamKazam emails</CardTitle>
<CardText>
{
success?
'Your email has been successfully updated.' :
'Loading...'
}
</CardText>
</CardBody>
</Card>
)
}
export default JKConfirmEmailChange

View File

@ -101,8 +101,8 @@ export const getInstruments = () => {
export const getCurrentUser = () => {
return new Promise((resolve, reject) => {
apiFetch('/me')
.then(response => resolve(response))
.catch(error => reject(error))
.then(response => resolve(response))
.catch(error => reject(error))
})
}
@ -289,7 +289,7 @@ export const getCities = (countryId, regionId) => {
export const postUpdateAccountEmail = (userId, options) => {
const { email, current_password } = options;
return new Promise((resolve, reject) => {
apiFetch(`/users/${userId}/update_email`, {
apiFetch(`/users/${userId}/update_email_alt`, {
method: 'POST',
body: JSON.stringify({ update_email: email, current_password })
})
@ -339,7 +339,7 @@ export const requstResetForgotPassword = email => {
})
.then(response => resolve(response))
.catch(error => reject(error));
});
});
};
export const resetForgotPassword = (options = {}) => {
@ -491,9 +491,9 @@ export const getJamTrackPublic = options => {
const { plan_code } = options;
return new Promise((resolve, reject) => {
// This does not make sense; historical reasons here
apiFetch(`/jamtracks/band/${plan_code}?${new URLSearchParams({plan_code})}`)
.then(response => resolve(response))
.catch(error => reject(error));
apiFetch(`/jamtracks/band/${plan_code}?${new URLSearchParams({ plan_code })}`)
.then(response => resolve(response))
.catch(error => reject(error));
});
};
@ -683,7 +683,7 @@ export const createAlert = (subject, data) => {
return new Promise((resolve, reject) => {
apiFetch(`/alerts`, {
method: 'POST',
body: JSON.stringify({subject, data})
body: JSON.stringify({ subject, data })
})
.then(response => resolve(response))
.catch(error => reject(error));
@ -700,8 +700,8 @@ export const getClientDownloads = () => {
export const getObsPluginDownloads = () => {
return new Promise((resolve, reject) => {
apiFetch(`/artifacts/OBSPlugin`)
.then(response => resolve(response))
.catch(error => reject(error));
.then(response => resolve(response))
.catch(error => reject(error));
});
}
@ -719,7 +719,7 @@ export const paypalPlaceOrder = (options = {}) => {
export const submitStripe = (options = {}) => {
return new Promise((resolve, reject) => {
return new Promise((resolve, reject) => {
apiFetch(`/stripe`, {
method: 'POST',
body: JSON.stringify(options)
@ -749,4 +749,28 @@ export const updatePayment = (options = {}) => {
.then(response => resolve(response))
.catch(error => reject(error));
});
};
};
// function postUpdateEmail(email, current_password) {
// var url = "/api/users/" + context.JK.currentUserId + "/update_email";
// return $.ajax({
// type: "POST",
// dataType: "json",
// contentType: 'application/json',
// url: url,
// data: JSON.stringify({ update_email: email, current_password: current_password }),
// processData: false
// });
// }
export const updateEmail = (userId, email, current_password) => {
return new Promise((resolve, reject) => {
apiFetch(`/users/${userId}/update_email`, {
method: 'POST',
body: JSON.stringify({ update_email: email, current_password })
})
.then(response => resolve(response))
.catch(error => reject(error));
});
}

View File

@ -11,6 +11,7 @@ import JKUnsubscribe from '../components/public/JKUnsubscribe';
import JKDownloads from '../components/public/JKDownloads';
import JKDownloadsLegacy from '../components/public/JKDownloadsLegacy';
import JKObsDownloads from '../components/public/JKObsDownloads';
import JKConfirmEmailChange from '../components/public/JKConfirmEmailChange';
import JKJamTracksLanding from '../components/jamtracks/JKJamTracksLandingDev';
import JKJamTracksArtistLanding from '../components/jamtracks/JKJamTracksArtistLandingDev';
@ -23,6 +24,7 @@ const JKPublicRoutes = ({ match: { url } }) => (
<Route path={`${url}/help-desk`} component={JKHelpDesk} />
<Route path={`${url}/forum`} component={JKForum} />
<Route path={`${url}/unsubscribe/:tok`} exact component={JKUnsubscribe} />
<Route path={`${url}/confirm-email-change`} exact component={JKConfirmEmailChange} />
<Route path={`${url}/downloads`} exact component={JKDownloads} />
<Route path={`${url}/downloads-legacy`} exact component={JKDownloadsLegacy} />
<Route path={`${url}/obs-plugin-download`} exact component={JKObsDownloads} />

View File

@ -19,11 +19,5 @@
execute "ALTER TABLE users DROP COLUMN profile_complete_reminder3_sent_at"
end
end
=begin
ALTER TABLE users ADD COLUMN profile_completed_at TIMESTAMP;
CREATE INDEX index_users_on_profile_completed_at ON users USING btree (profile_completed_at);
ALTER TABLE users ADD COLUMN profile_complete_reminder1_sent_at TIMESTAMP;
ALTER TABLE users ADD COLUMN profile_complete_reminder2_sent_at TIMESTAMP;
ALTER TABLE users ADD COLUMN profile_complete_reminder3_sent_at TIMESTAMP;
UPDATE users set profile_completed_at=NOW() WHERE users.id IN (SELECT player_id FROM musicians_instruments) OR users.id IN (SELECT player_id FROM genre_players);
end

View File

@ -6,7 +6,7 @@
# affiliate_quarterly_payments.subscription_due_amount_in_cents
# affiliate_monthly_payments.jamtrack_due_amount_in_cents
# affiliate_monthly_payments.subscription_due_amount_in_cents
class AddTrackingTotalsToAffiliatePartners < ActiveRecord::Migration
class AffiliateTrackingTotals < ActiveRecord::Migration
def self.up
execute "ALTER TABLE affiliate_partners ADD COLUMN jamtrack_cumulative_earnings_in_cents INTEGER NOT NULL DEFAULT 0"
@ -16,16 +16,16 @@ class AddTrackingTotalsToAffiliatePartners < ActiveRecord::Migration
execute "ALTER TABLE affiliate_partners ADD COLUMN subscriptions_current_quarter_in_cents INTEGER NOT NULL DEFAULT 0"
execute "ALTER TABLE affiliate_partners ADD COLUMN jamtracks_sold INTEGER NOT NULL DEFAULT 0"
execute "ALTER TABLE affiliate_partners ADD COLUMN subscriptions_count INTEGER NOT NULL DEFAULT 0"
execute "ALTER TABLE affiliate_quarterly_payments ADD COLUMN subscriptions_count INTEGER NOT NULL DEFAULT 0"
execute "ALTER TABLE affiliate_monthy_payments ADD COLUMN subscriptions_count INTEGER NOT NULL DEFAULT 0"
execute "ALTER TABLE affiliate_quarterly_payments ADD COLUMN jamtrack_due_amount_in_cents INTEGER NOT NULL DEFAULT 0"
execute "ALTER TABLE affiliate_quarterly_payments ADD COLUMN subscription_due_amount_in_cents INTEGER NOT NULL DEFAULT 0"
execute "ALTER TABLE affiliate_monthly_payments ADD COLUMN jamtrack_due_amount_in_cents INTEGER NOT NULL DEFAULT 0"
execute "ALTER TABLE affiliate_monthly_payments ADD COLUMN subscription_due_amount_in_cents INTEGER NOT NULL DEFAULT 0"
# execute "ALTER TABLE affiliate_quarterly_payments ADD COLUMN subscriptions_count INTEGER NOT NULL DEFAULT 0"
# execute "ALTER TABLE affiliate_monthy_payments ADD COLUMN subscriptions_count INTEGER NOT NULL DEFAULT 0"
# execute "ALTER TABLE affiliate_quarterly_payments ADD COLUMN jamtrack_due_amount_in_cents INTEGER NOT NULL DEFAULT 0"
# execute "ALTER TABLE affiliate_quarterly_payments ADD COLUMN subscription_due_amount_in_cents INTEGER NOT NULL DEFAULT 0"
#execute "ALTER TABLE affiliate_monthly_payments ADD COLUMN jamtrack_due_amount_in_cents INTEGER NOT NULL DEFAULT 0"
#execute "ALTER TABLE affiliate_monthly_payments ADD COLUMN subscription_due_amount_in_cents INTEGER NOT NULL DEFAULT 0"
execute "CREATE INDEX affiliate_partner_user_id_idx ON affiliate_partners USING btree (partner_user_id);"
execute "CREATE INDEX affiliate_quarterly_payments_closed_index ON affiliate_quarterly_payments USING btree (paid);"
execute "CREATE INDEX affiliate_quarterly_payments_paid_index ON affiliate_quarterly_payments USING btree (closed);"
execute "CREATE INDEX affiliate_monthly_payments_paid_index ON affiliate_monthly_payments USING btree (closed);"
# execute "CREATE INDEX affiliate_quarterly_payments_closed_index ON affiliate_quarterly_payments USING btree (paid);"
# execute "CREATE INDEX affiliate_quarterly_payments_paid_index ON affiliate_quarterly_payments USING btree (closed);"
# execute "CREATE INDEX affiliate_monthly_payments_paid_index ON affiliate_monthly_payments USING btree (closed);"
end
=begin
@ -54,7 +54,7 @@ class AddTrackingTotalsToAffiliatePartners < ActiveRecord::Migration
execute "ALTER TABLE affiliate_partners DROP COLUMN jamtrack_cumulative_earnings_in_cents"
execute "ALTER TABLE affiliate_partners DROP COLUMN subscriptions_cumulative_earnings_in_cents"
execute "ALTER TABLE affiliate_partners DROP COLUMN subscriptions_count"
execute "ALTER TABLE affiliate_quarterly_payments DROP COLUMN jamtrack_due_amount_in_cents"
execute "ALTER TABLE affiliate_quarterly_payments DROP COLUMN subscription_due_amount_in_cents"
# execute "ALTER TABLE affiliate_quarterly_payments DROP COLUMN jamtrack_due_amount_in_cents"
# execute "ALTER TABLE affiliate_quarterly_payments DROP COLUMN subscription_due_amount_in_cents"
end
end

View File

@ -11,10 +11,3 @@
execute "ALTER TABLE users DROP COLUMN gear_setup_reminder3_sent_at"
end
end
=begin
ALTER TABLE users ADD COLUMN gear_setup_reminder1_sent_at TIMESTAMP;
ALTER TABLE users ADD COLUMN gear_setup_reminder2_sent_at TIMESTAMP;
ALTER TABLE users ADD COLUMN gear_setup_reminder3_sent_at TIMESTAMP;
end

View File

@ -5,7 +5,7 @@ module JamRuby
def after_save(user)
if user.updating_email && !user.errors.any?
UserMailer.updating_email(user).deliver_now
UserMailer.begin_update_email(user).deliver_now
elsif user.updated_email && !user.errors.any?
UserMailer.updated_email(user).deliver_now
elsif user.setting_password && !user.errors.any?

View File

@ -615,6 +615,15 @@ class ApiUsersController < ApiController
# NOTE: if you change confirm_email_link value below, you break outstanding email changes because links in user inboxes are broken
confirm_email_link = confirm_email_url + "?token="
do_bigin_complete_email(confirm_email_link)
end
def begin_update_email_alt
confirm_email_link = ApplicationHelper.spa_base_uri + '/public/confirm-email-change' + "?token="
do_bigin_complete_email(confirm_email_link)
end
def do_bigin_complete_email(confirm_email_link)
current_user.begin_update_email(params[:update_email], params[:current_password], confirm_email_link)
if current_user.errors.any?

View File

@ -511,6 +511,7 @@ Rails.application.routes.draw do
# user account settings
match '/users/:id/update_email' => 'api_users#begin_update_email', :via => :post, :as => 'begin_update_email'
match '/users/:id/update_email_alt' => 'api_users#begin_update_email_alt', :via => :post, :as => 'begin_update_email_alt'
match '/users/update_email/:token' => 'api_users#finalize_update_email', :via => :post, :as => 'finalize_update_email'
# user profile

View File

@ -248,6 +248,12 @@ describe "User API", :type => :api do
return last_response
end
def begin_update_email_alt(authenticated_user, update_email, validation_password, login = true)
login(authenticated_user.email, authenticated_user.password, 200, true) if login
post "/api/users/#{authenticated_user.id}/update_email_alt.json", { :update_email => update_email, :current_password => validation_password }.to_json, "CONTENT_TYPE" => 'application/json'
return last_response
end
def finalize_update_email(update_email_token)
post "/api/users/update_email/#{update_email_token}.json", {}.to_json, "CONTENT_TYPE" => 'application/json'
return last_response
@ -907,7 +913,7 @@ describe "User API", :type => :api do
end
########## UPDATE EMAIL ########
describe "update email" do
describe "update email", focus: true do
describe "begin update email" do
it "success" do
last_response = begin_update_email(user, "not_taken_test@jamkazam.com", user.password)
@ -933,6 +939,12 @@ describe "User API", :type => :api do
last_response.status.should == 403
UserMailer.deliveries.length.should == 0
end
it "success alt" do
last_response = begin_update_email_alt(user, "not_taken_test_alt@jamkazam.com", user.password)
last_response.status.should == 200
UserMailer.deliveries.length.should == 1
end
end
describe "finalize update email" do