Skip to content

Commit

Permalink
Fix for caching issue and create a new "contact support" page
Browse files Browse the repository at this point in the history
  • Loading branch information
bsclifton committed Apr 1, 2022
1 parent e78ea82 commit 5d44d1c
Show file tree
Hide file tree
Showing 9 changed files with 304 additions and 38 deletions.
6 changes: 6 additions & 0 deletions components/brave_vpn/brave_vpn.mojom
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,12 @@ interface ServiceHandler {

[EnableIfNot=is_android]
GetProductUrls() => (ProductUrls urls);

[EnableIfNot=is_android]
GetSupportData() => (string app_version, string os_version, string hostname);

[EnableIfNot = is_android]
CreateSupportTicket(string email, string subject, string body) => (string response);
};

// WebUI-side handler for requests from the browser.
Expand Down
98 changes: 68 additions & 30 deletions components/brave_vpn/brave_vpn_service.cc
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ constexpr char kProfileCredential[] = "api/v1.1/register-and-create";
constexpr char kVerifyPurchaseToken[] = "api/v1.1/verify-purchase-token";
constexpr char kCreateSubscriberCredentialV12[] =
"api/v1.2/subscriber-credential/create";
constexpr char kCreateSupportTicket[] = "api/v1.2/partners/support-ticket";

