diff --git a/app/config.json b/app/config.json index 92cf4d864e963b6b17122fd13a59290cbdd21d7a..3d9059a598f71dbc6490b8314ed45bf76c4a49b8 100644 --- a/app/config.json +++ b/app/config.json @@ -16,8 +16,8 @@ "installDocUrl": "https://github.com/duniter/duniter/blob/master/doc/install-a-node.md" }, "node": { - "host": "test-net.duniter.fr", - "port": "9201" + "host": "cgeek.fr", + "port": "9330" }, "plugins":{ "es": { @@ -89,9 +89,9 @@ }, "plugins":{ "es": { - "enable": false, + "enable": true, "askEnable": true, - "host": "data.duniter.fr", + "host": "data.le-sou.org", "port": "80" } } diff --git a/www/i18n/locale-en.json b/www/i18n/locale-en.json index 8497747fa705b4caffeeb869290645bb91d29243..8f3000ac33e28bc5f6c35f91d851029ec6b5c42d 100644 --- a/www/i18n/locale-en.json +++ b/www/i18n/locale-en.json @@ -326,7 +326,10 @@ "INVALID_USER_ID": "Field 'pseudonym' must not contains spaces or special characters.", "INVALID_COMMENT": "Field 'reference' has a bad format.", "INVALID_PUBKEY": "Public key has a bad format.", - "IDENTITY_SANDBOX_FULL": "Could not register, because node's sandbox is full.<br/><br/>Please retry later or choose another Duniter node (in <b>Settings</b>)." + "IDENTITY_INVALID_BLOCK_HASH": "This membership application is no longer valid (because it references a block that network nodes are cancelled): the person must renew its application for membership <b>before</b> being certified.", + "IDENTITY_SANDBOX_FULL": "Could not register, because node's sandbox is full.<br/><br/>Please retry later or choose another Duniter node (in <b>Settings</b>).", + "WOT_PENDING_INVALID_BLOCK_HASH": "Membership not valid.", + "WALLET_INVALID_BLOCK_HASH": "Your membership application is no longer valid (because it references a block that network nodes are cancelled).<br/>You must <a ng-click=\"doQuickFix('renew')\">renew your application for membership</a> to fix this issue." }, "INFO": { "POPUP_TITLE": "Information", @@ -342,8 +345,10 @@ "CERTIFY_RULES": "<b>Security warning:</b><br/><br/><b class=\"assertive\">Don't certify an account</b> if you believe that: <ul><li>1.) the issuers identity might be faked.<li>2.) the issuer already has another certified account.<li>3.) the issuer purposely or carelessly violates rule 1 or 2 (he certifies faked or double accounts).</ul></small><br/>Are you sure you want to certify this identity ?", "TRANSFER": "<b>Transfer summary:</b><br/><br/><ul><li> - From: <b>{{from}}</b></li><li> - To: <b>{{to}}</b></li><li> - Amount: <b>{{amount}} {{unit}}</b></li><li> - Comment: <i>{{comment}}</i></li></ul><br/><b>Are-you sure you want to do this transfer ?</b>", "MEMBERSHIP_OUT": "<b>Warning</b>:<br/>You are going to terminate your membership. This operation is irreversible<br/></br/><b>Are you sure you want to continue ?</b>", + "LOGIN_UNUSED_WALLET_TITLE": "Typing error ?", "LOGIN_UNUSED_WALLET": "You are logged into an account that seems <b>inactive</b>.<br/><br/>If this account does not match yours, it's probably a <b>typing error</b> when sign in.<br/><br/><b>Would you still continue with this account?</b>", - "LOGIN_UNUSED_WALLET_TITLE": "Typing error ?" + "FIX_MEMBERSHIP": "Your application for membership will be sent.<br/></br/><b>Are you sure ?</b>", + "RENEW_MEMBERSHIP": "Your membership will be renewed.<br/></br/><b>Are you sure ?</b>" }, "HELP": { "TITLE": "Online help", diff --git a/www/i18n/locale-fr-FR.json b/www/i18n/locale-fr-FR.json index 863a030e55c779520b38955451d68a63a716a299..25f0081e612ddededa94da427cec0a200e684509 100644 --- a/www/i18n/locale-fr-FR.json +++ b/www/i18n/locale-fr-FR.json @@ -225,12 +225,12 @@ "WAITING_MEMBERSHIP": "Demande d'adhésion envoyée. En attente d'acceptation.", "WAITING_CERTIFICATIONS": "Vous devez obtenir {{needCertificationCount}} certification(s) pour devenir membre.", "WILL_MISSING_CERTIFICATIONS": "Vous allez bientôt manquer de certifications", - "WILL_NEED_RENEW_MEMBERSHIP": "Votre adhésion comme membre va expirer {{membershipExpiresIn|formatDuration}}", + "WILL_NEED_RENEW_MEMBERSHIP": "Votre adhésion comme membre va expirer {{membershipExpiresIn|formatDuration}}. Pensez <a ng-click=\"doQuickFix('renew')\">renouveller votre adhésion</a> d'ici là .", "CERTIFICATION_COUNT": "Certifications reçues", "SIG_STOCK": "Certifications envoyées", "BTN_RECEIVE_MONEY": "Encaisser", "BTN_MEMBERSHIP_IN": "Devenir membre...", - "BTN_MEMBERSHIP_RENEW": "Renouveller l'adhésion comme membre", + "BTN_MEMBERSHIP_RENEW": "Renouveller l'adhésion", "BTN_MEMBERSHIP_OUT": "Arrêter l'adhésion", "BTN_SEND_IDENTITY": "Publier son identitié...", "BTN_SHOW_DETAILS": "Afficher la clé publique", @@ -326,7 +326,10 @@ "INVALID_USER_ID": "Le champ 'pseudonyme' ne doit contenir ni espace ni caractère spécial ou accentué.", "INVALID_COMMENT": "Le champ 'référence' ne doit pas contenir de caractères accentués.", "INVALID_PUBKEY": "La clé publique n'a pas le format attendu.", - "IDENTITY_SANDBOX_FULL": "Le noeud Duniter utilisé par Cesium ne peut plus recevoir de nouvelles identités, car sa file d'attente est pleine.<br/><br/>Veuillez réessayer ultérieurement ou changer de noeud (via le menu <b>Paramètres</b>)." + "IDENTITY_INVALID_BLOCK_HASH": "Cette demande d'adhésion n'est plus valide (car elle référence un bloc que les noeuds du réseau ont annulé) : cette personne doit renouveller sa demande d'adhésion <b>avant</b> d'être certifiée.", + "IDENTITY_SANDBOX_FULL": "Le noeud Duniter utilisé par Cesium ne peut plus recevoir de nouvelles identités, car sa file d'attente est pleine.<br/><br/>Veuillez réessayer ultérieurement ou changer de noeud (via le menu <b>Paramètres</b>).", + "WOT_PENDING_INVALID_BLOCK_HASH": "Adhésion non valide.", + "WALLET_INVALID_BLOCK_HASH": "Votre demande d'adhésion n'est plus valide (car elle référence un bloc que les noeuds du réseau ont annulé).<br/>Vous devez <a ng-click=\"doQuickFix('renew')\">envoyer une nouvelle demande</a> pour résoudre ce problème." }, "INFO": { "POPUP_TITLE": "Information", @@ -342,8 +345,10 @@ "CERTIFY_RULES": "<b>Avertissement de sécurité :</b><br/><br/><b class=\"assertive\">Ne pas certifier</b> un compte si vous pensez que :<ul><li>1.) il ne correspond pas à une personne physique vivante.<li>2.) son propriétaire possède un autre compte déjà certifié.<li>3.) son propriétaire viole (volontairement ou non) la règle 1 ou 2 (par exemple en certifiant des comptes factices ou en double).</ul><br/><b>Etes-vous sûr de vouloir néanmoins certifier cette identité ?</b>", "TRANSFER": "<b>Récapitulatif du virement</b> :<br/><br/><ul><li> - De : {{from}}</li><li> - A : <b>{{to}}</b></li><li> - Montant : <b>{{amount}} {{unit}}</b></li><li> - Commentaire : <i>{{comment}}</i></li></ul><br/><b>Etes-vous sûr de vouloir effectuer ce virement ?</b>", "MEMBERSHIP_OUT": "<b>Avertissement</b> :<br/>Vous allez résilier votre adhésion comme membre. Cette opération est <b>irréversible</b>.<br/></br/><b>Etes-vous sûr de vouloir continuer ?</b>", + "LOGIN_UNUSED_WALLET_TITLE": "Erreur de saisie ?", "LOGIN_UNUSED_WALLET": "Vous êtes connecté sur un compte qui parait <b>inactif</b>.<br/><br/>Si ce compte ne correspond pas au votre, il s'agit probablement d'une <b>erreur de saisie</b> de vos identifiants de connexion.<br/></br/><b>Voulez-vous néanmoins continuer avec ce compte ?</b>", - "LOGIN_UNUSED_WALLET_TITLE": "Erreur de saisie ?" + "FIX_MEMBERSHIP": "Votre demande d'adhésion comme membre va être renvoyée.<br/></br/><b>Etes-vous sûr ?</b>", + "RENEW_MEMBERSHIP": "Votre adhésion comme membre va être renouvellée.<br/></br/><b>Etes-vous sûr ?</b>" }, "HELP": { "TITLE": "Aide en ligne", diff --git a/www/js/config.js b/www/js/config.js index 86f2ec011d6b04b482d9d7122509e40d6562e800..589b5de0cb241ed6ae528d0a30489955abeaaf75 100644 --- a/www/js/config.js +++ b/www/js/config.js @@ -10,10 +10,11 @@ angular.module("cesium.config", []) .constant("csConfig", { "cacheTimeMs": 60000, - "fallbackLanguage": "en", - "rememberMe": false, + "fallbackLanguage": "fr-FR", + "defaultLanguage": "fr-FR", + "rememberMe": true, "showUDHistory": false, - "timeout": 10000, + "timeout": 6000, "timeWarningExpireMembership": 5184000, "timeWarningExpire": 7776000, "useLocalStorage": true, @@ -22,22 +23,25 @@ angular.module("cesium.config", []) "expertMode": false, "helptip": { "enable": true, - "installDocUrl": "https://github.com/duniter/duniter/blob/master/doc/install-a-node.md" + "installDocUrl": { + "fr-FR": "http://www.le-sou.org/devenir-noeud/", + "en": "https://github.com/duniter/duniter/blob/master/doc/install-a-node.md" + } }, "node": { - "host": "test-net.duniter.fr", - "port": "9201" + "host": "duniter.le-sou.org", + "port": "9600" }, "plugins": { "es": { "enable": true, - "askEnable": false, - "host": "data.duniter.fr", + "askEnable": true, + "host": "data.le-sou.org", "port": "80" } }, "version": "0.4.5", - "build": "2016-10-28T20:15:26.201Z", + "build": "2016-10-31T21:27:03.616Z", "newIssueUrl": "https://github.com/duniter/cesium/issues/new?labels=bug" }) diff --git a/www/js/controllers/currency-charts-controllers.js b/www/js/controllers/currency-charts-controllers.js index 2a5b965b14785c7ffe05a73a0ebaf4a81ba9b236..3e9f4f43e97a6b743b47acf53595c49e46d0d188 100644 --- a/www/js/controllers/currency-charts-controllers.js +++ b/www/js/controllers/currency-charts-controllers.js @@ -29,7 +29,7 @@ angular.module('cesium.currency-charts.controllers', ['cesium.services']) function CurrencyUdController($scope, BMA, $q) { 'ngInject'; - $scope.$on('$ionicView.enter', function(e, $state) { + $scope.$on('$ionicView.enter', function() { $scope.loadUds() .then(function (dataXY) { // TODO: plot diff --git a/www/js/controllers/currency-controllers.js b/www/js/controllers/currency-controllers.js index 7446a9c88714202e194629dad9a77a72bae4e2b3..882481b384aa6904d9a111b2eea848d17e3a07af 100644 --- a/www/js/controllers/currency-controllers.js +++ b/www/js/controllers/currency-controllers.js @@ -109,12 +109,12 @@ function CurrencyViewController($scope, $q, $translate, $timeout, BMA, UIUtils, $scope.Nprev = 0; $scope.screen = UIUtils.screen; - $scope.$on('$ionicView.enter', function(e, $state) { + $scope.$on('$ionicView.enter', function(e, state) { $translate(['COMMON.DATE_PATTERN']) .then(function($translations) { $scope.datePattern = $translations['COMMON.DATE_PATTERN']; - if ($state.stateParams && $state.stateParams.name) { // Load by name - csCurrency.searchByName($state.stateParams.name) + if (state.stateParams && state.stateParams.name) { // Load by name + csCurrency.searchByName(state.stateParams.name) .then(function(currency){ $scope.load(currency); }); diff --git a/www/js/controllers/peer-controllers.js b/www/js/controllers/peer-controllers.js index 0c8dff2430d3e3107d0d28d67027901a3acda329..f7c009f12cd2c20b4cbd8b0ada752d85fcdf7f03 100644 --- a/www/js/controllers/peer-controllers.js +++ b/www/js/controllers/peer-controllers.js @@ -2,16 +2,16 @@ function PeerController($scope, $rootScope, $ionicSlideBoxDelegate, $ionicModal, BMA, $controller) { 'ngInject'; - $scope.$on('$ionicView.enter', function(e, $state) { + $scope.$on('$ionicView.enter', function(e, state) { if (!$rootScope.memberUidsByPubkeys) { BMA.wot.member.uids() .then(function(uids){ $rootScope.memberUidsByPubkeys = uids; - $scope.showPeer($state.stateParams.server); + $scope.showPeer(state.stateParams.server); }); } else { - $scope.showPeer($state.stateParams.server); + $scope.showPeer(state.stateParams.server); } }); diff --git a/www/js/controllers/settings-controllers.js b/www/js/controllers/settings-controllers.js index 15fbfc08c7fe36a8242102746787cedc3cb682a3..b5b632778d9df8d52c48cb36c6760620a7f92ec1 100644 --- a/www/js/controllers/settings-controllers.js +++ b/www/js/controllers/settings-controllers.js @@ -27,7 +27,7 @@ function SettingsController($scope, $q, $ionicPopup, $timeout, $translate, csHtt $scope.popupData = {}; // need for the node popup $scope.loading = true; - $scope.$on('$ionicView.enter', function(e) { + $scope.$on('$ionicView.enter', function() { $scope.load(); }); diff --git a/www/js/controllers/transfer-controllers.js b/www/js/controllers/transfer-controllers.js index 301309ee831ca48f81865370f4ee5a04e13fde05..58164acad7df21952093be34a6b64e21f3f753ba 100644 --- a/www/js/controllers/transfer-controllers.js +++ b/www/js/controllers/transfer-controllers.js @@ -49,11 +49,11 @@ function TransferController($scope, $rootScope, $state, BMA, Wallet, UIUtils, $t TransferModalController.call(this, $scope, $rootScope, $state, BMA, Wallet, UIUtils, $timeout, Device, $ionicPopover, $translate, $filter, $q, Modals, csSettings); - $scope.$on('$ionicView.enter', function(e, $state) { - if (!!$state.stateParams && !!$state.stateParams.pubkey) { - $scope.formData.destPub = $state.stateParams.pubkey; - if (!!$state.stateParams.uid) { - $scope.destUid = $state.stateParams.uid; + $scope.$on('$ionicView.enter', function(e, state) { + if (!!state.stateParams && !!state.stateParams.pubkey) { + $scope.formData.destPub = state.stateParams.pubkey; + if (!!state.stateParams.uid) { + $scope.destUid = state.stateParams.uid; $scope.destPub = ''; } else { diff --git a/www/js/controllers/wallet-controllers.js b/www/js/controllers/wallet-controllers.js index 856db2320345560aed082d380b887bf2d60f1110..5c496867df65bd0538b7ea92e25a07dac374f58f 100644 --- a/www/js/controllers/wallet-controllers.js +++ b/www/js/controllers/wallet-controllers.js @@ -155,11 +155,11 @@ function WalletController($scope, $rootScope, $q, $ionicPopup, $timeout, $state, $scope.self= function() { $scope.hideActionsPopover(); - $scope.showUidPopup() + return $scope.showUidPopup() .then(function(uid) { UIUtils.loading.show(); - Wallet.self(uid) + return Wallet.self(uid) .then(function() { $scope.updateView(); UIUtils.loading.hide(); @@ -173,12 +173,8 @@ function WalletController($scope, $rootScope, $q, $ionicPopup, $timeout, $state, }); }; - // Send membership IN - $scope.membershipIn= function() { - $scope.hideActionsPopover(); - - var doMembershipIn = function(retryCount) { - Wallet.membership.inside() + $scope.doMembershipIn = function(retryCount) { + return Wallet.membership.inside() .then(function() { $scope.updateView(); UIUtils.loading.hide(); @@ -196,18 +192,23 @@ function WalletController($scope, $rootScope, $q, $ionicPopup, $timeout, $state, }); } }); - }; + }; + + + // Send membership IN + $scope.membershipIn= function() { + $scope.hideActionsPopover(); - $scope.showUidPopup() + return $scope.showUidPopup() .then(function (uid) { UIUtils.loading.show(); - // If uid changed, or selft blockUid not retrieve : do self() first + // If uid changed, or self blockUid not retrieve : do self() first if (!$rootScope.walletData.blockUid || uid != $rootScope.walletData.uid) { $rootScope.walletData.blockUid = null; $rootScope.walletData.uid = uid; Wallet.self(uid, false/*do NOT load membership here*/) .then(function() { - doMembershipIn(); + $scope.doMembershipIn(); }) .catch(function(err){ UIUtils.onError('ERROR.SEND_IDENTITY_FAILED')(err) @@ -217,7 +218,7 @@ function WalletController($scope, $rootScope, $q, $ionicPopup, $timeout, $state, }); } else { - doMembershipIn(); + $scope.doMembershipIn(); } }) .catch(function(err){ @@ -225,7 +226,6 @@ function WalletController($scope, $rootScope, $q, $ionicPopup, $timeout, $state, UIUtils.alert.info(err); $scope.membershipIn(); // loop }); - //.catch(UIUtils.onError('ERROR.SEND_MEMBERSHIP_IN_FAILED')); }; // Send membership OUT @@ -260,8 +260,61 @@ function WalletController($scope, $rootScope, $q, $ionicPopup, $timeout, $state, .catch(UIUtils.onError('ERROR.REFRESH_WALLET_DATA')); }; - /* -- show display -- */ + /** + * Renew membership + */ + $scope.renewMembership = function() { + return UIUtils.alert.confirm("CONFIRM.RENEW_MEMBERSHIP") + .then(function() { + UIUtils.loading.show(); + return $scope.doMembershipIn(); + }) + .catch(function(err){ + UIUtils.loading.hide(); + UIUtils.alert.info(err); + $scope.renewMembership(); // loop + }); + }; + + /** + * Fix membership, when existing MS reference an invalid block + */ + $scope.fixMembership = function() { + if (!$rootScope.walletData.uid) return; + + return UIUtils.alert.confirm("CONFIRM.FIX_MEMBERSHIP") + .then(function(confirm) { + if (!confirm) return; + UIUtils.loading.show(); + // Reset membership data + $rootScope.walletData.blockUid = null; + $rootScope.walletData.sigDate = null; + return Wallet.self($rootScope.walletData.uid, false/*do NOT load membership here*/); + }) + .then(function() { + return $scope.doMembershipIn(); + }) + .catch(function(err){ + UIUtils.loading.hide(); + UIUtils.alert.info(err); + $scope.fixMembership(); // loop + }); + }; + + /** + * Catch click for quick fix + * @param fix + */ + $scope.doQuickFix = function(event) { + if (event == 'renew') { + $scope.renewMembership(); + } + else if (event == 'fixMembership)') { + $scope.fixMembership(); + } + }; + /* -- popup / UI -- */ $scope.setShowDetails = function(show) { $scope.showDetails = show; diff --git a/www/js/controllers/wot-controllers.js b/www/js/controllers/wot-controllers.js index 635cab82e2be12c0153fb61676ddc8d66a6a2693..8942b4b2719f05dfa72afdf27371472e0261696f 100644 --- a/www/js/controllers/wot-controllers.js +++ b/www/js/controllers/wot-controllers.js @@ -100,17 +100,17 @@ function WotLookupController($scope, BMA, $state, UIUtils, $timeout, csConfig, c $scope.wotSearchTextId = 'wotSearchText'; $scope.enableFilter = true; - $scope.$on('$ionicView.enter', function(e, $state) { + $scope.$on('$ionicView.enter', function(e, state) { if (!$scope.entered) { - if ($state.stateParams && $state.stateParams.q) { // Query parameter - $scope.search.text=$state.stateParams.q; + if (state.stateParams && state.stateParams.q) { // Query parameter + $scope.search.text=state.stateParams.q; $timeout(function() { $scope.doSearch(); }, 100); } else { // get new comers $timeout(function() { - $scope.doGetNewcomers($state.stateParams.newcomers); + $scope.doGetNewcomers(state.stateParams.newcomers); }, 100); } $scope.entered = true; @@ -415,7 +415,7 @@ function WotIdentityViewController($scope, $state, $timeout, UIUtils, WotService * @param Modals * @constructor */ -function WotCertificationsViewController($scope, $rootScope, $timeout, $translate, csConfig, csSettings, Wallet, UIUtils, WotService, Modals) { +function WotCertificationsViewController($scope, $rootScope, $state, $timeout, $translate, csConfig, csSettings, Wallet, UIUtils, WotService, Modals) { 'ngInject'; $scope.loading = true; @@ -424,11 +424,11 @@ function WotCertificationsViewController($scope, $rootScope, $timeout, $translat $scope.showGivenCertifications = false; // default value (overwrite on 'large' view) $scope.showAvatar = false; // default value (overwrite on 'large' view) - $scope.$on('$ionicView.enter', function(e, $state) { - if ($state.stateParams && $state.stateParams.pubkey && - $state.stateParams.pubkey.trim().length > 0) { + $scope.$on('$ionicView.enter', function(e, state) { + if (state.stateParams && state.stateParams.pubkey && + state.stateParams.pubkey.trim().length > 0) { if ($scope.loading) { - $scope.load($state.stateParams.pubkey.trim()); + $scope.load(state.stateParams.pubkey.trim()); } } diff --git a/www/js/directives.js b/www/js/directives.js index a0f76dbfb714729162c18700943156efff7b07ba..11b55185ce26ba6cf2f9974485e8cfa25ef5038b 100644 --- a/www/js/directives.js +++ b/www/js/directives.js @@ -130,6 +130,20 @@ angular.module('cesium.directives', ['cesium.services']) }; }) +.directive('trustAsHtml', ['$compile', function($compile){ + return { + restrict: 'AE', + link: function(scope, element, attrs) { + var value = attrs.trustAsHtml; + if (value) { + var html = scope.$eval(value); + element.append(html); + $compile(element.contents())(scope); + } + } + } +}]) + /** * Close the current modal */ @@ -191,10 +205,10 @@ angular.module('cesium.directives', ['cesium.services']) } return { - pre: function(scope, iElement, iAttrs, controller){ + pre: function(scope, iElement, iAttrs){ PluginService.extensions.points.current.set(iAttrs.name); }, - post: function(scope, iElement, iAttrs, controller){ + post: function(){ PluginService.extensions.points.current.set(); } }; @@ -203,8 +217,6 @@ angular.module('cesium.directives', ['cesium.services']) return { restrict: "E", - //link: linker, - //controller: controller, compile: compiler, scope: { content:'=' diff --git a/www/js/services/wallet-services.js b/www/js/services/wallet-services.js index 94f904ea99d374a4bfdcc410fa3d96498f4ec9ea..63efa090705c8faf8b9a863e2e172754b04c2d26 100644 --- a/www/js/services/wallet-services.js +++ b/www/js/services/wallet-services.js @@ -36,10 +36,11 @@ angular.module('cesium.wallet.services', ['ngResource', 'ngApi', 'cesium.bma.ser errors: [] }; data.requirements = {}; - data.isMember = false; - data.loaded = false; data.blockUid = null; + data.sigDate = null; + data.isMember = false; data.events = []; + data.loaded = false; if (init) { api.data.raise.init(data); } @@ -175,7 +176,7 @@ angular.module('cesium.wallet.services', ['ngResource', 'ngApi', 'cesium.bma.ser }); }, - logout = function(username, password) { + logout = function() { return $q(function(resolve, reject) { resetData(); // will reset keypair @@ -299,6 +300,8 @@ angular.module('cesium.wallet.services', ['ngResource', 'ngApi', 'cesium.bma.ser }; data.blockUid = null; data.isMember = false; + data.sigDate = null; + data.events = []; }, loadRequirements = function() { @@ -341,7 +344,32 @@ angular.module('cesium.wallet.services', ['ngResource', 'ngApi', 'cesium.bma.ser return count; }, 0) : 0; data.isMember = !data.requirements.needSelf && !data.requirements.needMembership; - resolve(); + + var blockParts = idty.meta.timestamp.split('-', 2); + var blockNumber = parseInt(blockParts[0]); + var blockHash = blockParts[1]; + // Retrieve registration date + return BMA.blockchain.block({block: blockNumber}) + .then(function(block) { + data.sigDate = block.time; + + // Check if self has been done on a valid block + if (blockNumber!== 0 && blockHash !== block.hash) { + addEvent({type: 'error', message: 'ERROR.WALLET_INVALID_BLOCK_HASH'}); + console.debug("Invalid membership for uid={0}: block hash not match a real block (block cancelled)".format(data.uid)); + } + resolve(); + }) + .catch(function(err){ + // Special case for currency init (root block not exists): use now + if (err && err.ucode == BMA.errorCodes.BLOCK_NOT_FOUND && blockParts.number === '0') { + data.sigDate = Math.trunc(new Date().getTime() / 1000); + resolve(); + } + else { + reject(err); + } + }); }) .catch(function(err) { resetRequirements(); @@ -406,7 +434,6 @@ angular.module('cesium.wallet.services', ['ngResource', 'ngApi', 'cesium.bma.ser .then(reduceTx) ]; - // get TX history since if (fromTime !== -1) { var sliceTime = csSettings.data.walletHistorySliceSecond; @@ -445,6 +472,7 @@ angular.module('cesium.wallet.services', ['ngResource', 'ngApi', 'cesium.bma.ser }, []); })); } + // Execute jobs $q.all(jobs) .then(function(){ @@ -605,6 +633,7 @@ angular.module('cesium.wallet.services', ['ngResource', 'ngApi', 'cesium.bma.ser (data.parameters.sigQty - data.requirements.certificationCount - willExpireCertificationCount) : 0; // Add user message + data.events = []; if (data.requirements.pendingMembership) { data.events.push({type:'pending',message: 'ACCOUNT.WAITING_MEMBERSHIP'}); } diff --git a/www/js/services/wot-services.js b/www/js/services/wot-services.js index fbcf3612240a1bb5746fe7126c397ba0b461d569..ba3abc26de244243d508b4da2d62ad6ed5562cbd 100644 --- a/www/js/services/wot-services.js +++ b/www/js/services/wot-services.js @@ -96,14 +96,14 @@ angular.module('cesium.wot.services', ['ngResource', 'ngApi', 'cesium.bma.servic uid: idty.uid, pubkey: res.pubkey, timestamp: idty.meta.timestamp, - number: blockUid[0], + number: parseInt(blockUid[0]), hash: blockUid[1], revoked: idty.revoked, revokedSig: idty.revocation_sig, sig: idty.self }); }, [])); - }, [])[0]; + }, [])[0]; // TODO : check if a sort before is not better ? identity.hasSelf = !!(identity.uid && identity.timestamp && identity.sig); // Retrieve certifications @@ -181,6 +181,12 @@ angular.module('cesium.wot.services', ['ngResource', 'ngApi', 'cesium.bma.servic return BMA.blockchain.block({block: identity.number}) .then(function(block) { identity.sigDate = block.time; + + // Check if self has been done on a valid block + if (identity.number !== 0 && identity.hash !== block.hash) { + addEvent(identity, {type: 'error', message: 'ERROR.IDENTITY_INVALID_BLOCK_HASH'}); + console.debug("Invalid membership for uid={0}: block hash not match a real block (block cancelled)".format(identity.uid)); + } resolve(identity); }) .catch(function(err){ @@ -548,8 +554,8 @@ angular.module('cesium.wot.services', ['ngResource', 'ngApi', 'cesium.bma.servic _.forEach(blocks, function(block){ _.forEach(idtiesByBlock[block.number], function(idty) { idty.sigDate = block.medianTime; - if (idty.blockHash !== block.hash) { - idty.errors = ['INVALID_MS_BLOCK_HASH']; + if (block.number !== 0 && idty.blockHash !== block.hash) { + addEvent(idty, {type:'error', message: 'ERROR.WOT_PENDING_INVALID_BLOCK_HASH'}); console.debug("Invalid membership for uid={0}: block hash not match a real block (block cancelled)".format(idty.uid)); } }); @@ -629,6 +635,15 @@ angular.module('cesium.wot.services', ['ngResource', 'ngApi', 'cesium.bma.servic } }); }); + }, + + addEvent = function(data, event) { + event = event || {}; + event.type = event.type || 'info'; + event.message = event.message || ''; + event.messageParams = event.messageParams || {}; + data.events = data.events || []; + data.events.push(event); } ; diff --git a/www/plugins/es/js/controllers/market-controllers.js b/www/plugins/es/js/controllers/market-controllers.js index 50af465c5287f32144a3937d36863f0c239ff178..bc2cc59e48247ed09c6926c337609182946fc08c 100644 --- a/www/plugins/es/js/controllers/market-controllers.js +++ b/www/plugins/es/js/controllers/market-controllers.js @@ -90,7 +90,7 @@ function ESMarketLookupController($scope, $state, $focus, $timeout, $filter, $q, options: null }; - $scope.$on('$ionicView.enter', function(e, $state) { + $scope.$on('$ionicView.enter', function(e, state) { if (!$scope.entered || !$scope.search.results || $scope.search.results.length === 0) { var hasOptions = false; var runSearch = false; @@ -110,20 +110,20 @@ function ESMarketLookupController($scope, $state, $focus, $timeout, $filter, $q, }; // Search by text - if ($state.stateParams && $state.stateParams.q) { // Query parameter - $scope.search.text=$state.stateParams.q; + if (state.stateParams && state.stateParams.q) { // Query parameter + $scope.search.text=state.stateParams.q; hasOptions = runSearch = true; } // Search on location - if ($state.stateParams && $state.stateParams.location) { - $scope.search.location = $state.stateParams.location; + if (state.stateParams && state.stateParams.location) { + $scope.search.location = state.stateParams.location; hasOptions = runSearch = true; } // Search on category - if ($state.stateParams && $state.stateParams.category) { - esMarket.category.get({id: $state.stateParams.category}) + if (state.stateParams && state.stateParams.category) { + esMarket.category.get({id: state.stateParams.category}) .then(function(cat) { $scope.search.category = cat; hasOptions = runSearch = true; @@ -393,10 +393,10 @@ function ESMarketRecordViewController($scope, $anchorScroll, $ionicPopover, $sta ESCommentsController.call(this, $scope, $timeout, $filter, $state, Wallet, UIUtils, esHttp, esMarket); - $scope.$on('$ionicView.enter', function (e, $state) { - if ($state.stateParams && $state.stateParams.id) { // Load by id + $scope.$on('$ionicView.enter', function (e, state) { + if (state.stateParams && state.stateParams.id) { // Load by id if ($scope.loading) { // prevent reload if same id - $scope.load($state.stateParams.id, $state.stateParams.anchor); + $scope.load(state.stateParams.id, state.stateParams.anchor); } } else { @@ -609,7 +609,7 @@ function ESMarketRecordEditController($scope, esMarket, UIUtils, $state, $ionicP $scope.form = form; }; - $scope.$on('$ionicView.enter', function(e, $state) { + $scope.$on('$ionicView.enter', function(e, state) { // Load currencies list csCurrency.all() .then(function(currencies){ @@ -622,12 +622,12 @@ function ESMarketRecordEditController($scope, esMarket, UIUtils, $state, $ionicP .then(function(walletData) { $scope.useRelative = csSettings.data.useRelative; $scope.walletData = walletData; - if ($state.stateParams && $state.stateParams.id) { // Load by id - $scope.load($state.stateParams.id); + if (state.stateParams && state.stateParams.id) { // Load by id + $scope.load(state.stateParams.id); } else { - if ($state.stateParams && $state.stateParams.type) { // New record - $scope.formData.type=$state.stateParams.type; + if (state.stateParams && state.stateParams.type) { // New record + $scope.formData.type=state.stateParams.type; } $scope.loading = false; UIUtils.loading.hide(); diff --git a/www/plugins/es/js/controllers/registry-controllers.js b/www/plugins/es/js/controllers/registry-controllers.js index 87d1f6e55cee939f0e880becb9fe0241331b512f..52062db575f635955c19747b10a5774675b0dc3b 100644 --- a/www/plugins/es/js/controllers/registry-controllers.js +++ b/www/plugins/es/js/controllers/registry-controllers.js @@ -90,7 +90,7 @@ function ESRegistryLookupController($scope, $state, $focus, $timeout, esRegistry options: null }; - $scope.$on('$ionicView.enter', function(e, $state) { + $scope.$on('$ionicView.enter', function(e, state) { if (!$scope.entered || !$scope.search.results || $scope.search.results.length === 0) { var hasOptions = false; var runSearch = false; @@ -110,26 +110,26 @@ function ESRegistryLookupController($scope, $state, $focus, $timeout, esRegistry }; // Search by text - if ($state.stateParams && $state.stateParams.q) { - $scope.search.text=$state.stateParams.q; + if (state.stateParams && state.stateParams.q) { + $scope.search.text=state.stateParams.q; runSearch = true; } // Search on type - if ($state.stateParams && $state.stateParams.type) { - $scope.search.type = $state.stateParams.type; + if (state.stateParams && state.stateParams.type) { + $scope.search.type = state.stateParams.type; hasOptions = runSearch = true; } // Search on location - if ($state.stateParams && $state.stateParams.location) { - $scope.search.location = $state.stateParams.location; + if (state.stateParams && state.stateParams.location) { + $scope.search.location = state.stateParams.location; hasOptions = runSearch = true; } // Search on category - if ($state.stateParams && $state.stateParams.category) { - esRegistry.category.get({id: $state.stateParams.category}) + if (state.stateParams && state.stateParams.category) { + esRegistry.category.get({id: state.stateParams.category}) .then(function(cat) { $scope.search.category = cat; hasOptions = runSearch = true; @@ -388,10 +388,10 @@ function ESRegistryRecordViewController($scope, $state, $q, $timeout, $ionicPopo ESCommentsController.call(this, $scope, $timeout, $filter, $state, Wallet, UIUtils, esHttp, esRegistry); - $scope.$on('$ionicView.enter', function(e, $state) { - if ($state.stateParams && $state.stateParams.id) { // Load by id + $scope.$on('$ionicView.enter', function(e, state) { + if (state.stateParams && state.stateParams.id) { // Load by id if ($scope.loading) { // prevent reload if same id - $scope.load($state.stateParams.id, $state.stateParams.anchor); + $scope.load(state.stateParams.id, state.stateParams.anchor); } } else { @@ -571,16 +571,16 @@ function ESRegistryRecordEditController($scope, esRegistry, UIUtils, $state, $q, $scope.form = form; }; - $scope.$on('$ionicView.enter', function(e, $state) { + $scope.$on('$ionicView.enter', function(e, state) { $scope.loadWallet() .then(function(walletData) { $scope.walletData = walletData; - if ($state.stateParams && $state.stateParams.id) { // Load by id - $scope.load($state.stateParams.id); + if (state.stateParams && state.stateParams.id) { // Load by id + $scope.load(state.stateParams.id); } else { - if ($state.stateParams && $state.stateParams.type) { - $scope.formData.type=$state.stateParams.type; + if (state.stateParams && state.stateParams.type) { + $scope.formData.type=state.stateParams.type; } $scope.loading = false; UIUtils.loading.hide(); diff --git a/www/templates/wallet/popover_actions.html b/www/templates/wallet/popover_actions.html index e518813b1e61f4e88b306bfe3bbe29fbeba80264..ca3ea7eb7cd226b5e7ab2bac84a068b501a7df76 100644 --- a/www/templates/wallet/popover_actions.html +++ b/www/templates/wallet/popover_actions.html @@ -8,9 +8,7 @@ <a class="item item-icon-left item-icon-right ink" ng-click="setShowDetails(!showDetails)"> <i class="icon ion-key"></i> - {{'ACCOUNT.BTN_SHOW_DETAILS' | translate}} - <i class="icon" ng-class="{'ion-ios-checkmark-empty': showDetails}"></i> </a> @@ -30,7 +28,7 @@ <a class="item item-icon-left ink visible-xs visible-sm" ng-if="walletData.requirements.needRenew" - ng-click="membershipRenew()"> + ng-click="renewMembership()"> <i class="icon ion-loop"></i> {{'ACCOUNT.BTN_MEMBERSHIP_RENEW' | translate}} </a> diff --git a/www/templates/wallet/view_wallet.html b/www/templates/wallet/view_wallet.html index 181ba04c6d72da4b703aec34af07d4d11e14daab..e26fb9e6fea537b4ea72690da6de7aecb6c04f87 100644 --- a/www/templates/wallet/view_wallet.html +++ b/www/templates/wallet/view_wallet.html @@ -119,15 +119,13 @@ {{'ACCOUNT.EVENTS' | translate}} </span> - <div> - <span + <div class="item item-text-wrap item-icon-left item-wallet-event" + ng-class="{'assertive': event.type=='error'}" ng-repeat="event in walletData.events"> - <i class="icon" ng-class="{'ion-information-circled royal': event.type=='info','ion-alert-circled': event.type=='warn','ion-clock': event.type=='pending'}" + <i class="icon" ng-class="{'ion-information-circled royal': event.type=='info','ion-alert-circled': event.type=='warn'||event.type=='error','ion-clock': event.type=='pending'}" ></i> - <span ng-class="{'dark': event.type=='warn'}" - ng-bind-html="event.message | translate:event.messageParams"></span> - </span> + <span trust-as-html="event.message | translate:event.messageParams"></span> </div> <!-- Pending transactions --> diff --git a/www/templates/wot/lookup_form.html b/www/templates/wot/lookup_form.html index c6a7ba74a41987af8ee344460ebc5095012218fe..1dbf47f2ac5605498e0a15b6d8ae81191fce64ba 100644 --- a/www/templates/wot/lookup_form.html +++ b/www/templates/wot/lookup_form.html @@ -97,9 +97,16 @@ <span class="positive" ng-if="identity.name && identity.uid"> <i class="ion-person"></i> {{::identity.uid}} + </span> <b class="ion-key"></b> {{::identity.pubkey | formatPubkey}} + <span ng-if="identity.events" + ng-repeat="event in identity.events" + class="assertive"> + <i class="ion-alert-circled " ng-if="!identity.valid"></i> + <span ng-bind-html="event.message|translate:event.messageParams"></span> + </span> </h4> <i class="icon ion-ios-arrow-right "></i> <ion-option-button class="button-positive" ng-click="showTransferModal({pubkey: identity.pubkey, uid: identity.name ||identity.uid})" translate>COMMON.BTN_SEND_MONEY_SHORT</ion-option-button> diff --git a/www/templates/wot/view_identity.html b/www/templates/wot/view_identity.html index 63482b3e4a364da1992e393d7b49c704fc4366b0..cd38b4b7465fa590f2014f29caad75a54188bcc3 100644 --- a/www/templates/wot/view_identity.html +++ b/www/templates/wot/view_identity.html @@ -67,6 +67,13 @@ <span class="badge badge-balanced">{{::formData.sigDate | formatFromNow}}</span> </ion-item> + <div + class="item item-text-wrap item-icon-left item-wallet-event assertive" + ng-repeat="event in formData.events | filter: {type: 'error'}"> + <i class="icon ion-alert-circled"></i> + <span trust-as-html="event.message | translate:event.messageParams"></span> + </div> + <cs-extension-point name="general"></cs-extension-point> <span class="item item-divider" translate>WOT.TECHNICAL_DIVIDER</span>