From 7ed0d32e3fdde07833418a77256c92637585d4b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Espino?= Date: Thu, 30 Mar 2017 16:11:57 +0200 Subject: [PATCH 1/2] Working on live-notifications --- app/coffee/modules/events.coffee | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/app/coffee/modules/events.coffee b/app/coffee/modules/events.coffee index 6202289b..4e3d4874 100644 --- a/app/coffee/modules/events.coffee +++ b/app/coffee/modules/events.coffee @@ -87,6 +87,35 @@ class EventsService @liveAnnouncementService.show(data.title, data.desc) @rootScope.$digest() + liveNotifications: -> + userId = @.auth.userData.get('id') + + subscribe = () => + @.subscribe null, "live_notifications.#{userId}", (data) => + notification = new Notification(data.title, { + icon: "/#{window._version}/images/favicon.png", + body: data.body, + tag: data.id + }) + notification.onshow = () => + if data.timeout and data.timeout > 0 + setTimeout => + notification.close() + , + data.timeout + + if data.url + notification.onclick = () => + window.open data.url + if !Notification + console.log("This browser does not support desktop notification") + else if Notification.permission == "granted" + subscribe() + else if Notification.permission != 'denied' + Notification.requestPermission (permission) => + if (permission == "granted") + subscribe() + ########################################### # Heartbeat (Ping - Pong) ########################################### @@ -216,6 +245,7 @@ class EventsService @.sendMessage(message) @.startHeartBeatMessages() @.notifications() + @.liveNotifications() onMessage: (event) -> @.log.debug "WebSocket message received: #{event.data}" From 39f806b0a31cc8aa0762db9f240366947b22a601 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Espino?= Date: Fri, 31 Mar 2017 15:13:01 +0200 Subject: [PATCH 2/2] Adding live notifications configuration --- app/coffee/app.coffee | 2 + app/coffee/modules/base.coffee | 1 + .../user-settings/live-notifications.coffee | 155 ++++++++++++++++++ app/locales/taiga/locale-en.json | 5 +- app/locales/taiga/locale-es.json | 2 +- .../projects-resource.service.coffee | 1 + .../includes/modules/user-settings-menu.jade | 3 + .../live-notifications-table.jade | 12 ++ app/partials/user/live-notifications.jade | 19 +++ 9 files changed, 198 insertions(+), 2 deletions(-) create mode 100644 app/coffee/modules/user-settings/live-notifications.coffee create mode 100644 app/partials/includes/modules/user-settings/live-notifications-table.jade create mode 100644 app/partials/user/live-notifications.jade diff --git a/app/coffee/app.coffee b/app/coffee/app.coffee index 4b3af7ed..6a5470a4 100644 --- a/app/coffee/app.coffee +++ b/app/coffee/app.coffee @@ -450,6 +450,8 @@ configure = ($routeProvider, $locationProvider, $httpProvider, $provide, $tgEven {templateUrl: "user/user-change-password.html"}) $routeProvider.when("/user-settings/mail-notifications", {templateUrl: "user/mail-notifications.html"}) + $routeProvider.when("/user-settings/live-notifications", + {templateUrl: "user/live-notifications.html"}) $routeProvider.when("/change-email/:email_token", {templateUrl: "user/change-email.html"}) $routeProvider.when("/cancel-account/:cancel_token", diff --git a/app/coffee/modules/base.coffee b/app/coffee/modules/base.coffee index ce0ecdca..c1cde42c 100644 --- a/app/coffee/modules/base.coffee +++ b/app/coffee/modules/base.coffee @@ -124,6 +124,7 @@ urls = { "user-settings-user-change-password": "/user-settings/user-change-password" "user-settings-user-avatar": "/user-settings/user-avatar" "user-settings-mail-notifications": "/user-settings/mail-notifications" + "user-settings-live-notifications": "/user-settings/live-notifications" "user-settings-contrib": "/user-settings/contrib/:plugin" } diff --git a/app/coffee/modules/user-settings/live-notifications.coffee b/app/coffee/modules/user-settings/live-notifications.coffee new file mode 100644 index 00000000..7411dd46 --- /dev/null +++ b/app/coffee/modules/user-settings/live-notifications.coffee @@ -0,0 +1,155 @@ +### +# Copyright (C) 2014-2017 Andrey Antukh +# Copyright (C) 2014-2017 Jesús Espino Garcia +# Copyright (C) 2014-2017 David Barragán Merino +# Copyright (C) 2014-2017 Alejandro Alonso +# Copyright (C) 2014-2017 Juan Francisco Alcántara +# Copyright (C) 2014-2017 Xavi Julian +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +# File: modules/user-settings/live-notifications.coffee +### + +taiga = @.taiga +mixOf = @.taiga.mixOf +bindOnce = @.taiga.bindOnce + +module = angular.module("taigaUserSettings") + + +############################################################################# +## User settings Controller +############################################################################# + +class UserLiveNotificationsController extends mixOf(taiga.Controller, taiga.PageMixin) + @.$inject = [ + "$scope", + "$rootScope", + "$tgRepo", + "$tgConfirm", + "$tgResources", + "$routeParams", + "$q", + "$tgLocation", + "$tgNavUrls", + "$tgAuth", + "tgErrorHandlingService" + ] + + constructor: (@scope, @rootscope, @repo, @confirm, @rs, @params, @q, @location, @navUrls, @auth, @errorHandlingService) -> + @scope.sectionName = "USER_SETTINGS.NOTIFICATIONS.LIVE_SECTION_NAME" + @scope.user = @auth.getUser() + promise = @.loadInitialData() + promise.then null, @.onInitialDataError.bind(@) + + loadInitialData: -> + return @rs.notifyPolicies.list().then (notifyPolicies) => + @scope.notifyPolicies = notifyPolicies + return notifyPolicies + +module.controller("UserLiveNotificationsController", UserLiveNotificationsController) + + +############################################################################# +## User Notifications Directive +############################################################################# + +UserLiveNotificationsDirective = () -> + link = ($scope, $el, $attrs) -> + $scope.$on "$destroy", -> + $el.off() + + return {link:link} + +module.directive("tgUserLiveNotifications", UserLiveNotificationsDirective) + + +############################################################################# +## User Notifications List Directive +############################################################################# + +UserLiveNotificationsListDirective = ($repo, $confirm, $compile) -> + template = _.template(""" + <% _.each(notifyPolicies, function (notifyPolicy, index) { %> +
+
<%- notifyPolicy.project_name %>
+
+
+ checked="checked"<% } %>/> + +
+
+
+
+ checked="checked"<% } %> /> + +
+
+
+
+ checked="checked"<% } %> /> + +
+
+
+ <% }) %> + """) + + link = ($scope, $el, $attrs) -> + render = -> + $el.off() + + ctx = {notifyPolicies: $scope.notifyPolicies} + html = template(ctx) + + $el.html($compile(html)($scope)) + + $el.on "change", "input[type=radio]", (event) -> + target = angular.element(event.currentTarget) + + policyIndex = target.parents(".policy-table-row").data('index') + policy = $scope.notifyPolicies[policyIndex] + prev_level = policy.live_notify_level + policy.live_notify_level = parseInt(target.val(), 10) + + onSuccess = -> + $confirm.notify("success") + + onError = -> + $confirm.notify("error") + target.parents(".policy-table-row") + .find("input[value=#{prev_level}]") + .prop("checked", true) + + $repo.save(policy).then(onSuccess, onError) + + $scope.$on "$destroy", -> + $el.off() + + bindOnce($scope, $attrs.ngModel, render) + + return {link:link} + +module.directive("tgUserLiveNotificationsList", ["$tgRepo", "$tgConfirm", "$compile", + UserLiveNotificationsListDirective]) diff --git a/app/locales/taiga/locale-en.json b/app/locales/taiga/locale-en.json index a9636202..bcf22303 100644 --- a/app/locales/taiga/locale-en.json +++ b/app/locales/taiga/locale-en.json @@ -1343,6 +1343,7 @@ "SAVED": "Our Oompa Loompas saved all your changes!", "CLOSE": "Close notification", "MAIL": "Notifications By Mail", + "DESKTOP": "Messages by desktop notifications", "ASK_DELETE": "Are you sure you want to delete?" }, "CANCEL_ACCOUNT": { @@ -1458,9 +1459,11 @@ "SECTION_TITLE": "User Settings", "USER_PROFILE": "User profile", "CHANGE_PASSWORD": "Change password", - "EMAIL_NOTIFICATIONS": "Email notifications" + "EMAIL_NOTIFICATIONS": "Email notifications", + "DESKTOP_NOTIFICATIONS": "Desktop notifications" }, "NOTIFICATIONS": { + "LIVE_SECTION_NAME": "Desktop Notifications", "SECTION_NAME": "Email Notifications", "COLUMN_PROJECT": "Project", "COLUMN_RECEIVE_ALL": "Receive All", diff --git a/app/locales/taiga/locale-es.json b/app/locales/taiga/locale-es.json index be5af55a..0d8507fe 100644 --- a/app/locales/taiga/locale-es.json +++ b/app/locales/taiga/locale-es.json @@ -1670,4 +1670,4 @@ "RESULTS": "Resultados de búsqueda" } } -} \ No newline at end of file +} diff --git a/app/modules/resources/projects-resource.service.coffee b/app/modules/resources/projects-resource.service.coffee index 978593f4..03a57ad4 100644 --- a/app/modules/resources/projects-resource.service.coffee +++ b/app/modules/resources/projects-resource.service.coffee @@ -122,6 +122,7 @@ Resource = (urlsService, http, paginateResponseService) -> service.watchProject = (projectId, notifyLevel) -> data = { notify_level: notifyLevel + live_notify_level: notifyLevel } url = urlsService.resolve("project-watch", projectId) return http.post(url, data) diff --git a/app/partials/includes/modules/user-settings-menu.jade b/app/partials/includes/modules/user-settings-menu.jade index 05a7cb7c..070e6ac2 100644 --- a/app/partials/includes/modules/user-settings-menu.jade +++ b/app/partials/includes/modules/user-settings-menu.jade @@ -10,6 +10,9 @@ section.admin-menu li#usersettingsmenu-mail-notifications a(href="", tg-nav="user-settings-mail-notifications", title="{{ 'USER_SETTINGS.MENU.EMAIL_NOTIFICATIONS' | translate }}") span.title(translate="USER_SETTINGS.MENU.EMAIL_NOTIFICATIONS") + li#usersettingsmenu-live-notifications + a(href="", tg-nav="user-settings-live-notifications", title="{{ 'USER_SETTINGS.MENU.DESKTOP_NOTIFICATIONS' | translate }}") + span.title(translate="USER_SETTINGS.MENU.DESKTOP_NOTIFICATIONS") li#usersettings-contrib(ng-repeat="plugin in userSettingsPlugins") a( href="" diff --git a/app/partials/includes/modules/user-settings/live-notifications-table.jade b/app/partials/includes/modules/user-settings/live-notifications-table.jade new file mode 100644 index 00000000..077a2f79 --- /dev/null +++ b/app/partials/includes/modules/user-settings/live-notifications-table.jade @@ -0,0 +1,12 @@ +section.policy-table + div.policy-table-header + div.policy-table-row + div.policy-table-project + span(translate="USER_SETTINGS.NOTIFICATIONS.COLUMN_PROJECT") + div.policy-table-all + span(translate="USER_SETTINGS.NOTIFICATIONS.COLUMN_RECEIVE_ALL") + div.policy-table-involved + span(translate="USER_SETTINGS.NOTIFICATIONS.COLUMN_ONLY_INVOLVED") + div.policy-table-none + span(translate="USER_SETTINGS.NOTIFICATIONS.COLUMN_NO_NOTIFICATIONS") + div.policy-table-body(tg-user-live-notifications-list, ng-model="notifyPolicies") diff --git a/app/partials/user/live-notifications.jade b/app/partials/user/live-notifications.jade new file mode 100644 index 00000000..5d357c68 --- /dev/null +++ b/app/partials/user/live-notifications.jade @@ -0,0 +1,19 @@ +doctype html + +div.wrapper( + tg-user-live-notifications + ng-controller="UserLiveNotificationsController as ctrl", + ng-init="section='live-notifications'" +) + + sidebar.menu-secondary.sidebar.settings-nav(tg-user-settings-navigation="live-notifications") + include ../includes/modules/user-settings-menu + + section.main.admin-common + header + h1 + span.green {{sectionName | translate}} + + p.total(translate="NOTIFICATION.DESKTOP") + + include ../includes/modules/user-settings/live-notifications-table