net::NetworkTrafficAnnotationTag GetNetworkTrafficAnnotationTag() {
return net::DefineNetworkTrafficAnnotation("brave_vpn_service", R"(
Expand Down Expand Up @@ -220,9 +221,9 @@ void BraveVpnService::ScheduleFetchRegionDataIfNeeded() {
// Try to update region list every 5h.
FetchRegionData();
constexpr int kRegionDataUpdateIntervalInHours = 5;
region_data_update_timer_.Start(
FROM_HERE, base::Hours(kRegionDataUpdateIntervalInHours), this,
&BraveVpnService::FetchRegionData);
region_data_update_timer_.Start(FROM_HERE,
base::Hours(kRegionDataUpdateIntervalInHours),
this, &BraveVpnService::FetchRegionData);
}

void BraveVpnService::OnCreated() {
Expand Down Expand Up @@ -447,8 +448,7 @@ void BraveVpnService::OnPanelVisible() {
LoadPurchasedState();
}

void BraveVpnService::GetConnectionState(
GetConnectionStateCallback callback) {
void BraveVpnService::GetConnectionState(GetConnectionStateCallback callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
VLOG(2) << __func__ << " : " << static_cast<int>(connection_state_);
std::move(callback).Run(connection_state_);
Expand Down Expand Up @@ -493,7 +493,6 @@ void BraveVpnService::LoadCachedRegionData() {
}
}


void BraveVpnService::LoadSelectedRegion() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
auto* preference =
Expand All @@ -519,7 +518,7 @@ void BraveVpnService::LoadSelectedRegion() {
}

void BraveVpnService::OnFetchRegionList(const std::string& region_list,
bool success) {
bool success) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!success) {
// TODO(simonhong): Re-try?
Expand All @@ -533,8 +532,8 @@ void BraveVpnService::OnFetchRegionList(const std::string& region_list,

if (ParseAndCacheRegionList(std::move(*value))) {
// Fetch timezones list to determine default region of this device.
GetTimezonesForRegions(base::BindOnce(
&BraveVpnService::OnFetchTimezones, base::Unretained(this)));
GetTimezonesForRegions(base::BindOnce(&BraveVpnService::OnFetchTimezones,
base::Unretained(this)));
return;
}
}
Expand Down Expand Up @@ -582,7 +581,7 @@ bool BraveVpnService::ParseAndCacheRegionList(base::Value region_value) {
}

void BraveVpnService::OnFetchTimezones(const std::string& timezones_list,
bool success) {
bool success) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!success) {
VLOG(2) << "Failed to get timezones list";
Expand Down Expand Up @@ -663,8 +662,7 @@ void BraveVpnService::SetFallbackDeviceRegion() {
SetDeviceRegion(regions_[0]);
}

void BraveVpnService::SetDeviceRegion(
const brave_vpn::mojom::Region& region) {
void BraveVpnService::SetDeviceRegion(const brave_vpn::mojom::Region& region) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
device_region_ = region;

Expand Down Expand Up @@ -704,8 +702,7 @@ void BraveVpnService::GetDeviceRegion(GetDeviceRegionCallback callback) {
std::move(callback).Run(device_region_.Clone());
}

void BraveVpnService::GetSelectedRegion(
GetSelectedRegionCallback callback) {
void BraveVpnService::GetSelectedRegion(GetSelectedRegionCallback callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
VLOG(2) << __func__;

Expand Down Expand Up @@ -758,22 +755,54 @@ void BraveVpnService::GetProductUrls(GetProductUrlsCallback callback) {
std::move(callback).Run(urls.Clone());
}

void BraveVpnService::CreateSupportTicket(
const std::string& email,
const std::string& subject,
const std::string& body,
CreateSupportTicketCallback callback) {
// TODO(bsclifton): finish me
auto internal_callback =
base::BindOnce(&BraveVpnService::OnCreateSupportTicket,
weak_ptr_factory_.GetWeakPtr(), std::move(callback));

const GURL base_url = GetURLWithPath(kVpnHost, kCreateSupportTicket);
base::Value dict(base::Value::Type::DICTIONARY);
// required fields
// TODO: trim
dict.SetStringKey("email", email);
dict.SetStringKey("subject", subject);
dict.SetStringKey("support-ticket", body);
dict.SetStringKey("partner-client-id", "com.brave.browser");

// optional (but encouraged) fields
dict.SetStringKey("subscriber-credential", "");
dict.SetStringKey("payment-validation-method", "brave-premium");
dict.SetStringKey("payment-validation-data", "");

std::string request_body = CreateJSONRequestBody(dict);
LOG(ERROR) << " : sending " << request_body;
OAuthRequest(base_url, "POST", request_body, std::move(internal_callback));
}

void BraveVpnService::GetSupportData(GetSupportDataCallback callback) {
// TODO(bsclifton): finish me
}

void BraveVpnService::FetchHostnamesForRegion(const std::string& name) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
VLOG(2) << __func__;
// Hostname will be replaced with latest one.
hostname_.reset();

// Unretained is safe here becasue this class owns request helper.
GetHostnamesForRegion(
base::BindOnce(&BraveVpnService::OnFetchHostnames,
base::Unretained(this), name),
name);
GetHostnamesForRegion(base::BindOnce(&BraveVpnService::OnFetchHostnames,
base::Unretained(this), name),
name);
}

void BraveVpnService::OnFetchHostnames(const std::string& region,
const std::string& hostnames,
bool success) {
const std::string& hostnames,
bool success) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
VLOG(2) << __func__;
if (cancel_connecting_) {
Expand All @@ -798,9 +827,8 @@ void BraveVpnService::OnFetchHostnames(const std::string& region,
UpdateAndNotifyConnectionStateChange(ConnectionState::CONNECT_FAILED);
}

void BraveVpnService::ParseAndCacheHostnames(
const std::string& region,
base::Value hostnames_value) {
void BraveVpnService::ParseAndCacheHostnames(const std::string& region,
base::Value hostnames_value) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(hostnames_value.is_list());
if (!hostnames_value.is_list()) {
Expand Down Expand Up @@ -967,8 +995,7 @@ void BraveVpnService::AddObserver(
observers_.Add(std::move(observer));
}

void BraveVpnService::GetPurchasedState(
GetPurchasedStateCallback callback) {
void BraveVpnService::GetPurchasedState(GetPurchasedStateCallback callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
VLOG(2) << __func__ << " : " << static_cast<int>(purchased_state_);
std::move(callback).Run(purchased_state_);
Expand All @@ -994,8 +1021,7 @@ void BraveVpnService::LoadPurchasedState() {
base::Unretained(this)));
}

void BraveVpnService::OnCredentialSummary(
const std::string& summary_string) {
void BraveVpnService::OnCredentialSummary(const std::string& summary_string) {
std::string summary_string_trimmed;
base::TrimWhitespaceASCII(summary_string, base::TrimPositions::TRIM_ALL,
&summary_string_trimmed);
Expand All @@ -1021,9 +1047,8 @@ void BraveVpnService::OnCredentialSummary(
EnsureMojoConnected();
skus_service_->PrepareCredentialsPresentation(
skus::GetDomain("vpn"), "*",
base::BindOnce(
&BraveVpnService::OnPrepareCredentialsPresentation,
base::Unretained(this)));
base::BindOnce(&BraveVpnService::OnPrepareCredentialsPresentation,
base::Unretained(this)));
} else {
LOG(ERROR) << "Credential appears to be expired.";
SetPurchasedState(PurchasedState::EXPIRED);
Expand Down Expand Up @@ -1268,3 +1293,16 @@ void BraveVpnService::GetSubscriberCredentialV12(
OAuthRequest(base_url, "POST", request_body, std::move(internal_callback),
{{"Brave-Payments-Environment", payments_environment}});
}

void BraveVpnService::OnCreateSupportTicket(
CreateSupportTicketCallback callback,
int status,
const std::string& body,
const base::flat_map<std::string, std::string>& headers) {
bool success = status == 200;
LOG(ERROR) << "BSC]] OnCreateSupportTicket =" << success;

// TODO: hide the contact form
// maybe callback can do that behavior and we can just run callback
// ..
}
18 changes: 14 additions & 4 deletions components/brave_vpn/brave_vpn_service.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,10 @@ using PurchasedState = brave_vpn::mojom::PurchasedState;
// by OS_ANDROID ifdef.
class BraveVpnService :
#if !defined(OS_ANDROID)
public brave_vpn::BraveVPNOSConnectionAPI::Observer,
public brave_vpn::BraveVPNOSConnectionAPI::Observer,
#endif
public brave_vpn::mojom::ServiceHandler,
public KeyedService {
public brave_vpn::mojom::ServiceHandler,
public KeyedService {
public:
#if defined(OS_ANDROID)
BraveVpnService(
Expand Down Expand Up @@ -102,6 +102,11 @@ class BraveVpnService :
void GetSelectedRegion(GetSelectedRegionCallback callback) override;
void SetSelectedRegion(brave_vpn::mojom::RegionPtr region) override;
void GetProductUrls(GetProductUrlsCallback callback) override;
void CreateSupportTicket(const std::string& email,
const std::string& subject,
const std::string& body,
CreateSupportTicketCallback callback) override;
void GetSupportData(GetSupportDataCallback callback) override;
#endif // !defined(OS_ANDROID)

using ResponseCallback =
Expand Down Expand Up @@ -185,7 +190,6 @@ class BraveVpnService :
bool success);
void OnGetProfileCredentials(const std::string& profile_credential,
bool success);

brave_vpn::BraveVPNOSConnectionAPI* GetBraveVPNConnectionAPI();

void set_test_timezone(const std::string& timezone) {
Expand Down Expand Up @@ -219,6 +223,12 @@ class BraveVpnService :
const std::string& body,
const base::flat_map<std::string, std::string>& headers);

void OnCreateSupportTicket(
CreateSupportTicketCallback callback,
int status,
const std::string& body,
const base::flat_map<std::string, std::string>& headers);

void LoadPurchasedState();
void SetPurchasedState(PurchasedState state);
void EnsureMojoConnected();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
import * as React from 'react'
import { Button } from 'brave-ui'

import { getLocale } from '../../../../../common/locale'
import * as S from './style'
import getPanelBrowserAPI from '../../api/panel_browser_api'
import { CaratStrongLeftIcon } from 'brave-ui/components/icons'

interface Props {
closeContactSupport: React.MouseEventHandler<HTMLButtonElement>
}

interface ContactSupportState {
contactEmail: string
problemSubject: string
problemBody: string
shareHostname: boolean
shareAppVersion: boolean
shareOsVersion: boolean
}

function ContactSupport (props: Props) {
const [supportData, setSupportData] = React.useState('TODO: fill me in')

React.useEffect(async () => {
setSupportData(await getPanelBrowserAPI().getSupportData())
})

const [formData, setFormData] = React.useState<ContactSupportState>({
contactEmail: '',
problemSubject: '',
problemBody: '',
shareHostname: true,
shareAppVersion: true,
shareOsVersion: true
})

const isValid = React.useMemo(() => {
return !!formData?.problemBody
}, [formData])

const handleSubmit = () => {
// Build submit data
}

const onChangeBody = (event: React.ChangeEvent<HTMLTextAreaElement>) => {
setFormData({
...formData,
problemBody: event.currentTarget.value
})
console.log('changed')
}

return (
<S.Box>
<S.PanelContent>
<S.PanelHeader>
<S.BackButton
type='button'
onClick={props.closeContactSupport}
aria-label='Close support form'
>
<i><CaratStrongLeftIcon /></i>
<span>{getLocale('braveVpnContactSupport')}</span>
</S.BackButton>
</S.PanelHeader>
<S.List>
<li>
Your email address
</li>
<li>
Subject
<select value={formData?.problemSubject || ''} name="issue" id="contact-support-issue">
<option value="" disabled>Please choose a reason</option>
<option value="cant-connect">Cannot connect to the VPN (Other error)</option>
<option value="no-internet">No internet when connected</option>
<option value="slow">Slow connection</option>
<option value="website">Website doesn't work</option>
<option value="other">Other</option>
</select>
</li>
<li>
Describe your issue
<textarea
style={{ marginTop: '10px' }}
data-test-id={'contactSupportBody'}
cols={100}
rows={10}
value={formData?.problemBody || ''}
onChange={onChangeBody}
/>
</li>
<li>Please select the information you're comfortable sharing with us</li>
<li>VPN hostname: {supportData.os_version}</li>
<li>App version:</li>
<li>OS version:</li>
<li>
The more information you share with us the easier it will be for the support
staff to help you resolve your issue.

Support provided with the help of the Guardian team.
</li>
</S.List>
<Button
level='primary'
type='accent'
brand='rewards'
text='Submit'
disabled={!isValid}
onClick={handleSubmit}
/>
</S.PanelContent>
</S.Box>
)
}

export default ContactSupport
Loading

0 comments on commit 5d44d1c

Please sign in to comment.