Skip to content
This repository has been archived by the owner on Dec 11, 2019. It is now read-only.

Commit

Permalink
Add auto-suggest sites option
Browse files Browse the repository at this point in the history
Close #6261

Auditors: @mrose17, @bsclifton
  • Loading branch information
cezaraugusto authored and bsclifton committed Jan 23, 2017
1 parent f00cce0 commit ac6d8b4
Show file tree
Hide file tree
Showing 12 changed files with 252 additions and 7 deletions.
2 changes: 2 additions & 0 deletions app/extensions/brave/locales/en-US/app.properties
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ reloadButton.title=Reload page
homeButton.title=Open Homepage
stopButton.title=Stop loading
noScriptButton.title=Allow scripts
enablePublisher.title=Enable publisher for payments
disablePublisher.title=Disable publisher for payments
braveMenu.title=Open Brave Shields Panel
muteTab=Mute tab
unmuteTab=Unmute tab
Expand Down
4 changes: 3 additions & 1 deletion app/extensions/brave/locales/en-US/preferences.properties
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ paymentsWelcomeText5=Note: Brave Payments uses a country-lookup service in order
paymentsWelcomeText6=Need more info?
paymentsWelcomeText7=for Brave Payments…
paymentsWelcomeLink=View the FAQ
paymentsFAQLink.title=View the FAQ
paymentsSidebarText1=Our Partners
paymentsSidebarText2=All transaction IP addresses are anonymized with technology from:
paymentsSidebarText3=Brave Bitcoin Wallets are provided through a partnership with:
Expand Down Expand Up @@ -52,7 +53,7 @@ viewPaymentHistory=View Payment History…
paymentHistoryTitle=Your Payment History
paymentHistoryFooterText=Your next payment contribution is {{reconcileDate}}.
paymentHistoryOKText=OK
hideExcluded=hide excluded sites
hideExcluded=Only show included sites

This comment has been minimized.

Copy link
@mrose17

mrose17 Jan 23, 2017

Member

