Skip to content
Snippets Groups Projects
Commit a501c83a authored by Benoit Lavenier's avatar Benoit Lavenier
Browse files

[fix] Fix email subscription add/remove.

[enh] View subscriptions : group items by [type, provider]
parent b90ecd93
No related branches found
No related tags found
No related merge requests found
...@@ -1870,3 +1870,16 @@ div[dropzone] { ...@@ -1870,3 +1870,16 @@ div[dropzone] {
right: 16px; right: 16px;
} }
} }
/************************
Animation hide/show
*************************/
.animate-show-hide.ng-hide {
opacity: 0;
}
.animate-show-hide.ng-hide-add,
.animate-show-hide.ng-hide-remove {
transition: all linear 0.3s;
}
...@@ -15119,3 +15119,13 @@ div[dropzone] { ...@@ -15119,3 +15119,13 @@ div[dropzone] {
   
.popover-locked-outputs .item .badge { .popover-locked-outputs .item .badge {
right: 16px; } right: 16px; }
/************************
Animation hide/show
*************************/
.animate-show-hide.ng-hide {
opacity: 0; }
.animate-show-hide.ng-hide-add,
.animate-show-hide.ng-hide-remove {
transition: all linear 0.3s; }
This diff is collapsed.
...@@ -933,6 +933,8 @@ angular.module('cesium.wot.services', ['ngResource', 'ngApi', 'cesium.bma.servic ...@@ -933,6 +933,8 @@ angular.module('cesium.wot.services', ['ngResource', 'ngApi', 'cesium.bma.servic
extendAll = function(idties, pubkeyAttributeName, skipAddUid) { extendAll = function(idties, pubkeyAttributeName, skipAddUid) {
pubkeyAttributeName = pubkeyAttributeName || 'pubkey';
var jobs = []; var jobs = [];
if (!skipAddUid) jobs.push(BMA.wot.member.uids()); if (!skipAddUid) jobs.push(BMA.wot.member.uids());
......
...@@ -403,11 +403,11 @@ ...@@ -403,11 +403,11 @@
"BTN_ADD": "Ajouter un service", "BTN_ADD": "Ajouter un service",
"BTN_EDIT": "Gérer mes services", "BTN_EDIT": "Gérer mes services",
"NO_SUBSCRIPTION": "Aucun service utilisé", "NO_SUBSCRIPTION": "Aucun service utilisé",
"EMAIL": "Email de réception des notifications",
"SUBSCRIPTION_COUNT": "Services / Abonnements", "SUBSCRIPTION_COUNT": "Services / Abonnements",
"EDIT": { "EDIT": {
"TITLE": "Services en lignes", "TITLE": "Services en lignes",
"HELP_TEXT": "Gérer ici vos abonnements et autres services en ligne" "HELP_TEXT": "Gérer ici vos abonnements et autres services en ligne",
"PROVIDER": "Prestataire :"
}, },
"TYPE": { "TYPE": {
"ENUM": { "ENUM": {
...@@ -415,7 +415,9 @@ ...@@ -415,7 +415,9 @@
} }
}, },
"ERROR": { "ERROR": {
"LOAD_SUBSCRIPTIONS_FAILED": "Erreur lors du chargement des services en ligne" "LOAD_SUBSCRIPTIONS_FAILED": "Erreur lors du chargement des services en ligne",
"ADD_SUBSCRIPTION_FAILED": "Erreur de l'envoi de l'abonnement",
"UPDATE_SUBSCRIPTION_FAILED": "Erreur de la mise à jour de l'abonnement"
}, },
"MODAL_EMAIL": { "MODAL_EMAIL": {
"TITLE" : "Notification par email", "TITLE" : "Notification par email",
......
...@@ -21,7 +21,7 @@ angular.module('cesium.es.subscription.controllers', ['cesium.es.services']) ...@@ -21,7 +21,7 @@ angular.module('cesium.es.subscription.controllers', ['cesium.es.services'])
; ;
function ViewSubscriptionsController($scope, $rootScope, $translate, $ionicPopup, UIUtils, ModalUtils, csSettings, esSubscription) { function ViewSubscriptionsController($scope, $rootScope, csWot, UIUtils, ModalUtils, esSubscription) {
$scope.popupData = {}; // need for the node popup $scope.popupData = {}; // need for the node popup
$scope.search = { $scope.search = {
...@@ -54,12 +54,22 @@ function ViewSubscriptionsController($scope, $rootScope, $translate, $ionicPopup ...@@ -54,12 +54,22 @@ function ViewSubscriptionsController($scope, $rootScope, $translate, $ionicPopup
return esSubscription.record.load($rootScope.walletData.pubkey, $rootScope.walletData.keypair) return esSubscription.record.load($rootScope.walletData.pubkey, $rootScope.walletData.keypair)
.then(function(results) { .then(function(results) {
// Group by type // Group by type
results = _.groupBy((results || []), function(record) { var groups = _.groupBy((results || []), function (record) {
return record.type; return [record.type, record.recipient].join('|');
}); });
results = _.keys(results).reduce(function(res, type) { return _.keys(groups).reduce(function (res, key) {
return res.concat({type: type, items: results[type]}); var parts = key.split('|');
return res.concat({
type: parts[0],
recipient: parts[1],
items: groups[key]
});
}, []); }, []);
})
.then(function(results) {
return csWot.extendAll(results, 'recipient');
})
.then(function(results) {
// Display result // Display result
$scope.updateView(results); $scope.updateView(results);
}) })
...@@ -96,24 +106,22 @@ function ViewSubscriptionsController($scope, $rootScope, $translate, $ionicPopup ...@@ -96,24 +106,22 @@ function ViewSubscriptionsController($scope, $rootScope, $translate, $ionicPopup
if (type == 'email') { if (type == 'email') {
return $scope.showEmailModal(); return $scope.showEmailModal();
} }
else {
UIUtils.alert.notImplemented();
}
}) })
.then(function(content) { .then(function(record) {
UIUtils.loading.hide(); if (!record) return;
if (!content) return; UIUtils.loading.show();
esSubscription.record.add(record)
esSubscription.record.add(type, content) .then($scope.addToUI)
.then(function(record) { .then(function() {
$scope.search.results = $scope.search.results || [];
var subscriptions = _.findWhere($scope.search.results, {type: type});
if (!subscriptions) {
subscriptions = {type: type, items:[]};
$scope.search.results.push(subscriptions);
}
subscriptions.items.push(record);
$rootScope.walletData.subscriptions = $rootScope.walletData.subscriptions || {count: 0}; $rootScope.walletData.subscriptions = $rootScope.walletData.subscriptions || {count: 0};
$rootScope.walletData.subscriptions.count++; $rootScope.walletData.subscriptions.count++;
UIUtils.loading.hide();
$scope.updateView(); $scope.updateView();
}); })
.catch(UIUtils.onError('SUBSCRIPTION.ERROR.FAILED_ADD_SUBSCRIPTION'));
}); });
}; };
...@@ -121,21 +129,30 @@ function ViewSubscriptionsController($scope, $rootScope, $translate, $ionicPopup ...@@ -121,21 +129,30 @@ function ViewSubscriptionsController($scope, $rootScope, $translate, $ionicPopup
// get subscription parameters // get subscription parameters
var promise; var promise;
var oldRecord = angular.copy(record);
if (record.type == 'email') { if (record.type == 'email') {
promise = $scope.showEmailModal(record.content); promise = $scope.showEmailModal(record);
} }
if (!promise) return; if (!promise) return;
return promise return promise
.then(function(content) { .then(function() {
UIUtils.loading.hide(); if (!record) return;
if (!content) return; UIUtils.loading.show();
record.content = angular.copy(content); record.id = oldRecord.id;
record.recipient = record.content.recipient;
delete record.content.recipient;
return esSubscription.record.update(record) return esSubscription.record.update(record)
.then(function() { .then(function() {
// If recipient change, update in results
if (oldRecord.type != record.type ||
oldRecord.recipient != record.recipient) {
$scope.removeFromUI(oldRecord);
return $scope.addToUI(record);
}
})
.then(function() {
UIUtils.loading.hide();
$scope.updateView(); $scope.updateView();
}); })
.catch(UIUtils.onError('SUBSCRIPTION.ERROR.FAILED_ADD_SUBSCRIPTION'));
}); });
}; };
...@@ -143,11 +160,14 @@ function ViewSubscriptionsController($scope, $rootScope, $translate, $ionicPopup ...@@ -143,11 +160,14 @@ function ViewSubscriptionsController($scope, $rootScope, $translate, $ionicPopup
if (!record || !record.id) return; if (!record || !record.id) return;
esSubscription.record.remove(record.id); esSubscription.record.remove(record.id);
var subscriptions = _.findWhere($scope.search.results, {type: record.type}); $scope.removeFromUI(record);
};
$scope.removeFromUI = function(record) {
var subscriptions = _.findWhere($scope.search.results, {type: record.type, recipient: record.recipient});
var index = _.findIndex(subscriptions.items, record); var index = _.findIndex(subscriptions.items, record);
if (index >= 0) { if (index >= 0) {
subscriptions.items.splice(index, 1); subscriptions.items.splice(index, 1);
$rootScope.walletData.subscriptions.count--;
} }
if (!subscriptions.items.length) { if (!subscriptions.items.length) {
index = _.findIndex($scope.search.results, subscriptions); index = _.findIndex($scope.search.results, subscriptions);
...@@ -155,6 +175,25 @@ function ViewSubscriptionsController($scope, $rootScope, $translate, $ionicPopup ...@@ -155,6 +175,25 @@ function ViewSubscriptionsController($scope, $rootScope, $translate, $ionicPopup
} }
}; };
$scope.addToUI = function(record) {
$scope.search.results = $scope.search.results || [];
var subscriptions = _.findWhere($scope.search.results,
{type: record.type, recipient: record.recipient});
if (!subscriptions) {
subscriptions = {type: record.type, recipient: record.recipient, items: []};
return csWot.extendAll([subscriptions], 'recipient')
.then(function(){
subscriptions.items.push(record);
$scope.search.results.push(subscriptions);
return record;
});
}
subscriptions.items.push(record);
return $q.when(record);
};
/* -- modals -- */ /* -- modals -- */
$scope.showCategoryModal = function() { $scope.showCategoryModal = function() {
...@@ -180,25 +219,38 @@ function ViewSubscriptionsController($scope, $rootScope, $translate, $ionicPopup ...@@ -180,25 +219,38 @@ function ViewSubscriptionsController($scope, $rootScope, $translate, $ionicPopup
} }
function ModalEmailSubscriptionsController($scope, Modals, csSettings, esUser, parameters) { function ModalEmailSubscriptionsController($scope, Modals, csSettings, esUser, csWot, parameters) {
$scope.formData = parameters || {};
$scope.frequencies = [ $scope.frequencies = [
{id: "daily", label: "daily"}, {id: "daily", label: "daily"},
{id: "weekly", label: "weekly"} {id: "weekly", label: "weekly"}
]; ];
$scope.provider = {}; $scope.formData = parameters || {};
$scope.formData.content = $scope.formData.content || {};
$scope.formData.content.frequency = $scope.formData.content.frequency || $scope.frequencies[0].id; // set to first value
$scope.recipient = {};
$scope.$on('modal.shown', function() {
// Load recipient (uid, name, avatar...)
if ($scope.formData.recipient) {
$scope.recipient = {pubkey: $scope.formData.recipient};
return csWot.extendAll([$scope.recipient]);
}
});
// Submit // Submit
$scope.doSubmit = function() { $scope.doSubmit = function() {
$scope.form.$submitted = true; $scope.form.$submitted = true;
if (!$scope.form.$valid || !$scope.formData.email || !$scope.formData.frequency) return; if (!$scope.form.$valid || !$scope.formData.content.email || !$scope.formData.content.frequency) return;
var record = { var record = {
email: $scope.formData.email, type: 'email',
locale: csSettings.data.locale.id, recipient: $scope.formData.recipient,
frequency: $scope.formData.frequency, content: {
recipient: $scope.formData.recipient email: $scope.formData.content.email,
locale: csSettings.data.locale.id,
frequency: $scope.formData.content.frequency
}
}; };
$scope.closeModal(record); $scope.closeModal(record);
}; };
...@@ -218,10 +270,8 @@ function ModalEmailSubscriptionsController($scope, Modals, csSettings, esUser, p ...@@ -218,10 +270,8 @@ function ModalEmailSubscriptionsController($scope, Modals, csSettings, esUser, p
}) })
.then(function (peer) { .then(function (peer) {
if (peer) { if (peer) {
$scope.recipient = peer;
$scope.formData.recipient = peer.pubkey; $scope.formData.recipient = peer.pubkey;
$scope.peer = peer;
var eps = peer.getEndpoints(esUser.constants.ES_USER_API_ENDPOINT);
peer.bma = esUser.node.parseEndPoint(eps[0]);
} }
}); });
......
...@@ -79,16 +79,14 @@ angular.module('cesium.es.subscription.services', ['cesium.services', 'cesium.es ...@@ -79,16 +79,14 @@ angular.module('cesium.es.subscription.services', ['cesium.services', 'cesium.es
}); });
}; };
function addRecord(type, content) { function addRecord(record) {
if (!type || !content) { if (!record || !record.type || !record.content || !record.recipient) {
return $q.reject("Missing arguments 'type' or 'params'"); return $q.reject("Missing arguments 'record' or 'record.type' or 'record.content' or 'record.recipient'");
} }
var issuer = csWallet.data.pubkey; var issuer = csWallet.data.pubkey;
// TODO get the ES node pubkey
var recipient = 'G2CBgZBPLe6FSFUgpx2Jf1Aqsgta6iib3vmDRA1yLiqU';
var contentStr = JSON.stringify(content); var contentStr = JSON.stringify(record.content);
// Get a unique nonce // Get a unique nonce
return CryptoUtils.util.random_nonce() return CryptoUtils.util.random_nonce()
...@@ -96,21 +94,18 @@ angular.module('cesium.es.subscription.services', ['cesium.services', 'cesium.es ...@@ -96,21 +94,18 @@ angular.module('cesium.es.subscription.services', ['cesium.services', 'cesium.es
.then(function(nonce) { .then(function(nonce) {
return $q.all([ return $q.all([
esWallet.box.record.pack({issuer: issuer, issuerContent: contentStr}, csWallet.data.keypair, 'issuer', 'issuerContent', nonce), esWallet.box.record.pack({issuer: issuer, issuerContent: contentStr}, csWallet.data.keypair, 'issuer', 'issuerContent', nonce),
esWallet.box.record.pack({recipient: recipient, recipientContent: contentStr}, csWallet.data.keypair, 'recipient', 'recipientContent', nonce) esWallet.box.record.pack({recipient: record.recipient, recipientContent: contentStr}, csWallet.data.keypair, 'recipient', 'recipientContent', nonce)
]); ]);
}) })
// Merge encrypted record // Merge encrypted record
.then(function(res){ .then(function(res){
var record = angular.merge(res[0], res[1]); var encryptedRecord = angular.merge(res[0], res[1]);
record.type = type; encryptedRecord.type = record.type;
// Post subscription // Post subscription
return that.raw.add(record) return that.raw.add(encryptedRecord)
.then(function(id) { .then(function(id) {
record.id = id; record.id = id;
record.content = content;
delete record.issuerContent;
delete record.recipientContent;
return record; return record;
}); });
}) })
...@@ -136,10 +131,11 @@ angular.module('cesium.es.subscription.services', ['cesium.services', 'cesium.es ...@@ -136,10 +131,11 @@ angular.module('cesium.es.subscription.services', ['cesium.services', 'cesium.es
}) })
// Merge encrypted record // Merge encrypted record
.then(function(res){ .then(function(res){
var recordToSend = angular.merge(res[0], res[1]); var encryptedRecord = angular.merge(res[0], res[1]);
encryptedRecord.type = record.type;
// Post subscription // Post subscription
return that.raw.update(recordToSend, {id:record.id}) return that.raw.update(encryptedRecord, {id:record.id})
.then(function() { .then(function() {
return record; // return original record return record; // return original record
}); });
......
...@@ -39,25 +39,9 @@ ...@@ -39,25 +39,9 @@
<div class="col list {{::motion.ionListClass}} item-border-large"> <div class="col list {{::motion.ionListClass}} item-border-large">
<ng-repeat ng-repeat="subscriptions in search.results"> <!-- emails -->
<ng-repeat ng-repeat="subscriptions in search.results | filter: { type: 'email' }"
<!-- emails --> ng-include="'plugins/es/templates/subscription/item_' + subscriptions.type.toLowerCase() + '_subscription.html'">>
<div class="item item-thumbnail-left" ng-if="subscriptions.type == 'email'">
<i class="item-image icon ion-email"></i>
<div class="input-label">
{{'SUBSCRIPTION.TYPE.ENUM.' + subscriptions.type.toUpperCase() | translate}}
</div>
<div class="item-note">
<span ng-repeat="item in subscriptions.items">
{{item.recipient | formatPubkey}} <i class="ion-arrow-right-a"></i>
{{item.content.email}}
<a class="icon ion-close assertive padding-left" ng-click="deleteSubscription(item)"></a>
<a class="icon ion-edit gray padding-left" ng-click="editSubscription(item)"></a>
<br/>
</span>
</div>
</div>
</ng-repeat> </ng-repeat>
</div> </div>
......
<div class="item item-thumbnail-left">
<i class="item-image icon ion-email"></i>
<h3>
{{'SUBSCRIPTION.TYPE.ENUM.' + subscriptions.type.toUpperCase() | translate}}
</h3>
<h4 class="gray">
{{'SUBSCRIPTION.EDIT.PROVIDER'|translate}}
<a ui-sref="app.wot_identity({pubkey: subscriptions.recipient, uid: subscriptions.uid})">
<span class="positive" ng-if="subscriptions.uid">
<i class="ion-person"></i>
{{subscriptions.name||subscriptions.uid}}
</span>
<span class="gray" ng-if="!subscriptions.uid">
<i class="ion-key"></i>
{{subscriptions.recipient | formatPubkey}}
</span>
</a>
</h4>
<div class="item-note text-right">
<span ng-repeat="item in subscriptions.items">
{{item.content.email}}
<a class="icon ion-close assertive padding-left" ng-click="deleteSubscription(item)"></a>
<a class="icon ion-edit gray padding-left" ng-click="editSubscription(item)"></a>
<br/>
</span>
</div>
</div>
...@@ -23,16 +23,16 @@ ...@@ -23,16 +23,16 @@
<!-- email --> <!-- email -->
<label class="item item-input" <label class="item item-input"
ng-class="{'item-input-error': form.$submitted && form.email.$invalid}"> ng-class="{'item-input-error': form.$submitted && (form.email.$invalid || form.email.$error)}">
<span class="input-label" translate>SUBSCRIPTION.MODAL_EMAIL.EMAIL_LABEL</span> <span class="input-label" translate>SUBSCRIPTION.MODAL_EMAIL.EMAIL_LABEL</span>
<input name="email" type="text" placeholder="{{'SUBSCRIPTION.MODAL_EMAIL.EMAIL_HELP' | translate}}" <input name="email" type="text" placeholder="{{'SUBSCRIPTION.MODAL_EMAIL.EMAIL_HELP' | translate}}"
ng-model="formData.email" ng-model="formData.content.email"
ng-minlength="3" ng-minlength="3"
required required
email> email>
</label> </label>
<div class="form-errors" <div class="form-errors"
ng-if="form.$submitted && form.email.$invalid" ng-if="form.$submitted && (form.email.$invalid || form.email.$error)"
ng-messages="form.email.$error"> ng-messages="form.email.$error">
<div class="form-error" ng-message="minlength"> <div class="form-error" ng-message="minlength">
<span translate="ERROR.FIELD_TOO_SHORT"></span> <span translate="ERROR.FIELD_TOO_SHORT"></span>
...@@ -44,15 +44,15 @@ ...@@ -44,15 +44,15 @@
<!-- Frequency --> <!-- Frequency -->
<label class="item item-input item-select" <label class="item item-input item-select"
ng-class="{'item-input-error': form.$submitted && !formData.frequency}"> ng-class="{'item-input-error': form.$submitted && !formData.content.frequency}">
<span class="input-label" translate>SUBSCRIPTION.MODAL_EMAIL.FREQUENCY_LABEL</span> <span class="input-label" translate>SUBSCRIPTION.MODAL_EMAIL.FREQUENCY_LABEL</span>
<select ng-model="formData.frequency" style="height: 46px;margin-top: 1px;"> <select name="frequency" ng-model="formData.content.frequency" style="height: 46px;margin-top: 1px;">
<option value="weekly" translate>SUBSCRIPTION.MODAL_EMAIL.FREQUENCY_WEEKLY</option> <option value="weekly" translate>SUBSCRIPTION.MODAL_EMAIL.FREQUENCY_WEEKLY</option>
<option value="daily" translate>SUBSCRIPTION.MODAL_EMAIL.FREQUENCY_DAILY</option> <option value="daily" translate>SUBSCRIPTION.MODAL_EMAIL.FREQUENCY_DAILY</option>
</select> </select>
</label> </label>
<div class="form-errors" <div class="form-errors"
ng-if="form.$submitted && !formData.frequency"> ng-if="form.$submitted && !formData.content.frequency">
<div class="form-error"> <div class="form-error">
<span translate="ERROR.FIELD_REQUIRED"></span> <span translate="ERROR.FIELD_REQUIRED"></span>
</div> </div>
...@@ -61,10 +61,14 @@ ...@@ -61,10 +61,14 @@
<!-- Recipient (service provider) --> <!-- Recipient (service provider) -->
<a class="item item-input item-icon-right gray ink" <a class="item item-input item-icon-right gray ink"
ng-class="{'item-input-error': form.$submitted && !formData.recipient}" ng-class="{'item-input-error': form.$submitted && !formData.recipient}"
ng-click="showNetworkLookup()"> ng-click="showNetworkLookup()"
style="height: 67px;">
<span class="input-label" translate>SUBSCRIPTION.MODAL_EMAIL.PROVIDER</span> <span class="input-label" translate>SUBSCRIPTION.MODAL_EMAIL.PROVIDER</span>
<span class="badge badge-positive" ng-if="peer"> <span class="badge badge-positive animate-fade-in animate-show-hide ng-hide" ng-show="recipient && (recipient.name||recipient.uid)">
{{peer.getServer()}} {{recipient.name||recipient.uid}}
</span>
<span class="badge badge-secondary animate-fade-in animate-show-hide ng-hide" ng-show="formData.recipient">
<i class="ion-key"></i> {{formData.recipient | formatPubkey}}
</span> </span>
<i class="gray icon ion-ios-arrow-right"></i> <i class="gray icon ion-ios-arrow-right"></i>
</a> </a>
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment