Skip to content
This repository has been archived by the owner on Jan 22, 2022. It is now read-only.

enable html5 notifications #464

Open
wants to merge 9 commits into
base: xenial
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 7 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
3 changes: 3 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_AUTOMOC ON)

set(DESKTOP_FILE morph-browser.desktop)
set(PUSH_HELPER_DIR "lib/ubuntu-push-client/legacy-helpers")

# uninstall target
configure_file(
Expand Down Expand Up @@ -94,4 +95,6 @@ add_subdirectory(doc)

install(FILES morph-browser.svg DESTINATION ${CMAKE_INSTALL_DATADIR}/morph-browser)
install(FILES morph-browser-splash.svg DESTINATION ${CMAKE_INSTALL_DATADIR}/morph-browser)
install(PROGRAMS push-helper/morph-browser-helper.sh DESTINATION ${PUSH_HELPER_DIR} RENAME morph-browser)

add_subdirectory(click-hooks)
2 changes: 1 addition & 1 deletion debian/morph-browser-apparmor.manifest
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
],
"template_variables": {
"APP_ID_DBUS": "morph_2dbrowser",
"APP_PKGNAME_DBUS": "morph_2dbrowser",
"APP_PKGNAME_DBUS": "_",
"APP_PKGNAME": "morph-browser",
"CLICK_DIR": "/usr/share/morph-browser"
},
Expand Down
1 change: 1 addition & 0 deletions debian/morph-browser.install
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
usr/bin/morph-browser
usr/lib/ubuntu-push-client/legacy-helpers
usr/share/morph-browser/*.qml
usr/share/morph-browser/qmldir
usr/share/morph-browser/*.js
Expand Down
3 changes: 3 additions & 0 deletions push-helper/morph-browser-helper.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#!/bin/sh

cp $1 $2
3 changes: 3 additions & 0 deletions src/app/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ set(COMMONLIB_SRC
input-method-handler.cpp
meminfo.cpp
mime-database.cpp
notifications-proxy.cpp
pushclient/pushclient.cpp
session-storage.cpp
single-instance-manager.cpp
)
Expand All @@ -44,6 +46,7 @@ target_link_libraries(${COMMONLIB}
Qt5::Qml
Qt5::Quick
Qt5::Widgets
Qt5DBus
Qt5WebEngine
Qt5WebEngineCore
${LIBAPPARMOR_LDFLAGS}
Expand Down
21 changes: 20 additions & 1 deletion src/app/DomainSettingsPage.qml
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,7 @@ FocusScope {
readonly property string domain: model.domain
readonly property int userAgentId: model.userAgentId
readonly property int locationPreference: model.allowLocation
readonly property int notificationsPreference: model.allowNotifications
height: isCurrentItem ? layout.height : units.gu(5)
color: isCurrentItem ? ((theme.palette.selected.background.hslLightness > 0.5) ? Qt.darker(theme.palette.selected.background, 1.05) : Qt.lighter(theme.palette.selected.background, 1.5)) : theme.palette.normal.background

Expand Down Expand Up @@ -215,7 +216,6 @@ FocusScope {
}
}


Row {
spacing: units.gu(1.5)
height: units.gu(1)
Expand All @@ -234,6 +234,25 @@ FocusScope {
anchors.verticalCenter: parent.verticalCenter
}
}

Row {
spacing: units.gu(1.5)
height: units.gu(1)
visible: item.ListView.isCurrentItem

Label {
width: parent.width * 0.5
text: i18n.tr("send notifications")
anchors.verticalCenter: parent.verticalCenter
}

ComboBox {
model: [ i18n.tr("Ask each time"), i18n.tr("Allowed"), i18n.tr("Denied") ]
currentIndex: item.notificationsPreference
onCurrentIndexChanged: DomainSettingsModel.setNotificationsPreference(item.domain, currentIndex)
anchors.verticalCenter: parent.verticalCenter
}
}

Row {
spacing: units.gu(1.5)
Expand Down
61 changes: 61 additions & 0 deletions src/app/NotificationsAccessDialog.qml
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/*
* Copyright 2020 UBports Foundation
*
* This file is part of morph-browser.
*
* morph-browser is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 3.
*
* morph-browser is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

import QtQuick 2.4
import Ubuntu.Components 1.3
import Ubuntu.Components.Popups 1.3

Dialog {
id: dialog

property string securityOrigin
property bool showRememberDecisionCheckBox
modal: true

title: i18n.tr("Permission Request")
text: securityOrigin + "<br>" + i18n.tr("This page wants to create notifications.")

signal allow()
signal allowPermanently()
signal reject()
signal rejectPermanently()

onAllow: { PopupUtils.close(dialog); }
onAllowPermanently: { PopupUtils.close(dialog); }
onReject: { PopupUtils.close(dialog); }
onRejectPermanently: { PopupUtils.close(dialog); }

ListItemLayout {
visible: showRememberDecisionCheckBox
title.text: i18n.tr("Remember decision")
CheckBox {
id: rememberDecisionCheckBox
}
}
Button {
objectName: "allow"
text: i18n.tr("Allow")
color: theme.palette.normal.positive
onClicked: rememberDecisionCheckBox.checked ? allowPermanently() : allow()
}
Button {
objectName: "deny"
text: i18n.tr("Deny")
onClicked: rememberDecisionCheckBox.checked ? rejectPermanently() : reject()
}
}
30 changes: 30 additions & 0 deletions src/app/WebViewImpl.qml
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,36 @@ WebView {
mediaAccessDialog.origin = securityOrigin;
mediaAccessDialog.feature = feature;
break;

case WebEngineView.Notifications:

var domain = UrlUtils.extractHost(securityOrigin);
var notificationsPreference = DomainSettingsModel.getNotificationsPreference(domain);

if (notificationsPreference === DomainSettingsModel.AllowNotificationsAccess)
{
grantFeaturePermission(securityOrigin, feature, true);
return;
}

if (notificationsPreference === DomainSettingsModel.DenyNotificationsAccess)
{
grantFeaturePermission(securityOrigin, feature, false);
return;
}

var notificationsAccessDialog = PopupUtils.open(Qt.resolvedUrl("NotificationsAccessDialog.qml"), this);
notificationsAccessDialog.securityOrigin = securityOrigin;
notificationsAccessDialog.showRememberDecisionCheckBox = (domain !== "") && ! incognito
notificationsAccessDialog.allow.connect(function() { grantFeaturePermission(securityOrigin, feature, true); });
notificationsAccessDialog.allowPermanently.connect(function() { grantFeaturePermission(securityOrigin, feature, true);
DomainSettingsModel.setNotificationsPreference(domain, DomainSettingsModel.AllowNotificationsAccess);
});
notificationsAccessDialog.reject.connect(function() { grantFeaturePermission(securityOrigin, feature, false); });
notificationsAccessDialog.rejectPermanently.connect(function() { grantFeaturePermission(securityOrigin, feature, false);
DomainSettingsModel.setNotificationsPreference(domain, DomainSettingsModel.DenyNotificationsAccess);
});
break;
}
}

Expand Down
3 changes: 3 additions & 0 deletions src/app/browserapplication.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
#include "input-method-handler.h"
#include "meminfo.h"
#include "mime-database.h"
#include "notifications-proxy.h"
#include "session-storage.h"

BrowserApplication::BrowserApplication(int& argc, char** argv)
Expand Down Expand Up @@ -107,6 +108,7 @@ MAKE_SINGLETON_FACTORY(DownloadsModel)
MAKE_SINGLETON_FACTORY(FileOperations)
MAKE_SINGLETON_FACTORY(MemInfo)
MAKE_SINGLETON_FACTORY(MimeDatabase)
MAKE_SINGLETON_FACTORY(NotificationsProxy)
MAKE_SINGLETON_FACTORY(UserAgentsModel)

bool BrowserApplication::initialize(const QString& qmlFileSubPath
Expand Down Expand Up @@ -202,6 +204,7 @@ bool BrowserApplication::initialize(const QString& qmlFileSubPath
qmlRegisterSingletonType<FileOperations>(uri, 0, 1, "FileOperations", FileOperations_singleton_factory);
qmlRegisterSingletonType<MemInfo>(uri, 0, 1, "MemInfo", MemInfo_singleton_factory);
qmlRegisterSingletonType<MimeDatabase>(uri, 0, 1, "MimeDatabase", MimeDatabase_singleton_factory);
qmlRegisterSingletonType<NotificationsProxy>(uri, 0, 1, "NotificationsProxy", NotificationsProxy_singleton_factory);
qmlRegisterType<SessionStorage>(uri, 0, 1, "SessionStorage");
qmlRegisterSingletonType<UserAgentsModel>(uri, 0, 1, "UserAgentsModel", UserAgentsModel_singleton_factory);

Expand Down
75 changes: 69 additions & 6 deletions src/app/domain-settings-model.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ QHash<int, QByteArray> DomainSettingsModel::roleNames() const
roles[DomainWithoutSubdomain] = "domainWithoutSubdomain";
roles[AllowCustomUrlSchemes] = "allowCustomUrlSchemes";
roles[AllowLocation] = "allowLocation";
roles[AllowNotifications] = "allowNotifications";
roles[UserAgentId] = "userAgentId";
roles[ZoomFactor] = "zoomFactor";
}
Expand Down Expand Up @@ -98,6 +99,8 @@ QVariant DomainSettingsModel::data(const QModelIndex& index, int role) const
return entry.allowCustomUrlSchemes;
case AllowLocation:
return entry.allowLocation;
case AllowNotifications:
return entry.allowNotifications;
case UserAgentId:
return entry.userAgentId;
case ZoomFactor:
Expand All @@ -111,16 +114,40 @@ void DomainSettingsModel::createOrAlterDatabaseSchema()
{
QSqlQuery createQuery(m_database);
QString query = QLatin1String("CREATE TABLE IF NOT EXISTS domainsettings "
"(domain VARCHAR NOT NULL UNIQUE, domainWithoutSubdomain VARCHAR, allowCustomUrlSchemes BOOL, allowLocation INTEGER, "
"(domain VARCHAR NOT NULL UNIQUE, domainWithoutSubdomain VARCHAR, allowCustomUrlSchemes BOOL, allowLocation INTEGER, allowNotifications INTEGER, "
"userAgentId INTEGER, zoomFactor REAL, PRIMARY KEY(domain), FOREIGN KEY(userAgentId) REFERENCES useragents(id)); ");
createQuery.prepare(query);
createQuery.exec();

// Older version of the database schema didn’t have the column 'allowNotifications'
QSqlQuery tableInfoQuery(m_database);
query = QLatin1String("PRAGMA TABLE_INFO(domainsettings);");
tableInfoQuery.prepare(query);
tableInfoQuery.exec();

bool missingAllowNotificationsColumn = true;

while (tableInfoQuery.next()) {
if (tableInfoQuery.value("name").toString() == "allowNotifications") {
missingAllowNotificationsColumn = false;
}
if (!missingAllowNotificationsColumn) {
break;
}
}

if (missingAllowNotificationsColumn) {
QSqlQuery addFolderColumnQuery(m_database);
query = QLatin1String("ALTER TABLE domainsettings ADD COLUMN allowNotifications INTEGER;");
addFolderColumnQuery.prepare(query);
addFolderColumnQuery.exec();
}
}

void DomainSettingsModel::populateFromDatabase()
{
QSqlQuery populateQuery(m_database);
QString query = QLatin1String("SELECT domain, domainWithoutSubdomain, allowCustomUrlSchemes, allowLocation, userAgentId, zoomFactor "
QString query = QLatin1String("SELECT domain, domainWithoutSubdomain, allowCustomUrlSchemes, allowLocation, allowNotifications, userAgentId, zoomFactor "
"FROM domainsettings;");
populateQuery.prepare(query);
populateQuery.exec();
Expand All @@ -131,6 +158,7 @@ void DomainSettingsModel::populateFromDatabase()
entry.domainWithoutSubdomain = populateQuery.value("domainWithoutSubdomain").toString();
entry.allowCustomUrlSchemes = populateQuery.value("allowCustomUrlSchemes").toBool();
entry.allowLocation = static_cast<AllowLocationPreference>(populateQuery.value("allowLocation").toInt());
entry.allowNotifications = static_cast<NotificationsPreference>(populateQuery.value("allowNotifications").toInt());
entry.userAgentId = populateQuery.value("userAgentId").toInt();
entry.zoomFactor = populateQuery.value("zoomFactor").isNull() ? std::numeric_limits<double>::quiet_NaN()
: populateQuery.value("zoomFactor").toDouble();
Expand Down Expand Up @@ -247,6 +275,38 @@ void DomainSettingsModel::setLocationPreference(const QString& domain, DomainSet
}
}

DomainSettingsModel::NotificationsPreference DomainSettingsModel::getNotificationsPreference(const QString& domain) const
{
int index = getIndexForDomain(domain);
if (index == -1)
{
return NotificationsPreference::AskForNotificationsAccess;
}

return m_entries[index].allowNotifications;
}

void DomainSettingsModel::setNotificationsPreference(const QString& domain, DomainSettingsModel::NotificationsPreference preference)
{
insertEntry(domain);

int index = getIndexForDomain(domain);
if (index != -1) {
DomainSetting& entry = m_entries[index];
if (entry.allowNotifications == preference) {
return;
}
entry.allowNotifications = preference;
Q_EMIT dataChanged(this->index(index, 0), this->index(index, 0), QVector<int>() << AllowNotifications);
QSqlQuery query(m_database);
static QString updateStatement = QLatin1String("UPDATE domainsettings SET allowNotifications=? WHERE domain=?;");
query.prepare(updateStatement);
query.addBindValue(entry.allowNotifications);
query.addBindValue(domain);
query.exec();
}
}

int DomainSettingsModel::getUserAgentId(const QString& domain) const
{
int index = getIndexForDomain(domain);
Expand Down Expand Up @@ -347,20 +407,22 @@ void DomainSettingsModel::insertEntry(const QString &domain)
entry.domainWithoutSubdomain = DomainUtils::getDomainWithoutSubdomain(domain);
entry.allowCustomUrlSchemes = false;
entry.allowLocation = AllowLocationPreference::AskForLocationAccess;
entry.allowNotifications = NotificationsPreference::AskForNotificationsAccess;
entry.userAgentId = 0;
entry.zoomFactor = std::numeric_limits<double>::quiet_NaN();
m_entries.append(entry);
endInsertRows();
Q_EMIT rowCountChanged();

QSqlQuery query(m_database);
static QString insertStatement = QLatin1String("INSERT INTO domainsettings (domain, domainWithoutSubdomain, allowCustomUrlSchemes, allowLocation, userAgentId, zoomFactor)"
" VALUES (?, ?, ?, ?, ?, ?);");
static QString insertStatement = QLatin1String("INSERT INTO domainsettings (domain, domainWithoutSubdomain, allowCustomUrlSchemes, allowLocation, allowNotifications, userAgentId, zoomFactor)"
" VALUES (?, ?, ?, ?, ?, ?, ?);");
query.prepare(insertStatement);
query.addBindValue(entry.domain);
query.addBindValue(entry.domainWithoutSubdomain);
query.addBindValue(entry.allowCustomUrlSchemes);
query.addBindValue(entry.allowLocation);
query.addBindValue(entry.allowNotifications);
query.addBindValue((entry.userAgentId > 0) ? entry.userAgentId : QVariant());
query.addBindValue(entry.zoomFactor);
query.exec();
Expand Down Expand Up @@ -390,10 +452,11 @@ void DomainSettingsModel::removeEntry(const QString &domain)
void DomainSettingsModel::removeObsoleteEntries()
{
QSqlQuery query(m_database);
static QString deleteStatement = QLatin1String("DELETE FROM domainsettings WHERE allowCustomUrlSchemes=? AND allowLocation=? AND userAgentId IS NULL AND zoomFactor IS NULL;");
static QString deleteStatement = QLatin1String("DELETE FROM domainsettings WHERE allowCustomUrlSchemes=? AND allowLocation=? AND allowNotifications=? AND userAgentId IS NULL AND zoomFactor IS NULL;");
query.prepare(deleteStatement);
query.addBindValue(false);
query.addBindValue(false);
query.addBindValue(AllowLocationPreference::AskForLocationAccess);
query.addBindValue(NotificationsPreference::AskForNotificationsAccess);
query.exec();
}

Expand Down
Loading