"proper english" is "Show only included sites" (don't make the ST:TOS mistake!)

@cezaraugusto ^^^

bravePayments=Brave Payments
beta=beta
contributionDate=Contribution Date
Expand Down Expand Up @@ -85,6 +86,7 @@ off=off
on=on
ok=Ok
minimumPercentage=Hide sites with less than 1% usage
autoSuggestSites=auto-suggest sites
notifications=Show notifications
moneyAdd=Use your debit/credit card
moneyAddSubTitle=No Bitcoin needed!
Expand Down
6 changes: 5 additions & 1 deletion app/ledger.js
Original file line number Diff line number Diff line change
Expand Up @@ -519,7 +519,7 @@ eventStore.addChangeListener(() => {

// NB: in theory we have already seen every element in info except for (perhaps) the last one...
underscore.rest(info, info.length - 1).forEach((page) => {
var entry, faviconURL, publisher, siteSetting
var entry, faviconURL, pattern, publisher, siteSetting
var location = page.url

if ((location.match(/^about/)) || ((locations[location]) && (locations[location].publisher))) return
Expand All @@ -540,6 +540,10 @@ eventStore.addChangeListener(() => {
if (!page.publisher) return

publisher = page.publisher
pattern = `https?://${publisher}`
if ((!synopsis.publishers[publisher]) && (!getSetting(settings.AUTO_SUGGEST_SITES))) {
appActions.changeSiteSetting(pattern, 'ledgerPayments', false)
}
synopsis.initPublisher(publisher)
entry = synopsis.publishers[publisher]
if ((page.protocol) && (!entry.protocol)) entry.protocol = page.protocol
Expand Down
96 changes: 96 additions & 0 deletions app/renderer/components/publisherToggle.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */

const React = require('react')
const tldjs = require('tldjs')
const ImmutableComponent = require('../../../js/components/immutableComponent')
const appActions = require('../../../js/actions/appActions')
const settings = require('../../../js/constants/settings')
const getSetting = require('../../../js/settings').getSetting
const cx = require('../../../js/lib/classSet')
const Button = require('../../../js/components/button')

class PublisherToggle extends ImmutableComponent {
constructor () {
super()
this.onAuthorizePublisher = this.onAuthorizePublisher.bind(this)
}

get domain () {
return tldjs.getDomain(this.props.url)
}

get hostPattern () {
return `https?://${this.domain}`
}

get hostSettings () {
// hostPattern defines it's own identifier for authorized publishers
// sites that do not match criteria would populate siteSettings
// with their default protocol, not hostPattern
return this.props.hostSettings.get(this.hostPattern)
}

get validPublisherSynopsis () {
// If session is clear then siteSettings is undefined and icon will never be shown,
// but synopsis may not be empty. In such cases let's check if synopsis matches current domain
return this.props.synopsis.map(entry => entry.get('site')).includes(this.domain)
}

get enabledPublisher () {
// If we can't get ledgerPayments, then it's likely that we are
// on a clean session. Let's then check for publisher's synopsis
return this.hostSettings
? this.hostSettings.get('ledgerPayments') !== false
: this.validPublisherSynopsis
}

get visiblePublisher () {
// ledgerPaymentsShown is undefined by default until user decide to permanently hide the publisher
// so for icon to be shown it can be everything but false
const ledgerPaymentsShown = this.hostSettings && this.hostSettings.get('ledgerPaymentsShown')
return ledgerPaymentsShown === 'undefined' || ledgerPaymentsShown !== false
}

get shouldShowAddPublisherButton () {
if ((!!this.hostSettings || !!this.validPublisherSynopsis) && this.visiblePublisher) {
// Only show publisher icon if autoSuggest option is OFF
return !getSetting(settings.AUTO_SUGGEST_SITES)
}
return false
}

onAuthorizePublisher () {
// if payments disabled, enable it
if (!getSetting(settings.AUTO_SUGGEST_SITES)) {
appActions.changeSetting(settings.PAYMENTS_ENABLED, true)
}

this.enabledPublisher
? appActions.changeSiteSetting(this.hostPattern, 'ledgerPayments', false)
: appActions.changeSiteSetting(this.hostPattern, 'ledgerPayments', true)
}

render () {
return this.shouldShowAddPublisherButton
? <span className={cx({
addPublisherButtonContainer: true,
authorizedPublisher: this.enabledPublisher
})}>
<Button iconClass='fa-btc publisherToggleBtn'
l10nId='enablePublisher'
onClick={this.onAuthorizePublisher}
/>
</span>
: null
}
}

PublisherToggle.propTypes = {
url: React.PropTypes.string,
hostSettings: React.PropTypes.string,
synopsis: React.PropTypes.string
}

module.exports = PublisherToggle
5 changes: 4 additions & 1 deletion app/renderer/components/urlBar.js
Original file line number Diff line number Diff line change
Expand Up @@ -482,7 +482,10 @@ class UrlBar extends ImmutableComponent {

render () {
return <form
className='urlbarForm'
className={cx({
urlbarForm: true,
noBorderRadius: this.props.noBorderRadius
})}
action='#'
id='urlbar'
ref='urlbar'>
Expand Down
19 changes: 18 additions & 1 deletion js/about/preferences.js
Original file line number Diff line number Diff line change
Expand Up @@ -1373,6 +1373,16 @@ class PaymentsTab extends ImmutableComponent {
? <ModalOverlay title={'ledgerRecoveryTitle'} content={this.ledgerRecoveryContent} footer={this.ledgerRecoveryFooter} onHide={this.props.hideOverlay.bind(this, 'ledgerRecovery')} />
: null
}
<div className='advancedSettingsWrapper'>
{
this.props.ledgerData.get('created') && this.enabled
? <Button
l10nId='advancedSettings'
className='advancedSettings whiteButton'
onClick={this.props.showOverlay.bind(this, 'advancedSettings')} />
: null
}
</div>
<div className='titleBar'>
<div className='sectionTitleWrapper pull-left'>
<span className='sectionTitle'>Brave Payments</span>
Expand All @@ -1383,7 +1393,14 @@ class PaymentsTab extends ImmutableComponent {
<span data-l10n-id='off' />
<SettingCheckbox dataL10nId='on' prefKey={settings.PAYMENTS_ENABLED} settings={this.props.settings} onChangeSetting={this.props.onChangeSetting} />
</div>
{ this.props.ledgerData.get('created') && this.enabled ? <Button l10nId='advancedSettings' className='advancedSettings whiteButton' onClick={this.props.showOverlay.bind(this, 'advancedSettings')} /> : null }
{
this.props.ledgerData.get('created') && this.enabled
? <div className='autoSuggestSwitch'>
<SettingCheckbox dataL10nId='autoSuggestSites' prefKey={settings.AUTO_SUGGEST_SITES} settings={this.props.settings} onChangeSetting={this.props.onChangeSetting} />
<a className='moreInfoBtn fa fa-question-circle' href='https://brave.com/Payments_FAQ.html' target='_blank' data-l10n-id='paymentsFAQLink' />
</div>
: null
}
</div>
</div>
{
Expand Down
2 changes: 2 additions & 0 deletions js/components/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -1003,6 +1003,8 @@ class Main extends ImmutableComponent {
settings={this.props.appState.get('settings')}
noScriptIsVisible={noScriptIsVisible}
menubarVisible={customTitlebar.menubarVisible}
siteSettings={this.props.appState.get('siteSettings')}
synopsis={this.props.appState.getIn(['publisherInfo', 'synopsis']) || new Immutable.Map()}
/>
<div className='topLevelEndButtons'>
<div className={cx({
Expand Down
12 changes: 11 additions & 1 deletion js/components/navigationBar.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ const getSetting = require('../settings').getSetting
const windowStore = require('../stores/windowStore')
const contextMenus = require('../contextMenus')
const LongPressButton = require('./longPressButton')
const PublisherToggle = require('../../app/renderer/components/publisherToggle')

class NavigationBar extends ImmutableComponent {
constructor () {
Expand Down Expand Up @@ -128,7 +129,8 @@ class NavigationBar extends ImmutableComponent {
}

render () {
if (this.props.activeFrameKey === undefined) {
if (this.props.activeFrameKey === undefined ||
this.props.siteSettings === undefined) {
return null
}

Expand Down Expand Up @@ -206,13 +208,21 @@ class NavigationBar extends ImmutableComponent {
urlbar={this.props.navbar.get('urlbar')}
onStop={this.onStop}
menubarVisible={this.props.menubarVisible}
noBorderRadius={this.shouldShowAddPublisherButton}
/>
{
isSourceAboutUrl(this.props.location)
? <div className='endButtons'>
<span className='browserButton' />
</div>
: <div className='endButtons'>
{
<PublisherToggle
url={this.props.location}
hostSettings={this.props.siteSettings}
synopsis={this.props.synopsis}
/>
}
{
!this.showNoScriptInfo
? null
Expand Down
1 change: 1 addition & 0 deletions js/constants/appConfig.js
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ module.exports = {
'advanced.minimum-visit-time': 8,
'advanced.minimum-visits': 5,
'advanced.minimum-percentage': false,
'advanced.auto-suggest-sites': true,
'shutdown.clear-history': false,
'shutdown.clear-downloads': false,
'shutdown.clear-cache': false,
Expand Down
1 change: 1 addition & 0 deletions js/constants/settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ const settings = {
MINIMUM_VISIT_TIME: 'advanced.minimum-visit-time',
MINIMUM_VISITS: 'advanced.minimum-visits',
MINIMUM_PERCENTAGE: 'advanced.minimum-percentage',
AUTO_SUGGEST_SITES: 'advanced.auto-suggest-sites',

// DEPRECATED settings
// ########################
Expand Down
3 changes: 1 addition & 2 deletions less/navigationBar.less
Original file line number Diff line number Diff line change
Expand Up @@ -674,7 +674,6 @@
content: ' ';
position: absolute;
background: #fff;
border: 1px solid @focusUrlbarOutline;
border-radius: 4px;
box-shadow: 0 0 1px @focusUrlbarOutline, inset 0 0 2px @focusUrlbarOutline, inset 0 1px 8px rgba(0, 137, 255, 0.1);
color: #333;
Expand Down Expand Up @@ -734,7 +733,7 @@
}

.urlbarForm {
&.noBorderRadius {
&.noBorderRadius {
border-radius: 0;
}
}
Expand Down
108 changes: 108 additions & 0 deletions test/unit/app/renderer/publisherToggleTest.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
/* global describe, it, before, after */
const mockery = require('mockery')
const {shallow} = require('enzyme')
const assert = require('assert')
const Immutable = require('immutable')
const tldjs = require('tldjs')
const fakeElectron = require('../../lib/fakeElectron')
const settingsConst = require('../../../../js/constants/settings')
let PublisherToggle
require('../../braveUnit')

describe('PublisherToggle component', function () {
const getDomain = (url) => tldjs.getDomain(url)
const getPattern = (pattern) => `https?://${getDomain(pattern)}`
const getHostPattern = (pattern, isEnabled, shouldShow) => Immutable.fromJS({
[pattern]: {
'ledgerPayments': isEnabled,
'ledgerPaymentsShown': shouldShow
}
})
const getPublisherSynopsis = (url) => Immutable.fromJS([{
'site': getDomain(url),
'publisherURL': url
}])

const url1 = 'https://clifton.io/sharing-my-passion-for-mercedes-benz'
const domain1 = getDomain(url1)
const pattern1 = getPattern(domain1)

before(function () {
mockery.enable({
warnOnReplace: false,
warnOnUnregistered: false,
useCleanCache: true
})
mockery.registerMock('../../../js/settings', { getSetting: (settingKey, settingsCollection, value) => {
if (settingKey === settingsConst.AUTO_SUGGEST_SITES) {
return false
}
return true
}})
mockery.registerMock('electron', fakeElectron)
window.chrome = fakeElectron
PublisherToggle = require('../../../../app/renderer/components/publisherToggle')
})
after(function () {
mockery.disable()
})

describe('criteria to be shown', function () {
it('renders if domain match synopsis criteria (siteSettings is empty)', function () {
const wrapper = shallow(
<PublisherToggle
url={url1}
hostSettings={Immutable.Map()}
synopsis={getPublisherSynopsis(domain1, url1)} />
)
assert.equal(wrapper.find('.addPublisherButtonContainer').length, 1)
})
it('render if hostPattern match siteSettings (synopsis is empty)', function () {
const wrapper = shallow(
<PublisherToggle
url={url1}
hostSettings={getHostPattern(pattern1, true, true)}
synopsis={Immutable.List()} />
)
assert.equal(wrapper.find('.addPublisherButtonContainer').length, 1)
})
it('do not render for unauthorized publishers (no siteSettings and no synopsis)', function () {
const wrapper = shallow(
<PublisherToggle
url={url1}
hostSettings={Immutable.Map()}
synopsis={Immutable.List()} />
)
assert.equal(wrapper.find('.addPublisherButtonContainer').length, 0)
})
it('do not render if publisher is permanently hidden', function () {
const wrapper = shallow(
<PublisherToggle
url={url1}
hostSettings={getHostPattern(pattern1, true, false)}
synopsis={Immutable.List()} />
)
assert.equal(wrapper.find('.addPublisherButtonContainer').length, 0)
})
it('show as enabled if ledgerPayments is true for that publisher', function () {
const wrapper = shallow(
<PublisherToggle
url={url1}
hostSettings={getHostPattern(pattern1, true, true)}
synopsis={Immutable.List()} />
)
assert.equal(wrapper.find('.addPublisherButtonContainer').length, 1)
assert.equal(wrapper.find('.authorizedPublisher').length, 1)
})
it('Show as disabled if ledgerPayments is false for that publisher', function () {
const wrapper = shallow(
<PublisherToggle
url={url1}
hostSettings={getHostPattern(pattern1, false, true)}
synopsis={Immutable.List()} />
)
assert.equal(wrapper.find('.addPublisherButtonContainer').length, 1)
assert.equal(wrapper.find('.authorizedPublisher').length, 0)
})
})
})

0 comments on commit ac6d8b4

Please sign in to comment.