diff --git a/client/app/account/activate/activate.controller.js b/client/app/account/activate/activate.controller.js index a89cef9..e388fac 100644 --- a/client/app/account/activate/activate.controller.js +++ b/client/app/account/activate/activate.controller.js @@ -1,6 +1,14 @@ 'use strict'; angular.module('ldrWebApp') + /** + * @ngdoc controller + * @name ActivateCtrl + * @description activate account controller + * @requires activate + * @requires $scope + * @property {Boolean} activate - user has active account + */ .controller('ActivateCtrl', ['activate', '$scope', function (activate, $scope) { $scope.activate = activate; }]); diff --git a/client/app/account/fpw/fpw.controller.js b/client/app/account/fpw/fpw.controller.js index db657ce..e472233 100644 --- a/client/app/account/fpw/fpw.controller.js +++ b/client/app/account/fpw/fpw.controller.js @@ -1,12 +1,35 @@ 'use strict'; angular.module('ldrWebApp') + /** + * @ngdoc controller + * @name FpwCtrl + * @description reset password controller + * @requires $scope + * @requires User + * @requires LxNotificationService + * @requires responseHandler + * @requires $translate + * @property {Object} errors - errors object + * @property {Object} user - user object + * @property {Boolean} success - reset password email sent with success + */ .controller('FpwCtrl', ['$scope', 'User', 'LxNotificationService', 'responseHandler', '$translate', function ($scope, User, LxNotificationService, responseHandler, $translate) { $scope.errors = {}; $scope.user = {}; $scope.success = false; + /** + * @ngdoc + * @name FpwCtrl#reset + * @methodOf FpwCtrl + * @param {Object} form - reset password form object + * @example + *
+ * @description + * sends reset password email + */ $scope.reset = function (form) { $scope.submitted = true; diff --git a/client/app/account/login/login.controller.js b/client/app/account/login/login.controller.js index e0abe28..92fcf0e 100644 --- a/client/app/account/login/login.controller.js +++ b/client/app/account/login/login.controller.js @@ -1,6 +1,25 @@ 'use strict'; angular.module('ldrWebApp') + /** + * @ngdoc controller + * @name LoginCtrl + * @description login controller + * @requires $scope + * @requires Auth + * @requires $location + * @requires $window + * @requires LxNotificationService + * @requires $state + * @requires $stateParams + * @requires User + * @requires $translate + * @requires responseHandler + * @requires AUTH_URL + * @property {Object} errors - errors object + * @property {Object} user - user object + * @property {Object} fail - error response flag + */ .controller('LoginCtrl', ['$scope', 'Auth', '$location', '$window', 'LxNotificationService', '$state', '$stateParams', 'User', '$translate', 'responseHandler', 'AUTH_URL', function ($scope, Auth, $location, $window, LxNotificationService, $state, @@ -16,6 +35,15 @@ angular.module('ldrWebApp') $stateParams.error = null; } + /** + * @ngdoc + * @name LoginCtrl#resend + * @methodOf LoginCtrl + * @example + *
+ * @description + * resends confirmation email + */ $scope.resend = function () { LxNotificationService.confirm($translate.instant('views.login.resendConfirmTitle'), @@ -37,6 +65,17 @@ angular.module('ldrWebApp') }; + /** + * @ngdoc + * @name LoginCtrl#login + * @methodOf LoginCtrl + * @example + *
+ * @description + * login and redirect to dashboard + */ $scope.login = function (user, form) { $scope.submitted = true; $scope.fail.flag = false; @@ -47,7 +86,6 @@ angular.module('ldrWebApp') password: user.password }) .then(function () { - // Logged in, redirect to dashboard $state.go(Auth.getDefaultScreen()); }) .catch(function (err) { diff --git a/client/app/account/password/password.controller.js b/client/app/account/password/password.controller.js index 09b7f9d..3430afc 100644 --- a/client/app/account/password/password.controller.js +++ b/client/app/account/password/password.controller.js @@ -1,6 +1,19 @@ 'use strict'; angular.module('ldrWebApp') + /** + * @ngdoc controller + * @name PasswordCtrl + * @description change password controller + * @requires $scope + * @requires $state + * @requires User + * @requires LxNotificationService + * @requires $translate + * @property {Object} errors - errors object + * @property {Object} user - user object + * @property {Object} success - success response flag + */ .controller('PasswordCtrl', [ '$scope', '$state', @@ -12,6 +25,18 @@ angular.module('ldrWebApp') $scope.success = false; $scope.user = {}; + + /** + * @ngdoc + * @name PasswordCtrl#changePassword + * @methodOf PasswordCtrl + * @param {Object} form - change password form object + * @example + *

+             * @description
+             * changes user password
+             */
             $scope.changePassword = function (form) {
 
                 $scope.submitted = true;
diff --git a/client/app/account/profile/profile.controller.js b/client/app/account/profile/profile.controller.js
index dd86f6e..246a0b4 100644
--- a/client/app/account/profile/profile.controller.js
+++ b/client/app/account/profile/profile.controller.js
@@ -1,6 +1,32 @@
 'use strict';
 
 angular.module('ldrWebApp')
+    /**
+     * @ngdoc controller
+     * @name ProfileCtrl
+     * @description profile controller
+     * @requires CountyService
+     * @requires LxNotificationService
+     * @requires LxDialogService
+     * @requires Auth
+     * @requires $filter
+     * @requires ImageUpload
+     * @requires $rootScope
+     * @requires $timeout
+     * @requires LxProgressService
+     * @requires $state
+     * @requires CountryService
+     * @requires $translate
+     * @requires HelperService
+     * @requires responseHandler
+     * @property {Object} user - current user object
+     * @property {Object} selectedLanguage - selected language object
+     * @property {Object} country - current user country object
+     * @property {Array} countries - all countries array
+     * @property {Array} counties - all counties array
+     * @property {Object} availableLanguages - available languages object
+     * @property {Object} errors - error response object
+     */
     .controller('ProfileCtrl', ['$scope',
         'CountyService',
         'LxNotificationService',
@@ -53,6 +79,16 @@ angular.module('ldrWebApp')
                 $scope.errors = {};
             };
 
+            /**
+             * @ngdoc
+             * @name ProfileCtrl#resetCounties
+             * @methodOf ProfileCtrl
+             * @param {Object} selectedCountry - selected country
+             * @example
+             * 
+ * @description + * gets counties depending on selected country + */ $scope.resetCounties = function (selectedCountry) { var params = { id: selectedCountry._id @@ -68,6 +104,15 @@ angular.module('ldrWebApp') ); }; + /** + * @ngdoc + * @name ProfileCtrl#openPasswordDialog + * @methodOf ProfileCtrl + * @example + *
+ * @description + * opens change password dialog + */ $scope.openPasswordDialog = function () { $scope.submitted = false; $scope.pass = { @@ -79,6 +124,17 @@ angular.module('ldrWebApp') LxDialogService.open('password'); }; + /** + * @ngdoc + * @name ProfileCtrl#closePasswordDialog + * @methodOf ProfileCtrl + * @param {Object} form - change password form object + * @param {Object} user - user form object + * @example + *

+             * @description
+             * saves new password on dialog close
+             */
             $scope.closePasswordDialog = function (form, user) {
 
                 $scope.submitted = true;
@@ -106,6 +162,17 @@ angular.module('ldrWebApp')
                 }
             };
 
+            /**
+             * @ngdoc
+             * @name ProfileCtrl#update
+             * @methodOf ProfileCtrl
+             * @param {Object} form - user profile form object
+             * @example
+             * 
+ * @description + * updates user profile + */ $scope.update = function (form) { $scope.submitted = true; @@ -134,6 +201,18 @@ angular.module('ldrWebApp') } }; + + /** + * @ngdoc + * @name ProfileCtrl#changeProfilePic + * @methodOf ProfileCtrl + * @param {Array} $files - array containing new profile image + * @example + *
+ * @description + * uploads new profile image, then updates the user profile + */ $scope.changeProfilePic = function ($files) { if ($files && $files[0]) { var file = $files[0]; diff --git a/client/app/account/signup/signup.controller.js b/client/app/account/signup/signup.controller.js index 59757fa..8879ee2 100644 --- a/client/app/account/signup/signup.controller.js +++ b/client/app/account/signup/signup.controller.js @@ -1,6 +1,22 @@ 'use strict'; angular.module('ldrWebApp') + /** + * @ngdoc controller + * @name SignupCtrl + * @description user sign in controller + * @requires $scope + * @requires Auth + * @requires User + * @requires $location + * @requires LxNotificationService + * @requires $translate + * @requires responseHandler + * @requires AUTH_URL + * @property {Object} errors - errors object + * @property {Object} user - user object + * @property {Object} success - success response flag + */ .controller('SignupCtrl', ['$scope', 'Auth', 'User', '$location', '$window', 'LxNotificationService', '$translate', 'responseHandler', 'AUTH_URL', function ($scope, Auth, User, $location, $window, LxNotificationService, $translate, @@ -12,6 +28,18 @@ angular.module('ldrWebApp') var email_created; + /** + * @ngdoc + * @name SignupCtrl#register + * @methodOf SignupCtrl + * @param {Object} user - user object + * @param {Object} form - new user form object + * @example + *

+             
+ * @description + * resends confirmation email + */ $scope.register = function (user, form) { $scope.submitted = true; var mailLanguage = $translate.use(); @@ -43,6 +71,16 @@ angular.module('ldrWebApp') } }; + /** + * @ngdoc + * @name SignupCtrl#resend + * @methodOf SignupCtrl + * @example + *
+ * @description + * resends confirmation email + */ $scope.resend = function () { User.resendActivation({email: email_created}).$promise .then(function () { diff --git a/client/app/account/signup/signup.directive.js b/client/app/account/signup/signup.directive.js index 0363dd9..800f8cd 100644 --- a/client/app/account/signup/signup.directive.js +++ b/client/app/account/signup/signup.directive.js @@ -1,6 +1,13 @@ 'use strict'; angular.module('ldrWebApp') + /** + * @ngdoc directive + * @name checkRequired + * @description returns true if model value is true + * @example + *
+ */ .directive('checkRequired', [function () { return { require: 'ngModel', diff --git a/client/app/activity/controllers/activityCtrl.js b/client/app/activity/controllers/activityCtrl.js index 36157d4..3b4045e 100644 --- a/client/app/activity/controllers/activityCtrl.js +++ b/client/app/activity/controllers/activityCtrl.js @@ -1,5 +1,20 @@ 'use strict'; +/** + * @ngdoc controller + * @name ActivityCtrl + * @description notifications page controller + * @requires $scope + * @requires Activity + * @requires $rootScope + * @requires $state + * @requires responseHandler + * @requires PILE_IMAGE_CONFIG + * @property {String} defaultPileImageSrc - default image path + * @property {Boolean} busyLoading - currently loading notifications flag + * @property {Boolean} finishedLoading - finished loading all notifications flag + * @property {Array} activities - notifications array + */ angular.module('ldrWebApp').controller('ActivityCtrl', [ '$scope', 'Activity', @@ -15,6 +30,16 @@ angular.module('ldrWebApp').controller('ActivityCtrl', [ $scope.activities = []; var currentPage = 1; var pageLimit = 5; + + /** + * @ngdoc + * @name ActivityCtrl#nextPage + * @methodOf ActivityCtrl + * @example + *
+ * @description + * gets notifications next page + */ $scope.nextPage = function () { if ($scope.busyLoading || $scope.finishedLoading) { @@ -32,6 +57,16 @@ angular.module('ldrWebApp').controller('ActivityCtrl', [ }); }; + /** + * @ngdoc + * @name ActivityCtrl#markAsRead + * @methodOf ActivityCtrl + * @param {Object} activity - activity to mark as read + * @example + *
+ * @description + * marks given notification as read + */ $scope.markAsRead = function (activity) { if (!activity.viewed) { Activity.viewed({id: activity._id}, {}).$promise.then(function (data) { @@ -43,6 +78,18 @@ angular.module('ldrWebApp').controller('ActivityCtrl', [ }); } }; + + /** + * @ngdoc + * @name ActivityCtrl#visitNotification + * @methodOf ActivityCtrl + * @param {Object} activity - activity to mark as read + * @example + *

+         * @description
+         * marks given notification as read and redirects to pile view
+         */
         $scope.visitNotification = function (activity) {
             $scope.markAsRead(activity);
             $state.go('app.map.pile.view', {id: activity.pile._id});
diff --git a/client/app/admin/controllers/admin.controller.js b/client/app/admin/controllers/admin.controller.js
index 3f642cc..e634057 100644
--- a/client/app/admin/controllers/admin.controller.js
+++ b/client/app/admin/controllers/admin.controller.js
@@ -1,6 +1,26 @@
 'use strict';
 
 angular.module('ldrWebApp')
+    /**
+     * @ngdoc controller
+     * @name AdminCtrl
+     * @description admin's view main controller
+     * @requires $state
+     * @requires $scope
+     * @requires LxDialogService
+     * @requires LxNotificationService
+     * @requires Pile
+     * @requires HelperService
+     * @requires $filter
+     * @requires $q
+     * @requires User
+     * @requires $translate
+     * @requires responseHandler
+     * @property {Object} state - current state object
+     * @property {Object} datepicker - datepicker's information
+     * @property {Boolean} clickable1 - calendar opened flag
+     * @property {Boolean} clickable2 - calendar opened flag
+     */
     .controller('AdminCtrl', ['$state', '$scope', 'LxDialogService', 'LxNotificationService', 'Pile', 'HelperService',
         '$filter', '$q', 'User', '$translate', 'responseHandler',
         function ($state, $scope, LxDialogService, LxNotificationService, Pile, HelperService,
@@ -15,13 +35,22 @@ angular.module('ldrWebApp')
                 LxDialogService.open(dialogId);
             };
 
+            /**
+             * @ngdoc
+             * @name AdminCtrl#getUsersCSV
+             * @methodOf AdminCtrl
+             * @example
+             * 
+ * @description + * formats stats, inserts header and all data + * @returns {Promise} Resolves to an empty response/error + */ $scope.getUsersCSV = function () { var deferred = $q.defer(); User.getUsersStatistics().$promise.then(function (resp) { var stats = responseHandler.getData(resp); - //format stats var formatted = []; - //first, insert the header formatted.push({ email: 'Email', county: 'County', @@ -30,7 +59,6 @@ angular.module('ldrWebApp') role: 'Role', created_at: 'Created at' }); - //then insert all data for (var i = 0; i < stats.length; i++) { formatted.push({ email: stats[i].email, @@ -46,6 +74,17 @@ angular.module('ldrWebApp') return deferred.promise; }; + /** + * @ngdoc + * @name AdminCtrl#getCountry + * @methodOf AdminCtrl + * @example + + * @description + * prepares country stats array to generate CSV from + * @returns {Array} countryArray - country stats array to generate CSV from + */ $scope.getCountry = function (countryArray) { if (!angular.isArray(countryArray)) { countryArray = [countryArray]; @@ -57,12 +96,6 @@ angular.module('ldrWebApp') return $scope.countryArray; }; - /* - *Country report creation based on datepicker validation - *see moment.js library function details - *watcher to check validations - *generate report - */ $scope.createCountryReport = function (dialogId) { LxDialogService.close(dialogId); @@ -71,6 +104,13 @@ angular.module('ldrWebApp') }; + /** + * @ngdoc + * @name AdminCtrl#$watchCollection + * @methodOf AdminCtrl + * @description + * watcher to check validations and then generate country report + */ $scope.$watchCollection('datepicker', function () { @@ -127,7 +167,13 @@ angular.module('ldrWebApp') LxDialogService.close(dialogId); }; - // evaluate calendar is open or not + /** + * @ngdoc + * @name AdminCtrl#switchBoolean + * @methodOf AdminCtrl + * @description + * check if calendar is open + */ $scope.switchBoolean = function (bool) { var calendar = document.getElementsByClassName('lx-date-picker--is-shown'); diff --git a/client/app/admin/controllers/adminStatisticsCtrl.js b/client/app/admin/controllers/adminStatisticsCtrl.js index 5fd68c5..977c7c2 100644 --- a/client/app/admin/controllers/adminStatisticsCtrl.js +++ b/client/app/admin/controllers/adminStatisticsCtrl.js @@ -1,6 +1,23 @@ 'use strict'; angular.module('ldrWebApp') + /** + * @ngdoc controller + * @name StatisticsCtrl + * @description admin statistics controller + * @requires $scope + * @requires leafletData + * @requires $timeout + * @requires Pile + * @requires LxDialogService + * @requires LxNotificationService + * @requires LxProgressService + * @requires $filter + * @requires HelperService + * @requires responseHandler + * @property {Boolean} openInfo - open info modal flag + * @property {Object} defaultStyle - layer style config object + */ .controller('StatisticsCtrl', ['$scope', 'leafletData', '$timeout', @@ -32,6 +49,13 @@ angular.module('ldrWebApp') style: $scope.defaultStyle }); + /** + * @ngdoc + * @name StatisticsCtrl#calculateMapWidth + * @methodOf StatisticsCtrl + * @description + * calculates map with + */ $scope.calculateMapWidth = function () { if (window.innerWidth) { var leftMenuWidth = (window.innerWidth / 12) * 3; @@ -51,12 +75,31 @@ angular.module('ldrWebApp') } }; + /** + * @ngdoc + * @name StatisticsCtrl#getArray + * @methodOf StatisticsCtrl + * @example + + * @description + * prepares county stats array to generate CSV from + * @returns {Array} county - country stats array to generate CSV from + */ $scope.getArray = function (countyArray) { $scope.data = [countyArray]; $scope.data.unshift(HelperService.headerOnCsv('County')); return $scope.data; }; + /** + * @ngdoc + * @name StatisticsCtrl#onMapClick + * @methodOf StatisticsCtrl + * @description + * gets statistics for clicked county, sets show info flag to true + */ function onMapClick(e) { $scope.featureSiruta = leafletPip.pointInLayer([e.latlng.lng, e.latlng.lat], gjLayer, true)[0].feature.properties.SIRUTA; $scope.featureName = leafletPip.pointInLayer([e.latlng.lng, e.latlng.lat], gjLayer, true)[0].feature.properties.NAME; @@ -72,6 +115,13 @@ angular.module('ldrWebApp') } } + /** + * @ngdoc + * @name StatisticsCtrl#highlightFeature + * @methodOf StatisticsCtrl + * @description + * sets style for highlighted county + */ function highlightFeature(e) { var layer = e.target; layer.setStyle({ @@ -87,6 +137,13 @@ angular.module('ldrWebApp') gjLayer.resetStyle(e.target); } + /** + * @ngdoc + * @name StatisticsCtrl#onEachFeature + * @methodOf StatisticsCtrl + * @description + * sets options for each layer + */ function onEachFeature(polygon, layer) { layer.on({ click: onMapClick, @@ -96,6 +153,14 @@ angular.module('ldrWebApp') }); } + /** + * @ngdoc + * @name StatisticsCtrl#calculateMapStatisticsResolution + * @methodOf StatisticsCtrl + * @description + * calculates statistics map height + * @returns {Integer} statisticsMap - statistics map height + */ $scope.calculateMapStatisticsResolution = function () { if (window.innerWidth > 1023) { $scope.statisticsMap = window.innerHeight - 150 - 40; @@ -105,8 +170,13 @@ angular.module('ldrWebApp') return $scope.statisticsMap; }; - //CREATE leaflet map for statistics - + /** + * @ngdoc + * @name StatisticsCtrl#createMap + * @methodOf StatisticsCtrl + * @description + * creates leaflet map object for statistics, mapbox token is required + */ self.createMap = function () { return { defaults: { @@ -127,7 +197,7 @@ angular.module('ldrWebApp') baselayers: { xyz: { name: 'OpenStreetMap (XYZ)', - url: 'https://api.mapbox.com/v4/mapbox.streets-basic/{z}/{x}/{y}.png?access_token=pk.eyJ1IjoicXVhbGl0YW5jZSIsImEiOiJkYTY0ODQzMGM1MDFlOGVhM2FiZjc3M2ZkYmQ2MjA0NSJ9.3bxLXwcDaG_V0H3reJzLBg', + url: 'https://api.mapbox.com/v4/mapbox.streets-basic/{z}/{x}/{y}.png?access_token=*********', type: 'xyz' } }, @@ -136,11 +206,18 @@ angular.module('ldrWebApp') }; }; + /** + * @ngdoc + * @name StatisticsCtrl#centerMap + * @methodOf StatisticsCtrl + * @description + * map is repositioned on Roumania's center + */ $scope.centerMap = function () { angular.extend($scope.map, { center: { zoom: 7, - lat: 45.834402, //middle of romania + lat: 45.834402, lng: 24.996989 } }); diff --git a/client/app/admin/controllers/adminUserCtrl.js b/client/app/admin/controllers/adminUserCtrl.js index 859dabe..043a98d 100644 --- a/client/app/admin/controllers/adminUserCtrl.js +++ b/client/app/admin/controllers/adminUserCtrl.js @@ -1,5 +1,15 @@ 'use strict'; - +/** + * @ngdoc controller + * @name AdminUserCtrl + * @description admin user controller + * @requires $scope + * @requires User + * @requires $state + * @requires Auth + * @requires responseHandler + * @property {Boolean} user - selected user object + */ angular.module('ldrWebApp') .controller('AdminUserCtrl', ['$scope', 'User', diff --git a/client/app/admin/controllers/adminUsersCtrl.js b/client/app/admin/controllers/adminUsersCtrl.js index f9479a6..34d150d 100644 --- a/client/app/admin/controllers/adminUsersCtrl.js +++ b/client/app/admin/controllers/adminUsersCtrl.js @@ -1,6 +1,32 @@ 'use strict'; angular.module('ldrWebApp') + /** + * @ngdoc controller + * @name AdminUsersCtrl + * @description admin statistics controller + * @requires $scope + * @requires User + * @requires CountyService + * @requires CountryService + * @requires LxDialogService + * @requires LxNotificationService + * @requires HelperService + * @requires Auth + * @requires $state + * @requires $translate + * @requires responseHandler + * @property {Object} currentUser - current user object + * @property {Object} supervisor - supervisor to create object + * @property {Object} data - data to show + * @property {Boolean} disableBtn - filter button flag + * @property {Object} user - user to search object + * @property {Object} all_counties - all counties object + * @property {Object} all_countries - all countries object + * @property {Object} state - current state object + * @property {Object} allUserRoles - all roles object + * @property {Object} config_obj - params object + */ .controller('AdminUsersCtrl', [ '$scope', 'User', @@ -89,15 +115,23 @@ angular.module('ldrWebApp') }; /** + * @ngdoc + * @name AdminUsersCtrl#$watch + * @methodOf AdminUsersCtrl * @description watch for changes on the config page that may be triggered when press on - * the page skipper select and then get the according page data - * @return {Undefined} + * the page skipper select and then gets the according page data */ $scope.$watch('config_obj.page', function () { $scope.getUsers(); }); - //get users and pagination info + /** + * @ngdoc + * @name AdminUsersCtrl#getUsers + * @methodOf AdminUsersCtrl + * @description + * gets users and pagination info + */ $scope.getUsers = function () { User.all($scope.config_obj, function (data, headers) { $scope.data.users = responseHandler.getData(data); @@ -106,16 +140,27 @@ angular.module('ldrWebApp') }); }; - //function to reset filters + /** + * @ngdoc + * @name AdminUsersCtrl#resetFilter + * @methodOf AdminUsersCtrl + * @description + * resets filters + */ $scope.resetFilter = function (property, fetchResults) { $scope.config_obj[property] = null; if (fetchResults) $scope.filter(null, null, true); }; - // updates config object & fetches piles if required - // fetchresults get users and reset the page counter - // gets property to filter by and the value, and modify the config object and do the query + /** + * @ngdoc + * @name AdminUsersCtrl#filter + * @methodOf AdminUsersCtrl + * @description + * updates config object & fetches piles if required, fetch results get users and reset the page counter, + * gets property to filter by and the value, and modify the config object and do the query + */ $scope.filter = function (property, value, fetchResults) { if (property) { $scope.config_obj[property] = (value) ? value : @@ -134,9 +179,10 @@ angular.module('ldrWebApp') }; /** - * Enable/disable filter and reset filter buttons - * @name enableFilterBtn - * @return {undefined} + * @ngdoc + * @name AdminUsersCtrl#enableFilterBtn + * @methodOf AdminUsersCtrl + * @description enable/disable filter and reset filter buttons */ $scope.enableFilterBtn = function () { $scope.clearFilterEmptyVals(); @@ -150,9 +196,10 @@ angular.module('ldrWebApp') }; /** - * Clear the filters with empty values - * @name clearFilterEmptyVals - * @return {undefined} + * @ngdoc + * @name AdminUsersCtrl#clearFilterEmptyVals + * @methodOf AdminUsersCtrl + * @description clear the filters with empty values */ $scope.clearFilterEmptyVals = function () { angular.forEach($scope.user, function (value, key) { @@ -164,9 +211,10 @@ angular.module('ldrWebApp') }; /** - * generate filters from the user selections - * @name filterUsers - * @return {undefined} + * @ngdoc + * @name AdminUsersCtrl#filterUsers + * @methodOf AdminUsersCtrl + * @description generate filters from the user selections */ $scope.filterUsers = function () { var index = 0; @@ -182,19 +230,10 @@ angular.module('ldrWebApp') }); }; - /** - * - * @name setFetchResults - * @param index - * @returns {boolean} - */ $scope.setFetchResults = function (index) { return (Object.keys($scope.user).length === index); }; - /** - * - */ $scope.resetUserFilters = function () { $scope.disableBtn = true; angular.forEach($scope.user, function (value, key) { @@ -212,7 +251,6 @@ angular.module('ldrWebApp') } }; - //reset page on pagination $scope.resetPage = function () { $scope.config_obj.page = 1; }; @@ -227,9 +265,6 @@ angular.module('ldrWebApp') $scope.getUsers(); }; - /* - Modal functions start from here - */ $scope.alertAdmin = function (dialogId, user) { $scope.temp_user = user; LxDialogService.open(dialogId); @@ -251,7 +286,18 @@ angular.module('ldrWebApp') LxNotificationService.info($translate.instant('views.usersList.noChanges')); }; - //creates a supervisor after validation and sync it on the list until refresh + /** + * @ngdoc + * @name AdminUsersCtrl#createSupervisor + * @methodOf AdminUsersCtrl + * @param {String} dialogId - new supervisor dialog id + * @param {Object} form - new supervisor form object + * @example + *

+             * @description
+             * creates new supervisor, updates the supervisors list
+             */
             $scope.createSupervisor = function (dialogId, form) {
                 $scope.submitted = true;
                 if (form.$valid) {
@@ -268,6 +314,19 @@ angular.module('ldrWebApp')
                 }
             };
 
+            /**
+             * @ngdoc
+             * @name AdminUsersCtrl#makeUserInactive
+             * @methodOf AdminUsersCtrl
+             * @param {Object} user - user to make inactive object
+             * @param {String} dialogId - dialog id
+             * @example
+             * 
+ * @description + * makes user inactive + */ $scope.makeUserInactive = function (user, dialogId) { user.role = 'inactive'; User.updateUser({id: user._id}, {status: user.role}).$promise.then(function (data) { @@ -280,8 +339,5 @@ angular.module('ldrWebApp') LxNotificationService.info($translate.instant('generic.errorSaving')); }); }; - /* - Modal functions end here - */ $scope.init(); }]); diff --git a/client/app/admin/controllers/editUserCtrl.js b/client/app/admin/controllers/editUserCtrl.js index 2070ac5..59542b1 100644 --- a/client/app/admin/controllers/editUserCtrl.js +++ b/client/app/admin/controllers/editUserCtrl.js @@ -1,6 +1,25 @@ 'use strict'; angular.module('ldrWebApp') + /** + * @ngdoc controller + * @name AdminEditUserCtrl + * @description admin edit user controller + * @requires $scope + * @requires User + * @requires $state + * @requires HelperService + * @requires LxNotificationService + * @requires Auth + * @requires $translate + * @requires responseHandler + * @property {Object} currentUser - current user object + * @property {Object} roles - user's all roles object + * @property {Object} statuses - user's all statuses object + * @property {Object} user - user to edit object + * @property {Object} selectedStatus - selected status object + * @property {Object} selectedRole - selected role object + */ .controller('AdminEditUserCtrl', ['$scope', 'User', '$state', @@ -33,6 +52,12 @@ angular.module('ldrWebApp') } }); + /** + * @ngdoc + * @name AdminEditUserCtrl#resend + * @methodOf AdminEditUserCtrl + * @description resends activation email to specified user + */ $scope.resend = function () { LxNotificationService.confirm($translate.instant('views.editSingleUser.resend'), @@ -51,6 +76,13 @@ angular.module('ldrWebApp') }; + /** + * @ngdoc + * @name AdminEditUserCtrl#updateUser + * @methodOf AdminEditUserCtrl + * @param {Object} form - user to update form object + * @description updates specified user + */ $scope.updateUser = function (form) { $scope.submitted = true; @@ -66,10 +98,11 @@ angular.module('ldrWebApp') }; /** - * @name refreshUser + * @ngdoc + * @name AdminEditUserCtrl#refreshUser + * @methodOf AdminEditUserCtrl * @description - * Changes the user's status/role, depending on the entity param - * + * changes the user's status/role, depending on the entity param * @param {Object} item - the selected item from dropdown * @param {string} entity - the type of the selected item (can be 'status' or 'role') */ diff --git a/client/app/contact/contact.controller.js b/client/app/contact/contact.controller.js index 7d298b7..43ad74c 100644 --- a/client/app/contact/contact.controller.js +++ b/client/app/contact/contact.controller.js @@ -1,37 +1,60 @@ 'use strict'; angular.module('ldrWebApp') + /** + * @ngdoc controller + * @name ContactCtrl + * @description contact page controller + * @requires $scope + * @requires Auth + * @requires ContactService + * @requires LxNotificationService + * @requires $translate + * @requires responseHandler + * @property {Object} contact - contact info object + * @property {Boolean} messageSending - sending message in progress flag + */ .controller('ContactCtrl', ['$scope', 'Auth', 'ContactService', 'LxNotificationService', '$translate', 'responseHandler', function ($scope, Auth, ContactService, LxNotificationService, $translate, responseHandler) { - $scope.init = function () { - Auth.getCurrentUser().$promise.then(function success(data) { - $scope.contact = _.pick(responseHandler.getData(data), ['first_name', 'last_name', 'email']); - }); - }; - - $scope.init(); - $scope.messageSending = false; - $scope.sendMessage = function (form) { - if (form.$valid) { - $scope.messageSending = true; - ContactService.create({ - first_name: form.first_name.$viewValue, - last_name: form.last_name.$viewValue, - email: form.email.$viewValue, - subject: form.subject.$viewValue, - message: form.message.$viewValue - }).$promise.then(function (resp) { - $scope.messageSending = false; - if (resp.success) { - LxNotificationService.alert($translate.instant('generic.notificationTitle'), - $translate.instant('generic.notificationMessage'), - $translate.instant('generic.notificationOKButton'), - function () {}); - } + $scope.init = function () { + Auth.getCurrentUser().$promise.then(function success(data) { + $scope.contact = _.pick(responseHandler.getData(data), ['first_name', 'last_name', 'email']); }); - } - }; + }; + + $scope.init(); + $scope.messageSending = false; + + /** + * @ngdoc + * @name ContactCtrl#sendMessage + * @methodOf ContactCtrl + * @description + * sends email to contact person with given message + * @param {Object} form - send message form object + */ + $scope.sendMessage = function (form) { + if (form.$valid) { + $scope.messageSending = true; + ContactService.create({ + first_name: form.first_name.$viewValue, + last_name: form.last_name.$viewValue, + email: form.email.$viewValue, + subject: form.subject.$viewValue, + message: form.message.$viewValue + }).$promise.then(function (resp) { + $scope.messageSending = false; + if (resp.success) { + LxNotificationService.alert($translate.instant('generic.notificationTitle'), + $translate.instant('generic.notificationMessage'), + $translate.instant('generic.notificationOKButton'), + function () { + }); + } + }); + } + }; - }]); + }]); diff --git a/client/app/dashboard/dashboard.controller.js b/client/app/dashboard/dashboard.controller.js index b6b8f9d..6508484 100644 --- a/client/app/dashboard/dashboard.controller.js +++ b/client/app/dashboard/dashboard.controller.js @@ -1,6 +1,27 @@ 'use strict'; angular.module('ldrWebApp') + /** + * @ngdoc controller + * @name DashboardCtrl + * @description dashboard controller + * @requires $scope + * @requires Pile + * @requires Auth + * @requires HelperService + * @requires CountyService + * @requires $state + * @requires $translate + * @requires responseHandler + * @requires CityService + * @property {Object} counties - all counties object + * @property {Object} all_cities - all cities object + * @property {Object} statuses - pile statuses object + * @property {Object} data - data to show object + * @property {Object} config_obj - query config object + * @property {Function} isAdmin - auth function to determine is user has admin role + * @property {Function} hasRole - auth function to compare with given role + */ .controller('DashboardCtrl', [ '$scope', 'Pile', @@ -45,7 +66,6 @@ angular.module('ldrWebApp') $scope.data = {}; - //query config object $scope.config_obj = { page: 1, skip: 15, @@ -67,12 +87,24 @@ angular.module('ldrWebApp') $scope.isAdmin = Auth.isAdmin; $scope.hasRole = Auth.hasRole; + /** + * @ngdoc + * @name DashboardCtrl#goToPile + * @methodOf DashboardCtrl + * @param {object} obj - pile object + * @description redirects to pile view + */ $scope.goToPile = function (obj) { var url = $state.href($scope.hasRole('supervisor') ? 'app.map.pile.edit' : 'app.map.pile.view', obj); window.open(url, '_blank'); }; - // use case function to display county by user role + /** + * @ngdoc + * @name DashboardCtrl#displayDefaultCounty + * @methodOf DashboardCtrl + * @description displays user county or all acounties for admin + */ $scope.displayDefaultCounty = function () { if ($scope.user.role === 'admin') { return $scope.counties[0]; @@ -86,9 +118,11 @@ angular.module('ldrWebApp') }; /** + * @ngdoc + * @name DashboardCtrl#$watch + * @methodOf DashboardCtrl * @description watch for changes on the config page that may be triggered when press on - * the page skipper select and then get the according page data - * @return {Undefined} + * the page skipper select and then gets the according page data */ $scope.$watch('config_obj.page', function () { $scope.getPiles(); @@ -99,6 +133,14 @@ angular.module('ldrWebApp') var filter = {}; var sort = {}; + /** + * @ngdoc + * @name DashboardCtrl#applySort + * @methodOf DashboardCtrl + * @description + * calls refresh filter function after setting sort object + * @param {String} sort_by - user property to sort by + */ $scope.applySort = function (sort_by) { if (sort_by) { if (sort.by === sort_by) { @@ -114,6 +156,17 @@ angular.module('ldrWebApp') } }; + /** + * @ngdoc + * @name DashboardCtrl#addFilter + * @methodOf DashboardCtrl + * @example
+ * @description + * adds filter from select values + * @param {String} filter_name - filter name + * @param {String} filter_value - filter value + */ $scope.addFilter = function (filter_name, filter_value) { if (filter_name && filter_name !== 'city') { if (filter_name === 'county') { @@ -127,6 +180,14 @@ angular.module('ldrWebApp') } }; + /** + * @ngdoc + * @name DashboardCtrl#removeFilter + * @methodOf DashboardCtrl + * @description + * removes specifie filter from filters array + * @param {String} filter_name - filter name + */ $scope.removeFilter = function (filter_name) { if (filter_name) { filter[filter_name] = null; @@ -135,9 +196,11 @@ angular.module('ldrWebApp') }; /** - * - * @param filter_value - * @return {undefined} + * @ngdoc + * @name DashboardCtrl#applyCityFilter + * @methodOf DashboardCtrl + * @param {String} filter_value - filter value + * @description redirects to pile view */ $scope.applyCityFilter = function (filter_value) { if (filter_value._id === 0) { @@ -148,6 +211,13 @@ angular.module('ldrWebApp') refreshFilters(); }; + /** + * @ngdoc + * @name DashboardCtrl#displayFilterValue + * @methodOf DashboardCtrl + * @param {String} filter_name - filter name + * @description gets translation of filter name + */ $scope.displayFilterValue = function (filter_name) { if (filter_name === 'status') { for (var i = 0; i < $scope.statuses.length; i++) { @@ -158,21 +228,28 @@ angular.module('ldrWebApp') return ''; }; + /** + * @ngdoc + * @name DashboardCtrl#refreshFilters + * @methodOf DashboardCtrl + * @description updates config object & fetches piles if required + */ function refreshFilters() { $scope.config_obj.sort = sort; $scope.config_obj.filter = filter; $scope.getPiles(); } - // updates config object & fetches piles if required - // fetchresults get piles and reset the page counter - // gets property to filter by and the value, and modify the config object and do the query - //same as adminUsers ctrl - $scope.resetPage = function () { $scope.config_obj.page = 1; }; + /** + * @ngdoc + * @name DashboardCtrl#getPiles + * @methodOf DashboardCtrl + * @description gets required piles + */ $scope.getPiles = function () { Pile.query($scope.config_obj, function (data, headers) { $scope.data.piles = responseHandler.getData(data); @@ -191,15 +268,27 @@ angular.module('ldrWebApp') $scope.getPiles(); }; + /** + * @ngdoc + * @name DashboardCtrl#goToContributions + * @methodOf DashboardCtrl + * @description gets contribute piles + */ $scope.goToContributions = function () { - if (!$scope.config_obj.contributions) { //to not make a call if same button is pressed + if (!$scope.config_obj.contributions) { $scope.config_obj.contributions = true; $scope.getPiles(); } }; + /** + * @ngdoc + * @name DashboardCtrl#goToPiles + * @methodOf DashboardCtrl + * @description gets reported piles + */ $scope.goToPiles = function () { - if ($scope.config_obj.contributions) { //to not make a call if same button is pressed + if ($scope.config_obj.contributions) { $scope.config_obj.contributions = false; $scope.getPiles(); } @@ -209,7 +298,6 @@ angular.module('ldrWebApp') * @ngdoc method * @name DashboardCtrl#populateCity * @methodOf DashboardCtrl - * @return {undefined} * @description * populate city select */ diff --git a/client/app/dashboard/dashboard.directive.js b/client/app/dashboard/dashboard.directive.js index 71562e2..78ca02a 100644 --- a/client/app/dashboard/dashboard.directive.js +++ b/client/app/dashboard/dashboard.directive.js @@ -1,4 +1,11 @@ 'use strict'; +/** + * @ngdoc directive + * @name adStopEvent + * @description disables propagation for click event on div + * @example + *
div ad-stop-event>
+ */ angular.module('ldrWebApp').directive('adStopEvent', function () { return { restrict: 'A', diff --git a/client/app/directives.js b/client/app/directives.js index 7bd6b7d..8e01c0f 100644 --- a/client/app/directives.js +++ b/client/app/directives.js @@ -1,5 +1,12 @@ 'use strict'; angular.module('ldrWebApp') + /** + * @ngdoc directive + * @name roPhoneValidation + * @description phone number validation for Roumania + * @example + *
+ */ .directive('roPhoneValidation', function () { return { require: 'ngModel', @@ -24,6 +31,14 @@ angular.module('ldrWebApp') } }; }) + /** + * @ngdoc directive + * @name closeModalOnStateChange + * @description closes modal on state change + * @example + *
+ */ .directive('closeModalOnStateChange', function (LxDialogService) { return { restrict: 'A', @@ -36,6 +51,13 @@ angular.module('ldrWebApp') } }; }) + /** + * @ngdoc directive + * @name removeTooltip + * @description remove tooltip from element + * @example + *
+ */ .directive('removeTooltip', function () { return { restrict: 'A', diff --git a/client/app/filters.js b/client/app/filters.js index 4cdf809..f82faa0 100644 --- a/client/app/filters.js +++ b/client/app/filters.js @@ -1,15 +1,9 @@ -/** - * Created by razvan on 29/09/16. - */ -/** - * - */ - angular.module('ldrWebApp') -/** - * @return {String} - * @description filter used to convert words to first upper case first letter - */ + /** + * @ngdoc filter + * @name titleCase + * @description filter used to convert words to first upper case first letter + */ .filter('titleCase', function () { return function (str) { if (!str) { @@ -21,20 +15,22 @@ angular.module('ldrWebApp') }; }) /** - * @return {String} + * @ngdoc filter + * @name yesNo * @description filter used to translate true/false values in Yes/No */ - .filter('yesNo', function($translate) { - return function(input) { + .filter('yesNo', function ($translate) { + return function (input) { return input ? $translate.instant('views.dashboard.yes') : $translate.instant('views.dashboard.no'); }; }) /** - * @return {String} + * @ngdoc filter + * @name emptyVal * @description filter used to apply " - " string for empty vals */ - .filter('emptyVal', function() { - return function(input) { + .filter('emptyVal', function () { + return function (input) { return (!input) ? '-' : input; }; }); diff --git a/client/app/help/help.controller.js b/client/app/help/help.controller.js index 8e68a8b..b820af3 100644 --- a/client/app/help/help.controller.js +++ b/client/app/help/help.controller.js @@ -1,6 +1,15 @@ 'use strict'; angular.module('ldrWebApp') + /** + * @ngdoc controller + * @name HelpCtrl + * @description help page controller + * @requires $scope + * @requires Auth + * @property {String} message - hello message + * @property {String} helperLanguage - current user language + */ .controller('HelpCtrl', function ($scope, Auth) { $scope.message = 'Hello'; $scope.helperLanguage = Auth.getCurrentUser().language; diff --git a/client/app/help/help.directive.js b/client/app/help/help.directive.js index 1228eea..d2cf594 100644 --- a/client/app/help/help.directive.js +++ b/client/app/help/help.directive.js @@ -1,3 +1,11 @@ +/** + * @ngdoc directive + * @name bindHelpScreen + * @description binds help screen popup to specified element + * @example + *
+ */ angular.module('ldrWebApp').directive('bindHelpScreen', ['Help', 'LxNotificationService', '$translate', function (Help, LxNotificationService, $translate) { return { diff --git a/client/app/improve/IssuesListCtrl/IssuesListCtrl.controller.js b/client/app/improve/IssuesListCtrl/IssuesListCtrl.controller.js index f1fa894..6076317 100644 --- a/client/app/improve/IssuesListCtrl/IssuesListCtrl.controller.js +++ b/client/app/improve/IssuesListCtrl/IssuesListCtrl.controller.js @@ -1,6 +1,20 @@ 'use strict'; angular.module('ldrWebApp') + /** + * @ngdoc controller + * @name IssuesListCtrl + * @description issues page controller + * @requires $scope + * @requires Issues + * @requires LxNotificationService + * @requires LxDialogService + * @requires $translate + * @requires responseHandler + * @property {Object} range - query start/end date objects + * @property {Object} endDateLimit - end date moment object + * @property {Object} pagination - query pagination object + */ .controller('IssuesListCtrl', [ '$scope', 'Issues', @@ -33,6 +47,12 @@ angular.module('ldrWebApp') $scope.pagination.page++; }; + /** + * @ngdoc + * @name IssuesListCtrl#$watchGroup + * @methodOf IssuesListCtrl + * @description watch for changes on pagination and selected start/end date and gets requested issues + */ $scope.$watchGroup(['pagination.page', 'range.date_start', 'range.date_end'], function () { Issues.query({ page: $scope.pagination.page, @@ -67,6 +87,14 @@ angular.module('ldrWebApp') LxDialogService.open(dialogId); }; + /** + * @ngdoc + * @name IssuesListCtrl#sendErrors + * @methodOf IssuesListCtrl + * @param {Object} form - issue form object + * @param {String} dialogId - dialog ids + * @description sends issues in range to specified email + */ $scope.sendErrors = function (form, dialogId) { if (form.$valid) { @@ -83,9 +111,4 @@ angular.module('ldrWebApp') } }; - - $scope.filterByRange = function () { - - }; - }]); diff --git a/client/app/improve/improve.controller.js b/client/app/improve/improve.controller.js index 8462ddb..359aa2f 100644 --- a/client/app/improve/improve.controller.js +++ b/client/app/improve/improve.controller.js @@ -1,6 +1,18 @@ 'use strict'; angular.module('ldrWebApp') + /** + * @ngdoc controller + * @name ImproveCtrl + * @description improve page controller + * @requires $scope + * @requires Issues + * @requires LxNotificationService + * @requires LxDialogService + * @requires $translate + * @property {Object} issue - issue to report objects + * @property {String} currentLang - current language + */ .controller('ImproveCtrl', [ '$scope', 'Issues', @@ -14,6 +26,14 @@ angular.module('ldrWebApp') }; var originalIssue = angular.copy($scope.issue); $scope.currentLang = $translate.use(); + + /** + * @ngdoc method + * @name ImproveCtrl#sendIssue + * @methodOf ImproveCtrl + * @description + * creates entered issue + */ $scope.sendIssue = function (form, dialogId) { if (form.$valid) { Issues.create($scope.issue).$promise.then(function success() { @@ -23,6 +43,14 @@ angular.module('ldrWebApp') LxNotificationService.success($translate.instant('views.report.success')); } }; + + /** + * @ngdoc method + * @name ImproveCtrl#resetForm + * @methodOf ImproveCtrl + * @description + * clears form + */ $scope.resetForm = function (form) { $scope.issue = null; $scope.issue = angular.copy(originalIssue); diff --git a/client/app/main/main.controller.js b/client/app/main/main.controller.js index d822034..777dac8 100644 --- a/client/app/main/main.controller.js +++ b/client/app/main/main.controller.js @@ -1,24 +1,43 @@ 'use strict'; angular.module('ldrWebApp') + /** + * @ngdoc controller + * @name MainCtrl + * @description main controller + * @requires Auth + * @requires $state + * @requires LxNotificationService + * @requires $scope + * @requires ContactService + * @requires $translate + */ .controller('MainCtrl', ['Auth', '$state', 'LxNotificationService', '$scope', 'ContactService', '$translate', function (Auth, $state, LxNotificationService, $scope, ContactService, $translate) { - $scope.contact = function (form) { - if (form.$valid) { - ContactService.create({ - first_name: form.first_name.$viewValue, - last_name: form.last_name.$viewValue, - email: form.email.$viewValue, - message: form.message.$viewValue - }).$promise.then(function (resp) { - if (resp.success) { - LxNotificationService.alert($translate.instant('generic.notificationTitle'), - $translate.instant('generic.notificationMessage'), - $translate.instant('generic.notificationOKButton'), - function () {}); - } - }); - } - }; - }]); + /** + * @ngdoc + * @name MainCtrl#contact + * @methodOf MainCtrl + * @param {Object} form - contact us form object + * @description creates contact us note + */ + $scope.contact = function (form) { + if (form.$valid) { + ContactService.create({ + first_name: form.first_name.$viewValue, + last_name: form.last_name.$viewValue, + email: form.email.$viewValue, + message: form.message.$viewValue + }).$promise.then(function (resp) { + if (resp.success) { + LxNotificationService.alert($translate.instant('generic.notificationTitle'), + $translate.instant('generic.notificationMessage'), + $translate.instant('generic.notificationOKButton'), + function () { + }); + } + }); + } + }; + }]); diff --git a/client/app/main/main.directive.js b/client/app/main/main.directive.js index a23e3ee..d483bb0 100644 --- a/client/app/main/main.directive.js +++ b/client/app/main/main.directive.js @@ -1,6 +1,13 @@ 'use strict'; angular.module('ldrWebApp') + /** + * @ngdoc directive + * @name emailMatch + * @description sets entered email validity + * @example + *
+ */ .directive('emailMatch', [function () { return { require: 'ngModel', @@ -13,6 +20,13 @@ angular.module('ldrWebApp') } }; }]) + /** + * @ngdoc directive + * @name ldrOnePage + * @description adds scroll animation on main page + * @example + *
+ */ .directive('ldrOnePage', [function () { return { restrict: 'A', diff --git a/client/app/map/MapHelperService.js b/client/app/map/MapHelperService.js index 6a07364..70b9734 100644 --- a/client/app/map/MapHelperService.js +++ b/client/app/map/MapHelperService.js @@ -1,4 +1,11 @@ 'use strict'; +/** + * @ngdoc service + * @service + * @name map helper service + * @description The subsidy service + * @requires deviceDetector + */ angular.module('ldrWebApp').factory('MapHelperService', ['deviceDetector', function (deviceDetector) { @@ -78,15 +85,7 @@ angular.module('ldrWebApp').factory('MapHelperService', ['deviceDetector', }, calculateMenuResolution: function () { - var menuResolution; - - if (window.innerWidth > 1023) { - menuResolution = window.innerHeight - this.calculateMapResolution(); - } - else { - menuResolution = window.innerHeight - this.calculateMapResolution(); - } - return menuResolution; + return window.innerHeight - this.calculateMapResolution(); }, createMap: function () { diff --git a/client/app/map/controllers/CreatePileCtrl.js b/client/app/map/controllers/CreatePileCtrl.js index e59759e..ac62851 100644 --- a/client/app/map/controllers/CreatePileCtrl.js +++ b/client/app/map/controllers/CreatePileCtrl.js @@ -1,4 +1,34 @@ 'use strict'; +/** + * @ngdoc controller + * @name CreatePileCtrl + * @description create pile view controller + * @requires $rootScope + * @requires $scope + * @requires LxDialogService + * @requires LxNotificationService + * @requires $timeout + * @requires $state + * @requires Pile + * @requires Upload + * @requires HelperService + * @requires $sce + * @requires ImageUpload + * @requires preloader + * @requires $translate + * @requires responseHandler + * @requires Auth + * @requires API_URL + * @property {Integer} uploadMaxFileSize - environment maximum upload size + * @property {Object} bgImage - default background image + * @property {Object} files - image files + * @property {Boolean} inprogress - images uploading in progress + * @property {Object} steps - create pile steps config objects + * @property {Function} getThumbnail - generate photo thumbnail function + * @property {Object} materials - materials object + * @property {Object} areas - areas object + * @property {Object} pile - pile to create object + */ angular.module('ldrWebApp').controller('CreatePileCtrl', [ '$rootScope', '$scope', @@ -25,6 +55,13 @@ angular.module('ldrWebApp').controller('CreatePileCtrl', [ $scope.files = []; $scope.inprogress = false; + /** + * @ngdoc + * @name CreatePileCtrl#checkedMaterialType + * @methodOf CreatePileCtrl + * @description check if material type is selected + * @returns {Boolean} response + */ self.checkedMaterialType = function () { var response = false; angular.forEach($scope.materials, function (item) { @@ -35,6 +72,13 @@ angular.module('ldrWebApp').controller('CreatePileCtrl', [ return response; }; + /** + * @ngdoc + * @name CreatePileCtrl#checkedArea + * @methodOf CreatePileCtrl + * @description check if area is selected + * @returns {Boolean} response + */ self.checkedArea = function () { var response = false; angular.forEach($scope.areas, function (item) { @@ -93,6 +137,13 @@ angular.module('ldrWebApp').controller('CreatePileCtrl', [ size: 3 }; }; + + /** + * @ngdoc + * @name CreatePileCtrl#$watchCollection + * @methodOf CreatePileCtrl + * @description splice files array if limit is exceeded + */ $scope.$watchCollection('files', function () { if ($scope.files.length > 3) { $scope.files = $scope.files.slice(0, 3); @@ -100,6 +151,13 @@ angular.module('ldrWebApp').controller('CreatePileCtrl', [ } }); + /** + * @ngdoc + * @name CreatePileCtrl#selectFiles + * @methodOf CreatePileCtrl + * @param {Object} files - image files to upload + * @description for each image file generates thumbnail + */ $scope.selectFiles = function (files) { angular.forEach(files, function (file) { ImageUpload.isImage(file).then( @@ -131,17 +189,37 @@ angular.module('ldrWebApp').controller('CreatePileCtrl', [ }); }; + /** + * @ngdoc + * @name CreatePileCtrl#canNavigateToStep + * @param {String} step - step number + * @methodOf CreatePileCtrl + * @description check if user can go to next step + */ $scope.canNavigateToStep = function (step) { return (step >= 0 && step < $scope.steps.length && $scope.steps[step].isAvailable && (step !== $scope.currentStep)); }; + /** + * @ngdoc + * @name CreatePileCtrl#goToStep + * @methodOf CreatePileCtrl + * @param {String} step - step number + * @description redirects to specified step + */ $scope.goToStep = function (step) { if ($scope.canNavigateToStep(step)) { $scope.currentStep = step; } }; + /** + * @ngdoc + * @name CreatePileCtrl#nextStep + * @methodOf CreatePileCtrl + * @description redirects to next steps + */ $scope.nextStep = function () { if ($scope.steps[$scope.currentStep].isValid()) { $scope.pile.location = $rootScope.location; @@ -153,12 +231,25 @@ angular.module('ldrWebApp').controller('CreatePileCtrl', [ return area.selected === true; }); }; + + /** + * @ngdoc + * @name CreatePileCtrl#previousStep + * @methodOf CreatePileCtrl + * @description redirects to previous step + */ $scope.previousStep = function () { if ($scope.canNavigateToStep($scope.currentStep - 1)) { $scope.currentStep -= 1; } }; + /** + * @ngdoc + * @name CreatePileCtrl#resetPile + * @methodOf CreatePileCtrl + * @description resets pile object + */ $scope.resetPile = function () { $scope.pile = { size: 3, @@ -171,6 +262,12 @@ angular.module('ldrWebApp').controller('CreatePileCtrl', [ $scope.saving = false; + /** + * @ngdoc + * @name CreatePileCtrl#createPile + * @methodOf CreatePileCtrl + * @description maps pile object, uploads pile and images, resets pile object + */ $scope.createPile = function () { $scope.saving = true; diff --git a/client/app/map/controllers/EditPileCtrl.js b/client/app/map/controllers/EditPileCtrl.js index 62a7fde..f262ba3 100644 --- a/client/app/map/controllers/EditPileCtrl.js +++ b/client/app/map/controllers/EditPileCtrl.js @@ -1,4 +1,40 @@ 'use strict'; +/** + * @ngdoc controller + * @name EditPileCtrl + * @description edit pile controller + * @requires $scope + * @requires $rootScope + * @requires Pile + * @requires $state + * @requires HelperService + * @requires CommentsService + * @requires Auth + * @requires currentPile + * @requires Authority + * @requires LxNotificationService + * @requires LxDialogService + * @requires ImageUpload + * @requires $sce + * @requires preloader + * @requires $translate + * @requires responseHandler + * @property {Integer} comment - environment maximum upload size + * @property {Object} pile - pile object + * @property {Object} allImages - image files + * @property {Integer} maxSize - maximum number of images, 3/4 depending on existing screenshot + * @property {Integer} minSize - maximum number of images, 1/2 depending on existing screenshot + * @property {Object} truePileLocation - save pile location on $rootScope + * @property {Object} user - current user object + * @property {Object} showEditableMarker - show editable marker flag used in get pile screenshot + * @property {Object} selectedImage - check if at least one image is selected flag + * @property {Object} saving - saving in progress flag + * @property {Object} uploadMaxFileSize - environment maximum upload size + * @property {Object} pile_statuses - all pile available statuses + * @property {Object} authorities - authorities object + * @property {Object} comments - comments object + * @property {Object} allocate - allocate info object + */ angular.module('ldrWebApp').controller('EditPileCtrl', [ '$scope', '$rootScope', @@ -55,6 +91,12 @@ angular.module('ldrWebApp').controller('EditPileCtrl', [ $scope.comments = responseHandler.getData(data); }); + /** + * @ngdoc + * @name EditPileCtrl#confirmStatus + * @methodOf EditPileCtrl + * @description pile status is confirmed + */ $scope.confirmStatus = function (what) { Pile.confirm({action: what, pile: $scope.pile._id}).$promise.then(function success(data) { angular.extend($scope.pile, responseHandler.getData(data)); @@ -65,6 +107,13 @@ angular.module('ldrWebApp').controller('EditPileCtrl', [ date: moment().add(parseInt($rootScope.environment.pile.min_reported_days), 'day') }; + /** + * @ngdoc + * @name EditPileCtrl#allocatePile + * @methodOf EditPileCtrl + * @param {Object} form - allocate pile form object + * @description allocate pile to selected authority + */ $scope.allocatePile = function (form) { $scope.bgImage = '#FFF url("../assets/images/map/type_description_' + Auth.getCurrentUser().language + '.svg") no-repeat center center'; if (form.$valid) { @@ -87,6 +136,13 @@ angular.module('ldrWebApp').controller('EditPileCtrl', [ } }; + /** + * @ngdoc + * @name EditPileCtrl#setStatus + * @methodOf EditPileCtrl + * @param {Object} status - allocate pile form object + * @description updates pile status + */ $scope.setStatus = function (status) { Pile.query({id: $state.params.id}).$promise.then(function (data) { @@ -108,6 +164,12 @@ angular.module('ldrWebApp').controller('EditPileCtrl', [ }; + /** + * @ngdoc + * @name EditPileCtrl#printPile + * @methodOf EditPileCtrl + * @description generates pdf with pile info + */ $scope.printPile = function () { Pile.query({id: $state.params.id}).$promise.then(function (data) { @@ -195,6 +257,12 @@ angular.module('ldrWebApp').controller('EditPileCtrl', [ LxDialogService.close(dialogID); }; + /** + * @ngdoc + * @name EditPileCtrl#deleteImage + * @methodOf EditPileCtrl + * @description removes image from pile images + */ $scope.deleteImage = function (dialogId) { ImageUpload.remove($scope.allImages[$scope.allImages.index]._id).then(function () { $scope.allImages.splice($scope.allImages.index, 1); @@ -210,6 +278,12 @@ angular.module('ldrWebApp').controller('EditPileCtrl', [ $scope.newImage = {}; }; + /** + * @ngdoc + * @name EditPileCtrl#selectImage + * @methodOf EditPileCtrl + * @description generates selected image thumbnail + */ $scope.selectImage = function ($files) { $scope.selectedImage = false; var file = $files[0]; @@ -245,6 +319,13 @@ angular.module('ldrWebApp').controller('EditPileCtrl', [ } }; + /** + * @ngdoc + * @name EditPileCtrl#saveImage + * @methodOf EditPileCtrl + * @param {String} dialogId - dialog id + * @description uploads new image and refreshes allImages array + */ $scope.saveImage = function (dialogId) { $scope.saving = true; ImageUpload.upload($scope.newImage, 'pile', $scope.pile._id).then(function success(image) { @@ -260,6 +341,12 @@ angular.module('ldrWebApp').controller('EditPileCtrl', [ }); }; + /** + * @ngdoc + * @name EditPileCtrl#$watch + * @methodOf EditPileCtrl + * @description sets can delete flag depending on number of remaining images(at least one photo that is not screenshot) + */ $scope.$watch('allImages.index', function () { $scope.canDelete = ($scope.allImages[$scope.allImages.index].is_screenshot && $scope.allImages.index === $scope.allImages.length - 1); @@ -269,6 +356,14 @@ angular.module('ldrWebApp').controller('EditPileCtrl', [ $scope.comments.unshift(comment); }; + /** + * @ngdoc + * @name EditPileCtrl#postComment + * @methodOf EditPileCtrl + * @param {Object} form - comment form object + * @param {String} dialogId - dialog id + * @description creates new comment for specified pile + */ $scope.postComment = function (form, dialogId) { if (typeof $scope.comment.description === 'undefined') { LxNotificationService.info($translate.instant('views.editViewPile.addCommentDialog.commentTenChars')); @@ -286,6 +381,14 @@ angular.module('ldrWebApp').controller('EditPileCtrl', [ } }; + /** + * @ngdoc + * @name EditPileCtrl#editDescription + * @methodOf EditPileCtrl + * @param {Object} form - description form object + * @param {String} dialogId - dialog id + * @description updates description for specified pile + */ $scope.editDescription = function (form, dialogId) { if (form.$valid) { $scope.description = $scope.pile.description; diff --git a/client/app/map/controllers/MapCtrl.js b/client/app/map/controllers/MapCtrl.js index 7915926..15c24be 100644 --- a/client/app/map/controllers/MapCtrl.js +++ b/client/app/map/controllers/MapCtrl.js @@ -1,5 +1,32 @@ 'use strict'; angular.module('ldrWebApp') + /** + * @ngdoc controller + * @name CreatePileCtrl + * @description create pile view controller + * @requires $scope + * @requires leafletData + * @requires $rootScope + * @requires Pile + * @requires HelperService + * @requires $timeout + * @requires LxNotificationService + * @requires LxDialogService + * @requires Auth + * @requires deviceDetector + * @requires Help + * @requires $compile + * @requires LxProgressService + * @requires MapHelperService + * @requires $translate + * @requires responseHandler + * @property {Object} options - map options object + * @property {Function} hasRole - authentication function that checks if user has specified role + * @property {Object} regionBounds - map bounds + * @property {Boolean} markersLoading - markers loading flags + * @property {Object} map - map object + * @property {Object} userMarker - user marker object + */ .controller('MapCtrl', [ '$scope', 'leafletData', @@ -7,7 +34,8 @@ angular.module('ldrWebApp') 'Pile', 'HelperService', '$timeout', - 'LxNotificationService', 'LxDialogService', + 'LxNotificationService', + 'LxDialogService', 'Auth', 'deviceDetector', 'Help', diff --git a/client/app/map/controllers/ViewPileDetailsCtrl.js b/client/app/map/controllers/ViewPileDetailsCtrl.js index 91f0f9e..ff20e3a 100644 --- a/client/app/map/controllers/ViewPileDetailsCtrl.js +++ b/client/app/map/controllers/ViewPileDetailsCtrl.js @@ -1,4 +1,27 @@ 'use strict'; +/** + * @ngdoc controller + * @name ViewPileCtrl + * @description view pile controller + * @requires $scope + * @requires $state + * @requires Pile + * @requires CommentsService + * @requires HelperService + * @requires $sce + * @requires ImageUpload + * @requires currentPile + * @requires LxDialogService + * @requires LxNotificationService + * @requires Auth + * @requires $translate + * @requires responseHandler + * @property {Integer} comment - comment to add + * @property {Boolean} mapdialog - map dialog opened flag + * @property {Object} pile - pile object + * @property {Object} bgImage - default background image + * @property {Function} hasRole - authentication function that checks if user has specified role + */ angular.module('ldrWebApp').controller('ViewPileCtrl', [ '$scope', '$state', @@ -31,12 +54,25 @@ angular.module('ldrWebApp').controller('ViewPileCtrl', [ $scope.comments = responseHandler.getData(data); }); + /** + * @ngdoc + * @name ViewPileCtrl#confirmStatus + * @methodOf ViewPileCtrl + * @description pile status is confirmed + */ $scope.confirmStatus = function (what) { Pile.confirm({action: what, pile: $scope.pile._id}).$promise.then(function success(data) { angular.extend($scope.pile, responseHandler.getData(data)); }); }; + /** + * @ngdoc + * @name ViewPileCtrl#hidePile + * @methodOf ViewPileCtrl + * @param {Object} pile - pile to hide + * @description hides pile from normal users, is shown only for admin + */ $scope.hidePile = function (pile) { pile.is_hidden = true; Pile.hide({id: pile._id}, pile).$promise.then(function (data) { @@ -45,6 +81,13 @@ angular.module('ldrWebApp').controller('ViewPileCtrl', [ }); }; + /** + * @ngdoc + * @name ViewPileCtrl#unhidePile + * @methodOf ViewPileCtrl + * @param {Object} pile - pile to unhide + * @description unhides pile from normal users + */ $scope.unhidePile = function (pile) { pile.is_hidden = false; Pile.hide({id: pile._id}, pile).$promise.then(function (data) { @@ -80,18 +123,18 @@ angular.module('ldrWebApp').controller('ViewPileCtrl', [ $scope.comment.description = ''; }; - $scope.selectFiles = function (files) { - angular.forEach(files, function (file) { - HelperService.generateThumbnail(file).then(function (imageUrl) { - file.thumbnailImage = $sce.trustAsResourceUrl(imageUrl); - $scope.files.push(file); - }); - }); - }; $scope.addComment = function (comment) { $scope.comments.unshift(comment); }; + /** + * @ngdoc + * @name ViewPileCtrl#postComment + * @methodOf ViewPileCtrl + * @param {Object} form - comment form object + * @param {String} dialogId - dialog id + * @description creates new comment for specified pile + */ $scope.postComment = function (form, dialogId) { if (form.$valid) { CommentsService.create({pile: $state.params.id}, { diff --git a/client/app/map/controllers/ViewPileOnMapCtrl.js b/client/app/map/controllers/ViewPileOnMapCtrl.js index 82e4ec9..1411280 100644 --- a/client/app/map/controllers/ViewPileOnMapCtrl.js +++ b/client/app/map/controllers/ViewPileOnMapCtrl.js @@ -1,4 +1,29 @@ 'use strict'; +/** + * @ngdoc controller + * @name ViewPileCtrl + * @description view pile controller + * @requires $scope + * @requires $rootScope + * @requires $filter + * @requires leafletData + * @requires Pile + * @requires $q + * @requires Auth + * @requires ImageUpload + * @requires LxNotificationService + * @requires MapHelperService + * @requires $translate + * @requires responseHandler + * @property {Function} hasRole - authentication function that checks if user has specified role + * @property {Object} center - pile object + * @property {Boolean} savableScreenshot - screenshot can be saved depending on pile status + * @property {Boolean} savingScreenshot - saving screenshot in progress + * @property {Object} defaults - map options + * @property {Object} regionBounds - map bounds + * @property {Integer} marker - pile marker, icon color depending on status + * @property {Integer} markerOpts - marker options + */ angular.module('ldrWebApp').controller('ViewPileOnMapCtrl', ['$scope', '$rootScope', '$filter', 'leafletData', 'Pile', '$q', 'Auth', 'ImageUpload', 'LxNotificationService', 'MapHelperService', '$translate', 'responseHandler', function ($scope, $rootScope, $filter, leafletData, Pile, diff --git a/client/app/map/directives.js b/client/app/map/directives.js index 4a5e3f6..e2ea04c 100644 --- a/client/app/map/directives.js +++ b/client/app/map/directives.js @@ -1,4 +1,11 @@ angular.module('ldrWebApp') + /** + * @ngdoc directive + * @name markerPopup + * @description shows marker popup + * @example + *
+ */ .directive('markerPopup', function () { return { restrict: 'E', @@ -11,6 +18,15 @@ angular.module('ldrWebApp') } }; }) + /** + * @ngdoc directive + * @name markerDraggableUtil + * @description sets marker style while dragging + * @example + *
+ */ .directive('markerDraggableUtil', function () { return { restrict: 'A', @@ -25,6 +41,13 @@ angular.module('ldrWebApp') } }; }) + /** + * @ngdoc directive + * @name uploadPhoto + * @description upload photo step in create pile dialog + * @example + *
+ */ .directive('uploadPhoto', function () { return { restrict: 'AE', @@ -34,6 +57,13 @@ angular.module('ldrWebApp') } }; }) + /** + * @ngdoc directive + * @name pileCreation + * @description add pile details step in create pile dialog + * @example + *
+ */ .directive('pileCreation', function () { return { restrict: 'AE', @@ -43,6 +73,13 @@ angular.module('ldrWebApp') } }; }) + /** + * @ngdoc directive + * @name pileComments + * @description add pile comments step in create pile dialog + * @example + *
+ */ .directive('pileComments', function () { return { restrict: 'AE', @@ -52,6 +89,13 @@ angular.module('ldrWebApp') } }; }) + /** + * @ngdoc directive + * @name pileSummary + * @description pile summary step in create pile dialog + * @example + *
+ */ .directive('pileSummary', function () { return { restrict: 'AE', @@ -61,6 +105,13 @@ angular.module('ldrWebApp') } }; }) + /** + * @ngdoc directive + * @name issueModal + * @description report issue dialog + * @example + *
+ */ .directive('issueModal', function () { return { restrict: 'AE', @@ -70,6 +121,15 @@ angular.module('ldrWebApp') } }; }) + /** + * @ngdoc directive + * @name firefoxCompatibility + * @description listens to 'calculate-firefox' event, calculates drop location for firefox and broadcast 'resolved-position' event when done + * @example + *
+ */ .directive('firefoxCompatibility', ['$rootScope', function ($rootScope) { return { restrict: 'AE', diff --git a/client/app/map/directives/viewPileDetails.directive.js b/client/app/map/directives/viewPileDetails.directive.js index 11c1b1b..82dfaa9 100644 --- a/client/app/map/directives/viewPileDetails.directive.js +++ b/client/app/map/directives/viewPileDetails.directive.js @@ -1,5 +1,12 @@ 'use strict'; - +/** + * @ngdoc directive + * @name customCarousel + * @description directive for showing pile images, shows thumbnails and sets main image on click after calculating + * clicked image width and height, also binds magnificPopup to click event on main image, popup is closed on state change + * @example + *
+ */ angular.module('ldrWebApp') .directive('customCarousel', ['$timeout', 'PILE_IMAGE_CONFIG', function ($timeout, PILE_IMAGE_CONFIG) { return { diff --git a/client/app/map/filters/CreatePile.filter.js b/client/app/map/filters/CreatePile.filter.js index 378d896..212d4fb 100644 --- a/client/app/map/filters/CreatePile.filter.js +++ b/client/app/map/filters/CreatePile.filter.js @@ -1,6 +1,13 @@ 'use strict'; angular.module('ldrWebApp') + /** + * @ngdoc filter + * @name decToDms + * @description formats coordinates + * @example + *
+ */ .filter('decToDms', ['$sce', function ($sce) { return function (input, latlng) { var v = input.toString().split('.'); diff --git a/client/app/map/filters/capitalizeLetter.js b/client/app/map/filters/capitalizeLetter.js index 3f76101..72432a6 100644 --- a/client/app/map/filters/capitalizeLetter.js +++ b/client/app/map/filters/capitalizeLetter.js @@ -1,4 +1,11 @@ 'use strict'; +/** + * @ngdoc filter + * @name capitalizeFirstLetter + * @description capitalize first letter of string + * @example + *
[{{displayFilterValue('status') | capitalizeFirstLetter}}]
+ */ angular.module('ldrWebApp').filter('capitalizeFirstLetter', function () { return function (input) { diff --git a/client/app/privacy/privacy.controller.js b/client/app/privacy/privacy.controller.js index e0ea895..6cd628d 100644 --- a/client/app/privacy/privacy.controller.js +++ b/client/app/privacy/privacy.controller.js @@ -1,6 +1,14 @@ 'use strict'; - angular.module('ldrWebApp') + /** + * @ngdoc controller + * @name PrivacyCtrl + * @description privacy controller + * @requires $http + * @requires $scope + * @requires $translate + * @property {privacy} html containing privacy rules + */ .controller('PrivacyCtrl', ['$http', '$scope', '$translate', function ($http, $scope, $translate) { $http.get('/assets/pages/privacy_' + $translate.use() + '.html').success(function (data) { diff --git a/client/app/terms/terms.controller.js b/client/app/terms/terms.controller.js index a2d9f1d..0404e3f 100644 --- a/client/app/terms/terms.controller.js +++ b/client/app/terms/terms.controller.js @@ -1,6 +1,16 @@ 'use strict'; angular.module('ldrWebApp') + /** + * @ngdoc controller + * @name TermsCtrl + * @description terms controller + * @requires $http + * @requires $scope + * @requires $sce + * @requires $translate + * @property {terms} html containing terms and conditions + */ .controller('TermsCtrl', ['$http', '$scope', '$sce', '$translate', function ($http, $scope, $sce, $translate) { $http.get('/assets/pages/terms_' + $translate.use() + '.html').success(function (data) { diff --git a/client/components/IssueService/IssueService/IssueService.service.js b/client/components/IssueService/IssueService/IssueService.service.js index 3e0f2f4..3e0dbfc 100644 --- a/client/components/IssueService/IssueService/IssueService.service.js +++ b/client/components/IssueService/IssueService/IssueService.service.js @@ -1,6 +1,14 @@ 'use strict'; angular.module('ldrWebApp') + /** + * @ngdoc service + * @service + * @name Issue + * @description The issue service + * @requires $resource + * @requires API_URL + */ .service('Issues', ['$resource', 'API_URL', function ($resource, API_URL) { return $resource(API_URL + 'improves', {}, { query: {method: 'GET', isArray: false}, diff --git a/client/components/activities-service/activityService.js b/client/components/activities-service/activityService.js index 2a57400..4075e5d 100644 --- a/client/components/activities-service/activityService.js +++ b/client/components/activities-service/activityService.js @@ -1,6 +1,14 @@ 'use strict'; angular.module('ldrWebApp') + /** + * @ngdoc service + * @service + * @name Activity + * @description The activity service + * @requires $resource + * @requires API_URL + */ .service('Activity', ['$resource', 'API_URL', function ($resource, API_URL) { return $resource(API_URL + 'activities/:action', {}, { query: {method: 'GET', isArray: false}, diff --git a/client/components/auth/auth.service.js b/client/components/auth/auth.service.js index 6897311..1f53bdf 100644 --- a/client/components/auth/auth.service.js +++ b/client/components/auth/auth.service.js @@ -1,6 +1,20 @@ 'use strict'; angular.module('ldrWebApp') + /** + * @ngdoc service + * @service + * @name Auth + * @description The authentication service + * @requires $location + * @requires $rootScope + * @requires $http + * @requires $cookieStore + * @requires $q + * @requires responseHandler + * @requires $translate + * @requires AUTH_URL + */ .factory('Auth', function Auth($location, $rootScope, $http, User, $cookieStore, $q, responseHandler, $translate, AUTH_URL) { var currentUser = {}; @@ -10,10 +24,16 @@ angular.module('ldrWebApp') return { /** - * Authenticate user and save token - * @param {Object} user - login info + * @ngdoc + * @name Auth#login + * @methodOf Auth + * @param {Object} user - login info * @param {Function} callback - optional - * @return {Promise} + * @example + * Auth.login({email: user.email,password: user.password}) + * @description + * Tries to login a user + * @returns {Promise} Resolves to an empty response/error */ login: function (user, callback) { var cb = callback || angular.noop; @@ -37,6 +57,10 @@ angular.module('ldrWebApp') }, /** + * @ngdoc + * @name Auth#logout + * @methodOf Auth + * @description * Delete access token and user info */ logout: function () { @@ -46,10 +70,17 @@ angular.module('ldrWebApp') }, /** - * Create a new user - * @param {Object} user - user info + * @ngdoc + * @name Auth#createUser + * @methodOf Auth + * @param {Object} user - user info * @param {Function} callback - optional - * @return {Promise} + * @example + * Auth.createUser({terms: user.terms, pass: true,email: user.email, password: user.password1, + * first_name: user.first_name, last_name: user.last_name, language: mailLanguage}) + * @description + * Tries to create a user + * @returns {Promise} Resolves to an empty response/error */ createUser: function (user, callback) { var cb = callback || angular.noop; @@ -64,11 +95,17 @@ angular.module('ldrWebApp') }, /** - * Change password - * @param {String} oldPassword - * @param {String} newPassword - * @param {Function} callback - optional - * @return {Promise} + * @ngdoc + * @name Auth#changePassword + * @methodOf Auth + * @param {String} oldPassword - old password + * @param {String} newPassword - new password + * @param {Function} callback - optional + * @example + * Auth.changePassword($scope.pass.password0, $scope.pass.password1) + * @description + * Tries to change the password + * @returns {Promise} Resolves to an empty response/error */ changePassword: function (oldPassword, newPassword, callback) { var cb = callback || angular.noop; @@ -84,7 +121,10 @@ angular.module('ldrWebApp') }, /** - * Gets all available info on authenticated user + * @ngdoc + * @name Auth#getCurrentUser + * @methodOf Auth + * @description - Gets all available info on authenticated user * @return {Object} user */ getCurrentUser: function () { @@ -92,15 +132,20 @@ angular.module('ldrWebApp') }, /** - * Check if a user is logged in - * @return {Boolean} + * @ngdoc + * @name Auth#isLoggedIn + * @methodOf Auth + * @description - Check if a user is logged in */ isLoggedIn: function () { return responseHandler.getData(currentUser).hasOwnProperty('role'); }, /** - * Waits for currentUser to resolve before checking if user is logged in + * @ngdoc + * @name Auth#isLoggedInAsync + * @methodOf Auth + * @description - Waits for currentUser to resolve before checking if user is logged in */ isLoggedInAsync: function (cb) { if (currentUser.hasOwnProperty('$promise')) { @@ -117,23 +162,31 @@ angular.module('ldrWebApp') }, /** - * Check if a user is an admin - * @return {Boolean} + * @ngdoc + * @name Auth#isAdmin + * @methodOf Auth + * @description - Check if a user is an admin */ isAdmin: function () { return responseHandler.getData(currentUser).role === 'admin'; }, /** - * check user's role - * @param role - * @returns {boolean} + * @ngdoc + * @name Auth#hasRole + * @methodOf Auth + * @description - check user's role + * @param {String} - role */ hasRole: function (role) { return responseHandler.getData(currentUser).role === role; }, /** - * Get auth token + * @ngdoc + * @name Auth#getToken + * @methodOf Auth + * @description - Get auth token + * @returns {String} - token */ getToken: function () { return $cookieStore.get('token'); diff --git a/client/components/auth/user.service.js b/client/components/auth/user.service.js index 5d22bfb..402c65b 100644 --- a/client/components/auth/user.service.js +++ b/client/components/auth/user.service.js @@ -1,6 +1,14 @@ 'use strict'; angular.module('ldrWebApp') + /** + * @ngdoc service + * @service + * @name User + * @description The user service + * @requires $resource + * @requires API_URL + */ .factory('User', ['$resource', 'API_URL', function ($resource, API_URL) { return $resource(API_URL + 'users/:action/:salt/:token', {}, { diff --git a/client/components/authorities-service/authoritiesService.js b/client/components/authorities-service/authoritiesService.js index bd7f9ab..573fb63 100644 --- a/client/components/authorities-service/authoritiesService.js +++ b/client/components/authorities-service/authoritiesService.js @@ -1,6 +1,14 @@ 'use strict'; angular.module('ldrWebApp') + /** + * @ngdoc service + * @service + * @name Authority + * @description The authorities service + * @requires $resource + * @requires API_URL + */ .service('Authority', ['$resource', 'API_URL', function ($resource, API_URL) { return $resource(API_URL + 'authorities', {}, { get: {method: 'GET', isArray: false} diff --git a/client/components/city/city.service.js b/client/components/city/city.service.js index 264c421..68c3404 100644 --- a/client/components/city/city.service.js +++ b/client/components/city/city.service.js @@ -1,6 +1,14 @@ 'use strict'; angular.module('ldrWebApp') + /** + * @ngdoc service + * @service + * @name City + * @description Get cities service + * @requires $resource + * @requires API_URL + */ .factory('City', function ($resource,API_URL) { return $resource(API_URL + 'cities/:id/:county/:countyId', { diff --git a/client/components/comments/comments.service.js b/client/components/comments/comments.service.js index f87150b..f9f2e2b 100644 --- a/client/components/comments/comments.service.js +++ b/client/components/comments/comments.service.js @@ -1,6 +1,14 @@ 'use strict'; angular.module('ldrWebApp') + /** + * @ngdoc service + * @service + * @name CommentsService + * @description Get comments service + * @requires $resource + * @requires API_URL + */ .factory('CommentsService', ['$resource', 'API_URL', function ($resource, API_URL) { return $resource(API_URL + 'comments', {}, { diff --git a/client/components/contact/contact.service.js b/client/components/contact/contact.service.js index a234cf3..1144319 100644 --- a/client/components/contact/contact.service.js +++ b/client/components/contact/contact.service.js @@ -1,6 +1,14 @@ 'use strict'; angular.module('ldrWebApp') + /** + * @ngdoc service + * @service + * @name ContactService + * @description create contact note service + * @requires $resource + * @requires API_URL + */ .factory('ContactService', ['$resource', 'API_URL', function ($resource, API_URL) { return $resource(API_URL + 'contact', {}, { diff --git a/client/components/country/country.service.js b/client/components/country/country.service.js index ccc4e6e..04de56d 100644 --- a/client/components/country/country.service.js +++ b/client/components/country/country.service.js @@ -1,5 +1,13 @@ (function (module) { 'use strict'; + /** + * @ngdoc service + * @service + * @name CountryService + * @description Get countries service + * @requires $resource + * @requires API_URL + */ module.factory('CountryService', CountryService); CountryService.$inject = ['$resource', 'API_URL']; function CountryService($resource, API_URL) { diff --git a/client/components/county/county.service.js b/client/components/county/county.service.js index eb2c5ab..e49a4f4 100644 --- a/client/components/county/county.service.js +++ b/client/components/county/county.service.js @@ -1,6 +1,14 @@ 'use strict'; angular.module('ldrWebApp') + /** + * @ngdoc service + * @service + * @name County + * @description get counties service + * @requires $resource + * @requires API_URL + */ .factory('County', ['$resource', 'API_URL', function ($resource, API_URL) { return $resource(API_URL + 'counties/:id', {id: '@_id'}, diff --git a/client/components/custom-ratings/custom-ratings.directive.js b/client/components/custom-ratings/custom-ratings.directive.js index 617d5e1..4f20e8d 100644 --- a/client/components/custom-ratings/custom-ratings.directive.js +++ b/client/components/custom-ratings/custom-ratings.directive.js @@ -1,3 +1,10 @@ +/** + * @ngdoc directive + * @name customRatings + * @description pile sizes directive + * @example + *
+ */ angular.module('customRatings', []).directive('customRatings', [function () { return { restrict: 'E', diff --git a/client/components/date-picker/js/date-picker_directive.js b/client/components/date-picker/js/date-picker_directive.js index 86cefdc..7f69ce3 100644 --- a/client/components/date-picker/js/date-picker_directive.js +++ b/client/components/date-picker/js/date-picker_directive.js @@ -1,6 +1,14 @@ 'use strict'; angular.module('ldrWebApp') + /** + * @ngdoc controller + * @name customDatePickerController + * @description custom date picker controller + * @requires $scope + * @requires $timeout + * @requires $window + */ .controller('customDatePickerController', ['$scope', '$timeout', '$window', function ($scope, $timeout, $window) { var self = this, activeLocale, @@ -170,6 +178,15 @@ angular.module('ldrWebApp') } }]) + /** + * @ngdoc directive + * @name customDatePicker + * @description custom date picker directive + * @example + *
+ */ .directive('customDatePicker', function () { return { restrict: 'AE', diff --git a/client/components/environment/environment.service.js b/client/components/environment/environment.service.js index 9aa0756..6b9ace6 100644 --- a/client/components/environment/environment.service.js +++ b/client/components/environment/environment.service.js @@ -1,5 +1,12 @@ 'use strict'; - +/** + * @ngdoc service + * @service + * @name Environment + * @description Get environment variables + * @requires $resource + * @requires API_URL + */ angular.module('ldrWebApp') .factory('Environment', ['$resource', 'API_URL', function ($resource, API_URL) { return $resource(API_URL + 'environment', {}, diff --git a/client/components/help/help.factory.js b/client/components/help/help.factory.js index 68873f0..601ecad 100644 --- a/client/components/help/help.factory.js +++ b/client/components/help/help.factory.js @@ -1,8 +1,26 @@ 'use strict'; angular.module('ldrWebApp') + /** + * @ngdoc service + * @service + * @name Help + * @description help service + * @requires $rootScope + * @requires Auth + */ .factory('Help', ['$rootScope', 'Auth', function ($rootScope, Auth) { return { + /** + * @ngdoc method + * @name Help#tutorial + * @methodOf Help + * @example + * var items = Help.tutorial(0); + * @description + * calculates map resolution depending on screen resolution and browser used + * @returns {Array} help step image required + */ tutorial: function (id) { switch (id) { case 0: @@ -31,6 +49,17 @@ angular.module('ldrWebApp') return []; } }, + /** + * @ngdoc method + * @name Help#display + * @methodOf Help + * @param {Object} items - items to display + * @param {Function} callback - callback function + * @example + * Help.display(items); + * @description + * displays magnificPopup + */ display: function (items, callback) { callback = callback || angular.noop; $.magnificPopup.open({ diff --git a/client/components/helper-service/helperService.js b/client/components/helper-service/helperService.js index 4125321..5292c2e 100644 --- a/client/components/helper-service/helperService.js +++ b/client/components/helper-service/helperService.js @@ -1,7 +1,24 @@ 'use strict'; - +/** + * @ngdoc service + * @service + * @name HelperService + * @description helper service + * @requires $q + * @requires $translate + */ angular.module('ldrWebApp').factory('HelperService', ['$q', '$translate', function ($q, $translate) { return { + /** + * @ngdoc method + * @name HelperService#configObjectReport + * @methodOf HelperService + * @example + * countryStatistics.push(HelperService.configObjectReport(statsTotal, 'Total', null, 'total')); + * @description + * configures report object + * @returns {Object} config object + */ configObjectReport: function (object, label, i, type) { type = typeof type !== 'undefined' ? type : 'row'; @@ -57,6 +74,16 @@ angular.module('ldrWebApp').factory('HelperService', ['$q', '$translate', functi return o; }, + /** + * @ngdoc method + * @name HelperService#headerOnCsv + * @methodOf HelperService + * @example + * $scope.data.unshift(HelperService.headerOnCsv('County')); + * @description + * configures csv header + * @returns {Object} config object + */ headerOnCsv: function (locationHeader) { var headerObject = { id: 'ID', @@ -89,6 +116,15 @@ angular.module('ldrWebApp').factory('HelperService', ['$q', '$translate', functi }; return headerObject; }, + /** + * @ngdoc method + * @name HelperService#generateThumbnail + * @methodOf HelperService + * @example + * $scope.getThumbnail = HelperService.generateThumbnail; + * @description + * generates specified image thumbnail + */ generateThumbnail: function (image) { var deferred = $q.defer(); @@ -100,6 +136,15 @@ angular.module('ldrWebApp').factory('HelperService', ['$q', '$translate', functi reader.readAsDataURL(image); return deferred.promise; }, + /** + * @ngdoc method + * @name HelperService#getPileMaterials + * @methodOf HelperService + * @example + * $scope.materials = HelperService.getPileMaterials(); + * @description + * translated pile materials + */ getPileMaterials: function () { return angular.copy([ {name: $translate.instant('helperService.plastic'), type: 'Plastic', selected: false}, @@ -114,6 +159,15 @@ angular.module('ldrWebApp').factory('HelperService', ['$q', '$translate', functi {name: $translate.instant('helperService.other'), type: 'Other', selected: false} ]); }, + /** + * @ngdoc method + * @name HelperService#getPileAreas + * @methodOf HelperService + * @example + * $scope.areas = HelperService.getPileAreas(); + * @description + * translated pile ares + */ getPileAreas: function () { return angular.copy([ {name: $translate.instant('helperService.cityArea'), type: 'city', selected: false}, @@ -123,6 +177,15 @@ angular.module('ldrWebApp').factory('HelperService', ['$q', '$translate', functi {name: $translate.instant('helperService.otherArea'), type: 'other', selected: false} ]); }, + /** + * @ngdoc method + * @name HelperService#getUserRoles + * @methodOf HelperService + * @example + * $scope.roles = HelperService.getUserRoles(); + * @description + * translated user roles + */ getUserRoles: function () { return angular.copy([ {name: $translate.instant('helperService.volunteerRole'), value: 'Volunteer', type: 'volunteer'}, @@ -130,6 +193,15 @@ angular.module('ldrWebApp').factory('HelperService', ['$q', '$translate', functi {name: $translate.instant('helperService.adminRole'), value: 'admin', type: 'admin'} ]); }, + /** + * @ngdoc method + * @name HelperService#getUserStatuses + * @methodOf HelperService + * @example + * $scope.statuses = HelperService.getUserStatuses(); + * @description + * translated user statuses + */ getUserStatuses: function () { return angular.copy([ {name: $translate.instant('helperService.active'), type: 'active', value: 'Active'}, @@ -137,6 +209,15 @@ angular.module('ldrWebApp').factory('HelperService', ['$q', '$translate', functi {name: $translate.instant('helperService.inactive'), type: 'inactive', value: 'Inactive'} ]); }, + /** + * @ngdoc method + * @name HelperService#getPileStatuses + * @methodOf HelperService + * @example + * $scope.statuses = HelperService.getPileStatuses(); + * @description + * translated pile statuses + */ getPileStatuses: function () { return angular.copy([ {name: $translate.instant('helperService.allPile'), type: null, value: 'All'}, @@ -147,6 +228,15 @@ angular.module('ldrWebApp').factory('HelperService', ['$q', '$translate', functi {name: $translate.instant('helperService.cleanedPile'), type: 'clean', value: 'Cleaned'} ]); }, + /** + * @ngdoc method + * @name HelperService#getAvailableLanguages + * @methodOf HelperService + * @example + * $scope.availableLanguages = HelperService.getAvailableLanguages(); + * @description + * gets available languages + */ getAvailableLanguages: function () { return angular.copy([ {name: $translate.instant('helperService.english'), type: 'en', value: 'en'}, diff --git a/client/components/image-upload/image-upload.service.js b/client/components/image-upload/image-upload.service.js index 8d0378c..cc0fde2 100644 --- a/client/components/image-upload/image-upload.service.js +++ b/client/components/image-upload/image-upload.service.js @@ -1,9 +1,31 @@ 'use strict'; angular.module('ldrWebApp') + /** + * @ngdoc service + * @service + * @name ImageUpload + * @description The image upload service + * @requires Upload + * @requires $q + * @requires $http + * @requires responseHandler + * @requires API_URL + */ .factory('ImageUpload', ['Upload', '$q', '$http', 'responseHandler', 'API_URL', function (Upload, $q, $http, responseHandler, API_URL) { return { + /** + * @name ImageUpload#upload + * @example + * ImageUpload.upload(file, 'user').then(function (success) {},function () {}, function () {}); + * @param {Object} imageBody - image body + * @param {String} imageType - image type + * @param {String} referenceID - pile containing image id + * @description + * uploads image + * @returns {Promise} Resolves to an empty response/error + */ upload: function (imageBody, imageType, referenceID) { var deferred = $q.defer(); Upload.upload({ @@ -24,6 +46,19 @@ angular.module('ldrWebApp') }); return deferred.promise; }, + /** + * @name ImageUpload#uploadScreenshot + * @example + * ImageUpload.uploadScreenshot($scope.mapScreenshot, $scope.width, $scope.height, 'pile', parent.pile._id) + * @param {Object} screenshotBase64 - screenshot image in base64 + * @param {Integer} width + * @param {Integer} height + * @param {String} imageType - image type + * @param {String} referenceID - pile containing image id + * @description + * uploads screenshot image + * @returns {Promise} Resolves to an empty response/error + */ uploadScreenshot: function (screenshotBase64, width, height, imageType, referenceID) { var deferred = $q.defer(); Upload.upload({ @@ -49,6 +84,15 @@ angular.module('ldrWebApp') }); return deferred.promise; }, + /** + * @name ImageUpload#remove + * @example + * ImageUpload.remove($scope.allImages[$scope.allImages.index]._id) + * @param {Object} image_id - image id to remove + * @description + * removes image + * @returns {Promise} Resolves to an empty response/error + */ remove: function (image_id) { var deferred = $q.defer(); $http.delete(API_URL + 'images', { diff --git a/client/components/mongoose-error/mongoose-error.directive.js b/client/components/mongoose-error/mongoose-error.directive.js index 554ae84..014fa35 100644 --- a/client/components/mongoose-error/mongoose-error.directive.js +++ b/client/components/mongoose-error/mongoose-error.directive.js @@ -1,5 +1,12 @@ 'use strict'; angular.module('ldrWebApp') + /** + * @ngdoc directive + * @name mongooseError + * @description sets model's mongoose validity to true + * @example + *
+ */ .directive('mongooseError', function () { return { restrict: 'A', diff --git a/client/components/pile-service/pilesService.js b/client/components/pile-service/pilesService.js index 00fd6ee..f702619 100644 --- a/client/components/pile-service/pilesService.js +++ b/client/components/pile-service/pilesService.js @@ -1,6 +1,14 @@ 'use strict'; angular.module('ldrWebApp') + /** + * @ngdoc service + * @service + * @name Pile + * @description The pile service + * @requires $resource + * @requires API_URL + */ .service('Pile', ['$resource', 'API_URL', function ($resource, API_URL) { return $resource(API_URL + 'piles/:action', {}, { query: {method: 'GET', isArray: false}, diff --git a/client/components/preloader/preloader.factory.js b/client/components/preloader/preloader.factory.js index 786eae3..ce288e4 100644 --- a/client/components/preloader/preloader.factory.js +++ b/client/components/preloader/preloader.factory.js @@ -1,3 +1,15 @@ +/** + * @ngdoc service + * @service + * @name preloader + * @description The image preloader service + * @requires $q + * @requires $rootScope + * @property {Object} imageLocations - array of images's sources + * @property {Integer} loadCount - load count + * @property {Integer} errorCount - error count + * @property {Boolean} states - possible states that preloader can be in + */ angular.module('preloader', []).factory('preloader', ['$q', '$rootScope', function ($q, $rootScope) { function Preloader(imageLocations) { this.imageLocations = imageLocations; @@ -15,6 +27,14 @@ angular.module('preloader', []).factory('preloader', ['$q', '$rootScope', functi this.promise = this.deferred.promise; } + /** + * @name preloader#preloadImages + * @example + * preloader.preloadImages([imageUrl]).then(function handleResolve() {}, function handleReject() {}); + * @description + * reloads given images and returns a promise + * @returns {Promise} Resolves with the array of image locations. + */ Preloader.preloadImages = function (imageLocations) { var preloader = new Preloader(imageLocations); return (preloader.load()); @@ -30,6 +50,15 @@ angular.module('preloader', []).factory('preloader', ['$q', '$rootScope', functi isResolved: function isResolved() { return (this.state === this.states.RESOLVED); }, + + /** + * @name preloader#load + * @example + * return (preloader.load()); + * @description + * if the images are already loading, return the existing promise. + * @returns {Promise} Resolves with the array of image locations. + */ load: function load() { if (this.isInitiated()) { return (this.promise); @@ -40,6 +69,13 @@ angular.module('preloader', []).factory('preloader', ['$q', '$rootScope', functi } return (this.promise); }, + /** + * @name preloader#handleImageError + * @example + * preloader.handleImageError(event.target.src); + * @description + * handles load-failure of given image location + */ handleImageError: function handleImageError(imageLocation) { this.errorCount++; if (this.isRejected()) { @@ -48,6 +84,13 @@ angular.module('preloader', []).factory('preloader', ['$q', '$rootScope', functi this.state = this.states.REJECTED; this.deferred.reject(imageLocation); }, + /** + * @name preloader#handleImageLoad + * @example + * preloader.handleImageLoad(event.target.src); + * @description + * notifies the progress of the overall deferred + */ handleImageLoad: function handleImageLoad(imageLocation) { this.loadCount++; if (this.isRejected()) { @@ -62,6 +105,13 @@ angular.module('preloader', []).factory('preloader', ['$q', '$rootScope', functi this.deferred.resolve(this.imageLocations); } }, + /** + * @name preloader#loadImageLocation + * @example + * this.loadImageLocation(this.imageLocations[i]); + * @description + * binds the event handlers before setting the image source + */ loadImageLocation: function loadImageLocation(imageLocation) { var preloader = this; var image = $(new Image()) diff --git a/gulpfile.js b/gulpfile.js index 877cf91..b5bc19d 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -82,6 +82,30 @@ gulp.task('findDamagedAuthorities', function () { }); }); +gulp.task('ngdocs', [], function () { + var gulpDocs = require('gulp-ngdocs'); + + var options = { + scripts: [ + 'http://ajax.googleapis.com/ajax/libs/angularjs/1.5.8/angular.min.js', + 'http://ajax.googleapis.com/ajax/libs/angularjs/1.5.8/angular-animate.min.js' + ] + }; + + return gulp.src(['server/api/activity/*.js']) + .pipe(gulpDocs.process(options)) + .pipe(gulp.dest('./docs')); +}); +gulp.task('connect_ngdocs', function() { + var connect = require('gulp-connect'); + connect.server({ + root: 'docs', + livereload: false, + fallback: 'docs/index.html', + port: 8083 + }); +}); + function findDamagedAuthorities(filterIds) { var query = {fax: new RegExp('rofax', 'i')}; if (filterIds) query['_id'] = {$in: filterIds}; diff --git a/package.json b/package.json index 465c16a..99bebd7 100644 --- a/package.json +++ b/package.json @@ -25,6 +25,7 @@ "gm": "latest", "html-pdf": "latest", "jsonwebtoken": "^0.3.0", + "kue": "~0.11.x", "lodash": "~2.4.1", "mandrill-api": "^1.0.41", "method-override": "~1.0.0", @@ -45,12 +46,15 @@ "raven": "^0.12.1", "request": "latest", "serve-favicon": "~2.0.1", - "kue": "~0.11.x" + "swagger-jsdoc": "^1.8.2" }, "devDependencies": { + "connect-livereload": "~0.4.0", "grunt": "~0.4.4", + "grunt-angular-templates": "^0.5.4", + "grunt-asset-injector": "^0.1.0", "grunt-autoprefixer": "~0.7.2", - "grunt-wiredep": "~1.8.0", + "grunt-build-control": "DaftMonk/grunt-build-control", "grunt-concurrent": "~0.5.0", "grunt-contrib-clean": "~0.5.0", "grunt-contrib-concat": "~0.4.0", @@ -59,57 +63,55 @@ "grunt-contrib-htmlmin": "~0.2.0", "grunt-contrib-imagemin": "~0.7.1", "grunt-contrib-jshint": "~0.10.0", + "grunt-contrib-sass": "^0.7.3", "grunt-contrib-uglify": "~0.4.0", "grunt-contrib-watch": "~0.6.1", + "grunt-dom-munger": "^3.4.0", + "grunt-env": "~0.4.1", + "grunt-express-server": "~0.4.17", "grunt-google-cdn": "~0.4.0", + "grunt-karma": "~0.8.2", + "grunt-mocha-test": "~0.10.2", "grunt-newer": "~0.7.0", "grunt-ng-annotate": "^0.2.3", - "grunt-rev": "~0.1.0", - "grunt-svgmin": "~0.4.0", - "grunt-usemin": "~2.1.1", - "grunt-env": "~0.4.1", "grunt-node-inspector": "~0.1.5", "grunt-nodemon": "~0.2.0", - "grunt-angular-templates": "^0.5.4", - "grunt-dom-munger": "^3.4.0", + "grunt-open": "~0.2.3", "grunt-protractor-runner": "^1.1.0", - "grunt-asset-injector": "^0.1.0", - "grunt-karma": "~0.8.2", - "grunt-build-control": "DaftMonk/grunt-build-control", - "grunt-mocha-test": "~0.10.2", - "grunt-contrib-sass": "^0.7.3", + "grunt-rev": "~0.1.0", + "grunt-svgmin": "~0.4.0", + "grunt-usemin": "~2.1.1", + "grunt-wiredep": "~1.8.0", + "gulp": "latest", + "gulp-concat": "latest", + "gulp-ngdocs": "^0.3.0", + "gulp-nodemon": "latest", + "gulp-notify": "latest", + "gulp-util": "latest", + "gulp-watch": "latest", + "gulp-webserver": "latest", "jit-grunt": "^0.5.0", - "time-grunt": "~0.3.1", - "grunt-express-server": "~0.4.17", - "grunt-open": "~0.2.3", - "open": "~0.0.4", "jshint-stylish": "~0.1.5", - "connect-livereload": "~0.4.0", - "karma-ng-scenario": "~0.1.0", - "karma-firefox-launcher": "~0.1.3", - "karma-script-launcher": "~0.1.0", - "karma-html2js-preprocessor": "~0.1.0", - "karma-ng-jade2js-preprocessor": "^0.1.2", - "karma-jasmine": "~0.1.5", + "karma": "~0.12.9", "karma-chrome-launcher": "~0.1.3", - "requirejs": "~2.1.11", - "karma-requirejs": "~0.2.1", "karma-coffee-preprocessor": "~0.2.1", + "karma-firefox-launcher": "~0.1.3", + "karma-html2js-preprocessor": "~0.1.0", "karma-jade-preprocessor": "0.0.11", - "karma-phantomjs-launcher": "~0.1.4", - "karma": "~0.12.9", + "karma-jasmine": "~0.1.5", "karma-ng-html2js-preprocessor": "~0.1.0", - "supertest": "~0.11.0", + "karma-ng-jade2js-preprocessor": "^0.1.2", + "karma-ng-scenario": "~0.1.0", + "karma-phantomjs-launcher": "~0.1.4", + "karma-requirejs": "~0.2.1", + "karma-script-launcher": "~0.1.0", + "mongodb": "latest", + "open": "~0.0.4", + "requirejs": "~2.1.11", "should": "~3.3.1", - "gulp": "latest", - "gulp-concat": "latest", - "gulp-notify": "latest", - "gulp-util": "latest", - "gulp-watch": "latest", - "gulp-webserver": "latest", - "gulp-nodemon": "latest", - "yargs": "latest", - "mongodb": "latest" + "supertest": "~0.11.0", + "time-grunt": "~0.3.1", + "yargs": "latest" }, "engines": { "node": ">=0.10.0" diff --git a/server/api/activity/activity.controller.js b/server/api/activity/activity.controller.js index 9202915..0d6d57a 100644 --- a/server/api/activity/activity.controller.js +++ b/server/api/activity/activity.controller.js @@ -4,22 +4,29 @@ var PileService = require('../pile/pile.service'); var env = require('../../config/environment'); +/** + * @name findAllMine + * @function + * @description finds all activities related to the user initiating the request, if the user is a volunteer we get all + * the activities that refer to reported piles by the user, if the user is a supervisor we get all the activities + * related to piles in user's county + * we query for activities that refer to the pile_ids obtained, since the activities' "viewed" field is an array of + * users that viewed the activity, we need to return it as a boolean being true if the user is found in the array and + * false otherwise + * @param {Object} req + * @param {Object} res + */ exports.findAllMine = function (req, res) { User.findOne({_id: req.user._id}).exec(function (err, user) { if (err) { handleError(res, 'No user'); } else { - //init pagination vars var page = req.query.page || 1; var limit = req.query.limit || env.defaultPaginationLimit; page = page - 1; if (page < 0) { page = 0; } - - //we will differentiate the response based on the user initiating the request - //if user is a volunteer we need to get all the activities that refer to a pile reported by this user - //if user is a supervisor we need to get all the activities that refer to a pile located in the user's county var promisedPileIds; if (user.role === 'volunteer') { promisedPileIds = PileService.getPileIds(user._id); @@ -30,9 +37,7 @@ exports.findAllMine = function (req, res) { } promisedPileIds.then( function (pile_ids) { - //now we can query for activities that refer to the pile_ids obtained - //since the activities' "viewed" field is an array of users that viewed the activity, - //we need to return it as a boolean being true if the user is found in the array and false otherwise + var cursor = Activity.aggregate([ {$match: {pile: {$in: pile_ids}}}, {$sort: {date_created: -1}}, @@ -71,6 +76,13 @@ exports.findAllMine = function (req, res) { }); }; +/** + * @name markAsViewed + * @function + * @description marks activity as viewed + * @param {Object} req + * @param {Object} res + */ exports.markAsViewed = function (req, res) { if (req.query.id) { Activity.update({_id: req.query.id}, {$addToSet: {viewed: req.user._id}}, function (err) { diff --git a/server/api/activity/activity.service.js b/server/api/activity/activity.service.js index 7372172..fa59cd2 100644 --- a/server/api/activity/activity.service.js +++ b/server/api/activity/activity.service.js @@ -7,7 +7,15 @@ var PileService = require('../pile/pile.service'); var Q = require('q'); -// Creates a new activity +/** + * @name create + * @function + * @description creates a new activity + * @param {String} actor_id + * @param {String} verb + * @param {String} pile_id + * @returns {Promise} + */ exports.create = function (actor_id, verb, pile_id) { var deferred = Q.defer(); var activity = new Activity({ @@ -33,6 +41,13 @@ exports.create = function (actor_id, verb, pile_id) { return deferred.promise; }; +/** + * @name countUnread + * @function + * @description counts unread activities + * @param {Object} user + * @returns {Promise} + */ exports.countUnread = function (user) { var deferred = Q.defer(); var county; @@ -56,6 +71,13 @@ exports.countUnread = function (user) { return deferred.promise; }; +/** + * @name getIdsOfPilesContributedTo + * @function + * @description gets piles that specified user contributed to + * @param {String} user_id + * @returns {Promise} + */ exports.getIdsOfPilesContributedTo = function (user_id) { var deferred = Q.defer(); Activity.aggregate([ diff --git a/server/api/activity/index.js b/server/api/activity/index.js index df91c59..73dd0e3 100644 --- a/server/api/activity/index.js +++ b/server/api/activity/index.js @@ -6,7 +6,27 @@ var auth = require('../../auth/auth.service'); var router = express.Router(); +/** + * @swagger + * /activity: + * get: + * responses: + * 200: + * description: activities of the user that initiated the request + * 400: + * description: user hasn't the required role + */ router.get('/', auth.isAuthenticated(), controller.findAllMine); +/** + * @swagger + * /activity/viewed: + * post: + * responses: + * 200: + * description: activity successfully marked as read + * 400: + * description: query missing id + */ router.post('/viewed', auth.isAuthenticated(), controller.markAsViewed); module.exports = router; diff --git a/server/api/authority/authority.controller.js b/server/api/authority/authority.controller.js index 37c9491..346c0ff 100644 --- a/server/api/authority/authority.controller.js +++ b/server/api/authority/authority.controller.js @@ -3,7 +3,13 @@ var _ = require('lodash'); var Authority = require('./authority.model'); -// Get list of authorities +/** + * @name find + * @function + * @description find authority + * @param {Object} req + * @param {Object} res + */ exports.find = function (req, res) { var cursor; if (req.query.id) { diff --git a/server/api/authority/authority.service.js b/server/api/authority/authority.service.js index ebddc04..11b2544 100644 --- a/server/api/authority/authority.service.js +++ b/server/api/authority/authority.service.js @@ -10,6 +10,13 @@ var UtilsService = require('../../components/utils'); var Q = require('q'); +/** + * @name validateAuthorityId + * @function + * @description checks if authority has id + * @param {String} authority_id + * @param {Object} authority_city + */ exports.validateAuthorityId = function (authority_id, authority_city) { var deferred = Q.defer(); Authority.findOne({_id: authority_id, city: authority_city}, function (err, authority) { @@ -22,6 +29,13 @@ exports.validateAuthorityId = function (authority_id, authority_city) { return deferred.promise; }; +/** + * @name sendToAuthority + * @function + * @description sends mail to authority + * @param {String} authority_id + * @param {Object} buffer + */ exports.sendToAuthority = function (authority_id, buffer) { var deferred = Q.defer(); Authority.findOne({_id: authority_id}).populate('city').exec(function (err, authority) { diff --git a/server/api/authority/index.js b/server/api/authority/index.js index e181f14..07d46c3 100644 --- a/server/api/authority/index.js +++ b/server/api/authority/index.js @@ -7,6 +7,16 @@ var router = express.Router(); var auth = require('../../auth/auth.service'); +/** + * @swagger + * /authority: + * get: + * responses: + * 200: + * description: authority required + * 500: + * description: server error + */ router.get('/', auth.hasRole('supervisor'), controller.find); -module.exports = router; \ No newline at end of file +module.exports = router; diff --git a/server/api/city/city.controller.js b/server/api/city/city.controller.js index a914919..7c7c988 100644 --- a/server/api/city/city.controller.js +++ b/server/api/city/city.controller.js @@ -3,7 +3,13 @@ var _ = require('lodash'); var City = require('./city.model'); -// Get list of citys +/** + * @name index + * @function + * @description gets list of all cities or cities in county + * @param {Object} req + * @param {Object} res + */ exports.index = function (req, res) { var params = {}; if (req.params.id === 'all' && req.params.countyId !== undefined) { @@ -17,7 +23,13 @@ exports.index = function (req, res) { }); }; -// Get a single city +/** + * @name show + * @function + * @description gets single city + * @param {Object} req + * @param {Object} res + */ exports.show = function (req, res) { City.findById(req.params.id, function (err, city) { if (err) { diff --git a/server/api/city/city.service.js b/server/api/city/city.service.js index 8a07240..7fb6d42 100644 --- a/server/api/city/city.service.js +++ b/server/api/city/city.service.js @@ -5,6 +5,12 @@ var County = require('../county/county.model'); var Q = require('q'); +/** + * @name getCity + * @function + * @description gets single city by siruta code, if no city checks counties from Moldova + * @param {String} siruta + */ exports.getCity = function (siruta) { var deferred = Q.defer(); City.findOne({siruta: siruta}, function (err, city) { diff --git a/server/api/city/index.js b/server/api/city/index.js index da47854..b15ca5e 100644 --- a/server/api/city/index.js +++ b/server/api/city/index.js @@ -5,8 +5,34 @@ var controller = require('./city.controller'); var router = express.Router(); +/** + * @swagger + * /city: + * get: + * responses: + * 200: + * description: all cities object + */ router.get('/', controller.index); +/** + * @swagger + * /city/:id/county/:countyId: + * get: + * responses: + * 200: + * description: cities in specific county object + */ router.get('/:id/county/:countyId', controller.index); +/** + * @swagger + * /city/:id: + * get: + * responses: + * 200: + * description: specific city object + * 404: + * description: city not found + */ router.get('/:id', controller.show); module.exports = router; diff --git a/server/api/comments/comment.controller.js b/server/api/comments/comment.controller.js index 3a3383a..561679a 100644 --- a/server/api/comments/comment.controller.js +++ b/server/api/comments/comment.controller.js @@ -2,6 +2,13 @@ var Comment = require('./comment.model'); +/** + * @name show + * @function + * @description gets single comment + * @param {Object} req + * @param {Object} res + */ exports.show = function (req, res) { if (req.query.pile) { Comment.find({pile: req.query.pile}, function (err, comments) { @@ -16,6 +23,13 @@ exports.show = function (req, res) { } }; +/** + * @name create + * @function + * @description creates comment + * @param {Object} req + * @param {Object} res + */ exports.create = function (req, res) { if (req.query.pile) { var comment = new Comment(req.body); diff --git a/server/api/comments/comment.service.js b/server/api/comments/comment.service.js index 2e6a0ad..a47f903 100644 --- a/server/api/comments/comment.service.js +++ b/server/api/comments/comment.service.js @@ -4,6 +4,12 @@ var Q = require('q'); var Comment = require('./comment.model'); +/** + * @name countCommentsBy + * @function + * @description counts specific user comments + * @param {String} user_id + */ exports.countCommentsBy = function (user_id) { var deferred = Q.defer(); Comment.count({user: user_id}, function (err, count) { diff --git a/server/api/comments/index.js b/server/api/comments/index.js index 1ec2ef7..adc0700 100644 --- a/server/api/comments/index.js +++ b/server/api/comments/index.js @@ -6,7 +6,31 @@ var auth = require('../../auth/auth.service'); var router = express.Router(); +/** + * @swagger + * /comments: + * get: + * responses: + * 200: + * description: comments associated to pile + * 400: + * description: query missing pile object + * 500: + * description: server error + */ router.get('/', auth.isAuthenticated(), controller.show); +/** + * @swagger + * /comments: + * post: + * responses: + * 200: + * description: comment successfully created + * 400: + * description: query missing pile object + * 500: + * description: server error + */ router.post('/', auth.isAuthenticated(), controller.create); module.exports = router; diff --git a/server/api/contact/contact.controller.js b/server/api/contact/contact.controller.js index 31aae49..e144e09 100644 --- a/server/api/contact/contact.controller.js +++ b/server/api/contact/contact.controller.js @@ -1,6 +1,13 @@ var env = require('../../config/environment'); var mailer = require('../../components/mailer'); +/** + * @name create + * @function + * @description sends mail with contact note + * @param {Object} req + * @param {Object} res + */ exports.create = function (req, res) { mailer.send( 'contact', diff --git a/server/api/contact/index.js b/server/api/contact/index.js index 8be0f5a..7c40283 100644 --- a/server/api/contact/index.js +++ b/server/api/contact/index.js @@ -4,6 +4,16 @@ var express = require('express'); var controller = require('./contact.controller'); var router = express.Router(); +/** + * @swagger + * /contact: + * post: + * responses: + * 200: + * description: mail successfully sent + * 500: + * description: server error + */ router.post('/', controller.create); -module.exports = router; \ No newline at end of file +module.exports = router; diff --git a/server/api/counter/counter.service.js b/server/api/counter/counter.service.js index c2ae279..d154831 100644 --- a/server/api/counter/counter.service.js +++ b/server/api/counter/counter.service.js @@ -4,6 +4,12 @@ var Counter = require('./counter.model'); var Q = require('q'); +/** + * @name getNextSequence + * @function + * @description atomically increment the seq value and return this new value + * @param {String} type + */ exports.getNextSequence = function (type) { var deferred = Q.defer(); Counter.findAndModify({type: type}, {}, {$inc: {seq: 1}}, {new: true}, function (err, counter) { diff --git a/server/api/country/country.controller.js b/server/api/country/country.controller.js index bbe723f..45acf60 100644 --- a/server/api/country/country.controller.js +++ b/server/api/country/country.controller.js @@ -2,7 +2,13 @@ var Countries = require('./country.model'); -// Gets a list of Countrys +/** + * @name index + * @function + * @description gets all countries + * @param {Object} req + * @param {Object} res + */ function index(req, res) { Countries.find({}, function (err, countries) { if (err) { diff --git a/server/api/country/index.js b/server/api/country/index.js index e0cd87b..127e7e6 100644 --- a/server/api/country/index.js +++ b/server/api/country/index.js @@ -5,6 +5,16 @@ var controller = require('./country.controller'); var router = express.Router(); +/** + * @swagger + * /country: + * get: + * responses: + * 200: + * description: countries object + * 500: + * description: server error + */ router.get('/', controller.index); module.exports = router; diff --git a/server/api/county/county.controller.js b/server/api/county/county.controller.js index deda000..ef27ea1 100644 --- a/server/api/county/county.controller.js +++ b/server/api/county/county.controller.js @@ -3,7 +3,13 @@ var _ = require('lodash'); var County = require('./county.model'); -// Get list of counties +/** + * @name index + * @function + * @description gets all counties + * @param {Object} req + * @param {Object} res + */ exports.index = function (req, res) { var q = {}; if (req.query.country) { @@ -17,7 +23,13 @@ exports.index = function (req, res) { }); }; -// Get a single county +/** + * @name show + * @function + * @description gets single county + * @param {Object} req + * @param {Object} res + */ exports.show = function (req, res) { County.findById(req.params.id, function (err, county) { if (err) { diff --git a/server/api/county/county.service.js b/server/api/county/county.service.js index 910db38..27c9d49 100644 --- a/server/api/county/county.service.js +++ b/server/api/county/county.service.js @@ -4,6 +4,12 @@ var County = require('./county.model'); var Q = require('q'); +/** + * @name getCounty + * @function + * @description gets single county by siruta code + * @param {String} siruta + */ exports.getCounty = function (siruta) { var deferred = Q.defer(); County.findOne({siruta: siruta}, function (err, county) { diff --git a/server/api/county/index.js b/server/api/county/index.js index bee962b..db1f5b4 100644 --- a/server/api/county/index.js +++ b/server/api/county/index.js @@ -5,7 +5,27 @@ var controller = require('./county.controller'); var router = express.Router(); +/** + * @swagger + * /county: + * get: + * responses: + * 200: + * description: counties by country object + */ router.get('/', controller.index); +/** + * @swagger + * /county/:id: + * get: + * responses: + * 200: + * description: requested county object + * 404: + * description: requested county not found + * 500: + * description: server error + */ router.get('/:id', controller.show); -module.exports = router; \ No newline at end of file +module.exports = router; diff --git a/server/api/environment/environment.controller.js b/server/api/environment/environment.controller.js index bed1d5b..7dd458a 100644 --- a/server/api/environment/environment.controller.js +++ b/server/api/environment/environment.controller.js @@ -2,6 +2,13 @@ var env = require('../../config/environment'); +/** + * @name find + * @function + * @description gets all environment variables + * @param {Object} req + * @param {Object} res + */ exports.find = function (req, res) { res.handleResponse(200, { success: { diff --git a/server/api/environment/index.js b/server/api/environment/index.js index e92e46b..4cbeffc 100644 --- a/server/api/environment/index.js +++ b/server/api/environment/index.js @@ -6,6 +6,14 @@ var auth = require('../../auth/auth.service'); var router = express.Router(); +/** + * @swagger + * /environment: + * get: + * responses: + * 200: + * description: environment variables object + */ router.get('/', controller.find); -module.exports = router; \ No newline at end of file +module.exports = router; diff --git a/server/api/image/image.controller.js b/server/api/image/image.controller.js index c940202..d56ab90 100644 --- a/server/api/image/image.controller.js +++ b/server/api/image/image.controller.js @@ -12,7 +12,18 @@ var TemporaryStorage = require('../../components/temporaryStorage'); var env = require('../../config/environment'); var Q = require('q'); -// Creates a new image in the DB. +/** + * @name create + * @function + * @description creates a new image + * for screenshot generates thumbnail and uploads to S3 then updates image and pile + * for normal image, we use the "multer" plugin which parses our form data request and places any text field + * on req.body[field] and any file field on req.files[field], then we open file from disk, establish our params for + * updating the document that the image refers to, process image, add to DB, add to S3 and update image + + * @param {Object} req + * @param {Object} res + */ exports.create = function (req, res) { try { if (req.body.screenshotBase64) { @@ -62,7 +73,6 @@ exports.create = function (req, res) { }); } else { - //the "multer" plugin parses our form data request and places any text field on req.body[field] and any file field on req.files[field] if (!(req.body.imageType && req.files && req.files.file)) { return res.handleResponse(400, {}, 'image_6'); } @@ -74,13 +84,11 @@ exports.create = function (req, res) { return res.handleResponse(400, {}, 'image_3'); } - // open file from disk TemporaryStorage.getResource(file.name) .then(function (buffer) { var referenceID; //id of the document that the image refers to var service; //the service that will be used to update the document that the image refers to - //establish our params for updating the document that the image refers to if (imageType === 'user') { service = UserService; referenceID = req.user._id; @@ -95,14 +103,11 @@ exports.create = function (req, res) { return res.handleResponse(400, 'image_5'); } - //process image ImageService.resizeImage(buffer, 'image').then( function (success) { var resizedImageBuffer = success.buffer; var resizedImageDimensions = success.dimensions; - //upload image - //first, add image to db var image = new Image(); image.user = req.user._id; image.dimensions = { @@ -112,20 +117,15 @@ exports.create = function (req, res) { if (err) { return handleError(res, err); } else { - //get image extension var extension = file.originalname.split('.').pop(); - //form amazon keys var key = imageType + '/' + referenceID + '/images/' + image._id + '.' + extension; var thumbnailKey = imageType + '/' + referenceID + '/images/' + image._id + 'thumb.' + extension; - //add thumbnail async ImageService.generateThumbnail(image._id, thumbnailKey, resizedImageBuffer).then(function (success) { image = success; - //add image to amazon ImageService.addToS3(key, resizedImageBuffer, function (err, data) { if (err) { return handleError(res, err); } else { - //update image src image.src = env.amazonPrefix + key; image.save(function (err, image) { if (err) { @@ -161,7 +161,13 @@ exports.create = function (req, res) { } }; -// Deletes a image from the DB. +/** + * @name destroy + * @function + * @description deletes an image from the DB, "supervisor" role required + * @param {Object} req + * @param {Object} res + */ exports.destroy = function (req, res) { Image.findOne({_id: req.query.id}, function (err, image) { if (err) { @@ -188,6 +194,12 @@ function handleError(res, err) { return res.handleResponse(500); } +/** + * @name decodeBase64Image + * @function + * @description decodes a image from a base 64 string + * @param {String} dataString + */ function decodeBase64Image(dataString) { var deferred = Q.defer(); var matches = dataString.match(/^data:([A-Za-z-+\/]+);base64,(.+)$/); diff --git a/server/api/image/image.model.js b/server/api/image/image.model.js index b544774..96b55c4 100644 --- a/server/api/image/image.model.js +++ b/server/api/image/image.model.js @@ -34,11 +34,16 @@ ImageSchema this.thumb_src = this.thumb_src || this.src; }); +/** + * @name post + * @function + * @description removes image and thumbnail from amazon, then from users or piles + * @param {String} 'remove' + */ ImageSchema.post('remove', function (image) { if (!image.not_local) { async.parallel([ function (callback) { - //remove image from amazon var key = image.src.replace(env.amazonPrefix, ''); amazon.deleteObjectS3(key, function (err, success) { if (err) console.log(err); @@ -46,7 +51,6 @@ ImageSchema.post('remove', function (image) { }); }, function (callback) { - //remove image thumbnail from amazon var key = image.thumb_src.replace(env.amazonPrefix, ''); amazon.deleteObjectS3(key, function (err, success) { if (err) console.log(err); @@ -54,7 +58,6 @@ ImageSchema.post('remove', function (image) { }); }, function (callback) { - //remove image from users UserService.removeImage(image._id).then( function (success) { callback(); @@ -66,7 +69,6 @@ ImageSchema.post('remove', function (image) { ); }, function (callback) { - //remove image from piles PileService.removeImage(image._id).then( function (success) { callback() diff --git a/server/api/image/image.service.js b/server/api/image/image.service.js index b5cd375..af07f60 100644 --- a/server/api/image/image.service.js +++ b/server/api/image/image.service.js @@ -8,6 +8,13 @@ var aws = require('../../components/amazon'); var Image = require('./image.model'); +/** + * @name createFromFB + * @function + * @description creates new image from FB profile picture + * @param {String} facebookID + * @returns {Promise} + */ function createFromFB(facebookID) { var deferred = Q.defer(); @@ -28,6 +35,13 @@ function createFromFB(facebookID) { return deferred.promise; } +/** + * @name processImage + * @function + * @description calls resize image function + * @param {String} buffer + * @returns {Promise} + */ function processImage(buffer) { var deferred = Q.defer(); resizeImage(buffer, 'image') @@ -43,10 +57,21 @@ function processImage(buffer) { return deferred.promise; } +/** + * @name updatePileImage + * @function + * @description get image from DB, upload to amazon, update image + * @param {Object} user + * @param {String} imageBuffer + * @param {Object} imageDimensions + * @param {String} imageExtension + * @param {String} referenceID + * @param {String} image_id + * @returns {Promise} + */ function updatePileImage(user, imageBuffer, imageDimensions, imageExtension, referenceID, image_id) { var deferred = Q.defer(); - //first, get the image from db Image.findOne({_id: image_id}, function (err, image) { if (err) { deferred.reject(err); @@ -60,12 +85,10 @@ function updatePileImage(user, imageBuffer, imageDimensions, imageExtension, ref }; var key = imageType + '/' + referenceID + '/images/' + image._id + '.' + imageExtension; image.src = config.amazonPrefix + key; - //add image to amazon aws.addObjectS3(key, imageBuffer, function (err) { if (err) { deferred.reject(err); } else { - //save image image.save(function (err, image) { if (err) { deferred.reject(err); @@ -86,6 +109,14 @@ function updatePileImage(user, imageBuffer, imageDimensions, imageExtension, ref }); } +/** + * @name resizeImage + * @function + * @description resizes image + * @param {String} buffer + * @param {String} image_type + * @returns {Promise} + */ function resizeImage(buffer, image_type) { var deferred = Q.defer(); @@ -118,14 +149,22 @@ function resizeImage(buffer, image_type) { return deferred.promise; } -//get resize dimensions; type = "image" / "thumbnail" +/** + * @name getResizeDimensions + * @function + * @description gets maximum allowed dimension from environment, resize width or height depending on image proportions + * make sure boundaries were not exceeded due to the division/multiplication + * @param {String} actual_width + * @param {String} actual_height + * @param {String} type + * @returns {Promise} + */ function getResizeDimensions(actual_width, actual_height, type) { var deferred = Q.defer(); if (type !== 'image' && type !== 'thumbnail') { deferred.reject({code: 'image_1'}); } else { - //get maximum allowed width and height from environment var max = { width: config.images[type + '_size'].width, height: config.images[type + '_size'].height @@ -141,8 +180,6 @@ function getResizeDimensions(actual_width, actual_height, type) { height: actual_height }; - //decide whether to resize on width or on height based on the image's proportions - //the idea is to get the largest possible image within the max boundary, without cropping it or changing it's ratio var ratio = actual.width / actual.height; if (ratio > config.images.target_ratio) { calculated.width = max.width; @@ -151,7 +188,6 @@ function getResizeDimensions(actual_width, actual_height, type) { calculated.height = max.height; calculated.width = Math.round(calculated.height * ratio); } - //make sure boundaries were not exceeded due to the division/multiplication if (calculated.height > max.height) { calculated.height = max.height; } @@ -163,6 +199,13 @@ function getResizeDimensions(actual_width, actual_height, type) { return deferred.promise; } +/** + * @name getImageDimensions + * @function + * @description gets image dimensions + * @param {String} buffer + * @returns {Promise} + */ function getImageDimensions(buffer) { var deferred = Q.defer(); gm(buffer).size(function (err, actual) { @@ -177,6 +220,15 @@ function getImageDimensions(buffer) { return deferred.promise; } +/** + * @name generateThumbnail + * @function + * @description generates image thumbnail, adds it to S3, updates image + * @param {String} imageID + * @param {String} key + * @param {String} buffer + * @returns {Promise} + */ function generateThumbnail(imageID, key, buffer) { var deferred = Q.defer(); Image.findOne({_id: imageID}, function (err, image) { @@ -192,7 +244,6 @@ function generateThumbnail(imageID, key, buffer) { if (err) { deferred.reject({data: err}); } else { - //add thumbnail key to db image.thumb_src = config.amazonPrefix + key; image.dimensions.thumb = resizedImageDimensions; image.save(function (err, image) { @@ -214,6 +265,12 @@ function generateThumbnail(imageID, key, buffer) { return deferred.promise; } +/** + * @name createEmpty + * @function + * @description creates empty image in DB + * @returns {Promise} + */ function createEmpty() { var deferred = Q.defer(); var img = new Image(); diff --git a/server/api/image/index.js b/server/api/image/index.js index 0374d5f..59ab5c6 100644 --- a/server/api/image/index.js +++ b/server/api/image/index.js @@ -6,7 +6,29 @@ var auth = require('../../auth/auth.service'); var router = express.Router(); +/** + * @swagger + * /image: + * post: + * responses: + * 200: + * description: created image object + * 400: + * description: file size exceeded or missing params + */ router.post('/', auth.isAuthenticated(), controller.create); +/** + * @swagger + * /image: + * delete: + * responses: + * 204: + * description: image successfully deleted + * 403: + * description: forbidden - only users with supervisor role can delete images + * 404: + * description: image to delete not found + */ router.delete('/', auth.isAuthenticated(), controller.destroy); module.exports = router; diff --git a/server/api/improve/improve.controller.js b/server/api/improve/improve.controller.js index 65e0cf4..51dc26a 100644 --- a/server/api/improve/improve.controller.js +++ b/server/api/improve/improve.controller.js @@ -12,6 +12,13 @@ var isValid = function (field, max_length) { return typeof field === 'string' && field.length < max_length; }; +/** + * @name find + * @function + * @description finds single record or records in dates range, sends mail if query mail_to + * @param {Object} req + * @param {Object} res + */ exports.find = function (req, res) { if (req.query.id) { Improve.findById(req.query.id).populate('user').exec(function (err, improve) { @@ -30,10 +37,8 @@ exports.find = function (req, res) { var limit = req.query.limit || env.defaultPaginationLimit; var mail_to = req.query.mail_to; - //parse query object var query = {}; - //parse date start / date end into query object try { var date_query = {}; if (date_start) { @@ -78,7 +83,13 @@ exports.find = function (req, res) { } }; -// Creates a new improve in the DB. +/** + * @name create + * @function + * @description creates a new improve in the DB + * @param {Object} req + * @param {Object} res + */ exports.create = function (req, res) { if (!isValid(req.body.description, 100) || !isValid(req.body.message, 500)) { return res.handleResponse(422, {}, 'improve_2'); diff --git a/server/api/improve/improve.service.js b/server/api/improve/improve.service.js index dd0791e..edadf6a 100644 --- a/server/api/improve/improve.service.js +++ b/server/api/improve/improve.service.js @@ -16,6 +16,13 @@ var fillTemplate = function (template, vars) { return Mustache.render(template, vars); }; +/** + * @name generateIssuesTable + * @function + * @description generates table with improve records + * @param {Array} improves + * @returns {String} ret + */ var generateIssuesTable = function (improves) { var ret = ''; var singeIssueTemplate, templateVars; @@ -31,6 +38,14 @@ var generateIssuesTable = function (improves) { return ret; }; +/** + * @name renderPDF + * @function + * @description generates pdf with improves table in given date range + * @param {Array} improves + * @param {Object} dates + * @returns {Promise} + */ var renderPDF = function (improves, dates) { var deferred = Q.defer(); var htmlTemplate = fs.readFileSync('./server/storage/html_templates/issues_report/template.html').toString(); @@ -52,6 +67,14 @@ var renderPDF = function (improves, dates) { return deferred.promise; }; +/** + * @name uploadPDF + * @function + * @description uploads pdf to S3 + * @param {Array} improves + * @param {Object} dates + * @returns {Promise} + */ var uploadPDF = function (improves, dates) { var deferred = Q.defer(); renderPDF(improves, dates).then( @@ -78,6 +101,15 @@ var uploadPDF = function (improves, dates) { return deferred.promise; }; +/** + * @name sendByEmail + * @function + * @description sends email with upload link + * @param {Array} improves + * @param {Object} mail_to + * @param {Object} dates + * @returns {Promise} + */ exports.sendByEmail = function (improves, mail_to, dates) { var deferred = Q.defer(); mail_to = mail_to.split(','); diff --git a/server/api/improve/index.js b/server/api/improve/index.js index 408ba0c..a74a0a2 100644 --- a/server/api/improve/index.js +++ b/server/api/improve/index.js @@ -7,7 +7,31 @@ var auth = require('../../auth/auth.service'); var router = express.Router(); +/** + * @swagger + * /improve: + * get: + * responses: + * 200: + * description: mail successfully sent or improve note object returned + * 400: + * description: invalid start/end date + * 404: + * description: requested improve note not found + */ router.get('/', auth.hasRole('admin'), controller.find); +/** + * @swagger + * /image: + * post: + * responses: + * 201: + * description: improve note successfully created + * 422: + * description: validation error + * 500: + * description: server error + */ router.post('/', auth.isAuthenticated(), controller.create); -module.exports = router; \ No newline at end of file +module.exports = router; diff --git a/server/api/pile/index.js b/server/api/pile/index.js index 8f05c53..488ae4a 100644 --- a/server/api/pile/index.js +++ b/server/api/pile/index.js @@ -9,14 +9,114 @@ var PileService = require('./pile.service'); var router = express.Router(); +/** + * @swagger + * /pile: + * get: + * responses: + * 200: + * description: piles to show in dashboard object + * 400: + * description: invalid sort/filter + * 404: + * description: pile requested not found + */ router.get('/', auth.isAuthenticated(), controller.find); +/** + * @swagger + * /pile/map: + * get: + * responses: + * 200: + * description: piles to show on map object + */ router.get('/map', auth.isAuthenticated(), controller.findOnMap); +/** + * @swagger + * /pile: + * post: + * responses: + * 200: + * description: mail successfully sent or improve note object returned + * 400: + * description: invalid start/end date + * 404: + * description: requested improve note not found + */ router.post('/', auth.isAuthenticated(), PileService.parseFormData, geoJsonMiddleWare, controller.create); +/** + * @swagger + * /pile: + * put: + * responses: + * 201: + * description: pile successfully created + * 400: + * description: file size limit exceeded/missing siruta code/pile size not in interval + */ router.put('/', auth.hasRole('supervisor'), controller.update); +/** + * @swagger + * /pile/hide: + * put: + * responses: + * 200: + * description: pile successfully hidden + * 404: + * description: pile to hide not found + */ router.put('/hide', auth.hasRole('admin'), controller.hide); +/** + * @swagger + * /pile/updateLocation: + * put: + * responses: + * 200: + * description: mail successfully sent or improve note object returned + * 400: + * description: missing siruta code + * 404: + * description: pile to update not found + */ router.put('/updateLocation', auth.hasRole('supervisor'), geoJsonMiddleWare, controller.updateLocation); +/** + * @swagger + * /pile/allocate: + * put: + * responses: + * 200: + * description: pile successfully allocated + * 400: + * description: missing params/error parsing due date/due date not in range: due_date + * 403: + * description: could not validate authority + * 404: + * description: pile not found + */ router.post('/allocate', auth.hasRole('supervisor'), controller.allocate); +/** + * @swagger + * /pile/pileConfirmation: + * put: + * responses: + * 200: + * description: pile successfully confirmed/unconfirmed + * 400: + * description: invalid params + * 404: + * description: pile not found + */ router.post('/pileConfirmation', auth.isAuthenticated(), controller.pileConfirmation); +/** + * @swagger + * /pile/statistics: + * put: + * responses: + * 200: + * description: statistics object + * 500: + * description: server error + */ router.post('/statistics', auth.hasRole('admin'), controller.getStatistics); module.exports = router; diff --git a/server/api/pile/pile.controller.js b/server/api/pile/pile.controller.js index 9ebef4c..d463da9 100644 --- a/server/api/pile/pile.controller.js +++ b/server/api/pile/pile.controller.js @@ -20,13 +20,17 @@ var env = require('../../config/environment'); var Q = require('q'); var async = require('async'); -//find piles for map +/** + * @name findOnMap + * @function + * @description find piles for map (with is_hidden false or undefined) depending on user role + * @param {Object} req + * @param {Object} res + */ exports.findOnMap = function (req, res) { - //find piles without is_hidden field or with is_hidden field set to false if (req.user.role !== 'admin') { var query = {$or: [{is_hidden: false}, {is_hidden: {$exists: false}}]}; if (req.user.role === 'volunteer') { - //find piles with a not pending status and pending piles reported by this user query = {$and: [{$or: [{status: {$ne: 'unconfirmed'}}, {user: req.user._id}]}, {$or: [{is_hidden: false}, {is_hidden: {$exists: false}}]}]}; } } @@ -39,7 +43,17 @@ exports.findOnMap = function (req, res) { }); }; -//find piles for tabled view +/** + * @name find + * @function + * @description find pile for dashboard view + * get all params, allow only certain filters to pass and only if they have a value, differentiate query based on role + * for volunteer, find piles contributed to, except piles created by this volunteer + * for supervisor, find piles located in this supervisor's county + * proceed to pagination and sorting, using a cursor + * @param {Object} req + * @param {Object} res + */ exports.find = function (req, res) { var id = req.query.id; if (id) { @@ -53,7 +67,6 @@ exports.find = function (req, res) { return res.handleResponse(200, {success: pile}); }); } else { - //get all params var contributions = req.query.contributions; var page = req.query.page || 1; var limit = req.query.limit || env.defaultPaginationLimit; @@ -82,20 +95,15 @@ exports.find = function (req, res) { } } - //form a complex query object based on the params above var query = {}; - //======================================================================= differentiate query based on role async.parallel([ function (callback) { if (user.role === 'volunteer') { - //=================================================================================== VOLUNTEER if (contributions !== 'true') { - //find piles reported by this volunteer query['user'] = user._id; callback(); } else { - //find piles this volunteer contributed to, except piles created by this volunteer ActivityService.getIdsOfPilesContributedTo(user._id).then( function (pile_ids) { query['user'] = {$ne: user._id}; @@ -108,8 +116,6 @@ exports.find = function (req, res) { ); } } else if (user.role === 'supervisor') { - //================================================================================== SUPERVISOR - //find piles located in this supervisor's county if (!user.county) { callback('Supervisor has no county'); } else { @@ -122,13 +128,10 @@ exports.find = function (req, res) { } } } else { - //======================================================================================= ADMIN - //please proceed, sir callback(); } }, function (callback) { - //filter by field value if (cleanedFilter) { _.assign(query, cleanedFilter); } @@ -138,8 +141,6 @@ exports.find = function (req, res) { if (err) { handleError(res, err); } else { - //proceed to pagination and sorting - //use a cursor for this var cursor = {}; if (user.role === 'admin') { cursor = Pile.find(query).populate('images user city county'); @@ -164,8 +165,17 @@ exports.find = function (req, res) { } }; + /** - * + * @name create + * @function + * @description uses the "multer" plugin to parse our form data request and places any text field on req.body[field] + * and any file field on req.files[field] + * the text fields should already be parsed in a previous middleware and we should have the pile details on req.body + * validate files + * create empty images and add their references to the pile + * set the references to the empty images created + * @param {Object} res * @param {Object} req - request object * @param {String} req.body.siruta - Unique code given to cities/counties by authorities * @param {number} req.body.size - Pile size @@ -173,13 +183,9 @@ exports.find = function (req, res) { * @param {Object} req.body.location.lat - Latitude * @param {Object} req.body.location.lng - Longitude * @param {String[]} req.body.content - Array of pile types - * @param {String[]} req.body.areas - ???? - * @param res + * @param {String[]} req.body.areas - Array of pile areas */ exports.create = function (req, res) { - // the 'multer' plugin parses our form data request and places any text field on req.body[field] and any file field on req.files[field] - // the text fields should already be parsed in a previous middleware and we should have the pile details on req.body - // validate files for (var key in req.files) { var file = req.files[key]; if (file.truncated) { @@ -206,7 +212,7 @@ exports.create = function (req, res) { CounterService.getNextSequence('pile').then( function (seq) { pile.nr_ord = seq; - // create empty images and add their references to the pile + var imageIds = []; async.each(req.files, function processFile(file, callback) { ImageService.createEmpty() @@ -223,7 +229,6 @@ exports.create = function (req, res) { if (err) { return handleError(res, err); } else { - // set the references to the empty images created pile.images = imageIds; pile.save(function (err, pile) { if (err) { @@ -246,7 +251,13 @@ exports.create = function (req, res) { } }; -// Updates an existing pile in the DB. +/** + * @name update + * @function + * @description updates existing pile + * @param {Object} req + * @param {Object} res + */ exports.update = function (req, res) { UtilsService.allowFields(req.body, ['status', 'description']); Pile.findById(req.query.id).exec(function (err, pile) { @@ -272,6 +283,13 @@ exports.update = function (req, res) { }); }; +/** + * @name updateLocation + * @function + * @description updates pile location + * @param {Object} req + * @param {Object} res + */ exports.updateLocation = function (req, res) { UtilsService.allowFields(req.body, ['location', 'siruta']); Pile.findById(req.query.id).exec(function (err, pile) { @@ -306,6 +324,13 @@ exports.updateLocation = function (req, res) { }); }; +/** + * @name hide + * @function + * @description sets pile hidden flag to true + * @param {Object} req + * @param {Object} res + */ exports.hide = function (req, res) { UtilsService.allowFields(req.body, ['is_hidden']); Pile.findById(req.query.id).exec(function (err, pile) { @@ -331,7 +356,13 @@ exports.hide = function (req, res) { }); }; -//allocate pile to authority +/** + * @name allocate + * @function + * @description allocate pile to authority, generate pdf and send to authority async + * @param {Object} req + * @param {Object} res + */ exports.allocate = function (req, res) { var due_date = req.body.due_date; if (!due_date) { @@ -384,7 +415,6 @@ exports.allocate = function (req, res) { res.handleResponse(200, {success: pile}); } }); - //generate pdf and send to authority async PileService.generateAuthorityReport(pile_id).then( function (buffer) { AuthorityService.sendToAuthority(authority_id, buffer); @@ -404,6 +434,13 @@ exports.allocate = function (req, res) { }); }; +/** + * @name pileConfirmation + * @function + * @description confirm/unconfirm pile, prevent multiple actions on the same pile + * @param {Object} req + * @param {Object} res + */ exports.pileConfirmation = function (req, res) { var action = req.body.action; var notAction; @@ -416,15 +453,11 @@ exports.pileConfirmation = function (req, res) { } else { notAction = 'confirm'; } - //parse modify query; user can make a single confirm / unconfirm on a pile var add = {}; var remove = {}; add[action] = req.user._id; remove[notAction] = req.user._id; var modifyQuery = {$addToSet: add, $pull: remove, last_update: new Date()}; - //parse find query - //prevent self confirm / unconfirm of pile - //prevent multiple confirm / unconfirm of the same pile, otherwise too many notifications will be triggered var query = {_id: pile_id, user: {$ne: req.user._id}}; query[action] = {$nin: [req.user._id]}; Pile.update(query, modifyQuery, function (err, wres) { @@ -448,6 +481,13 @@ exports.pileConfirmation = function (req, res) { } }; +/** + * @name getStatistics + * @function + * @description get statistics for specified county, within the date range + * @param {Object} req + * @param {Object} res + */ exports.getStatistics = function (req, res) { var siruta = req.body.siruta; var date_start = req.body.date_start; diff --git a/server/api/pile/pile.service.js b/server/api/pile/pile.service.js index c1b0d61..c2e9174 100644 --- a/server/api/pile/pile.service.js +++ b/server/api/pile/pile.service.js @@ -15,6 +15,14 @@ var amazon = require('../../components/amazon'); var mailer = require('../../components/mailer'); var UtilsService = require('../../components/utils'); +/** + * @name addImage + * @function + * @description update pile with image id + * @param {String} pile_id + * @param {String} image_id + * @returns {Promise} + */ exports.addImage = function (pile_id, image_id) { var deferred = Q.defer(); Pile.update({_id: pile_id}, {$addToSet: {images: image_id}}, function (err, wres) { @@ -27,6 +35,14 @@ exports.addImage = function (pile_id, image_id) { return deferred.promise; }; +/** + * @name addScreenshot + * @function + * @description update pile scrrenshot with image id + * @param {String} pile_id + * @param {String} image_id + * @returns {Promise} + */ exports.addScreenshot = function (pile_id, image_id) { var deferred = Q.defer(); Pile.update({_id: pile_id}, {screenshot: image_id}, function (err, wres) { @@ -39,6 +55,13 @@ exports.addScreenshot = function (pile_id, image_id) { return deferred.promise; }; +/** + * @name removeImage + * @function + * @description removes image id from pile image references id's array + * @param {String} image_id + * @returns {Promise} + */ exports.removeImage = function (image_id) { var deferred = Q.defer(); Pile.update({images: {$in: [image_id]}}, {$pull: {images: image_id}}, {multi: true}, function (err) { @@ -51,6 +74,13 @@ exports.removeImage = function (image_id) { return deferred.promise; }; +/** + * @name getUserId + * @function + * @description get reporter id + * @param {String} pile_id + * @returns {Promise} + */ exports.getUserId = function (pile_id) { var deferred = Q.defer(); Pile.findOne({_id: pile_id}, function (err, pile) { @@ -65,6 +95,14 @@ exports.getUserId = function (pile_id) { return deferred.promise; }; +/** + * @name getPileIds + * @function + * @description get user or county pile ids + * @param {String} user_id + * @param {String} county_id + * @returns {Promise} + */ exports.getPileIds = function (user_id, county_id) { var deferred = Q.defer(); if (user_id) { @@ -83,6 +121,13 @@ exports.getPileIds = function (user_id, county_id) { return deferred.promise; }; +/** + * @name getPilesIdsInCounty + * @function + * @description get county pile ids + * @param {String} county_id + * @returns {Promise} + */ exports.getPilesIdsInCounty = function (county_id) { var deferred = Q.defer(); if (county_id) { @@ -99,6 +144,14 @@ exports.getPilesIdsInCounty = function (county_id) { return deferred.promise; }; +/** + * @name countByUserAndStatus + * @function + * @description count piles by user and status + * @param {Object} user + * @param {Object} status + * @returns {Promise} + */ exports.countByUserAndStatus = function (user, status) { var deferred = Q.defer(); var query = {status: status}; @@ -119,8 +172,13 @@ exports.countByUserAndStatus = function (user, status) { return deferred.promise; }; -//===================================================================================================================== EXPORT PDF - +/** + * @name createHtmlImages + * @function + * @description creates images divs + * @param {Array} images + * @returns {String} imgHTML + */ var createHtmlImages = function (images) { var imagesCount = images.length; var imageLength = imagesCount === 1 ? 100 : 50; @@ -132,6 +190,13 @@ var createHtmlImages = function (images) { return imgHTML; }; +/** + * @name createHtmScreenshot + * @function + * @description creates screenshot div + * @param {Object} screenshot + * @returns {String} screenshotHTML + */ var createHtmScreenshot = function (screenshot) { var screenshotHTML = ''; if (screenshot) { @@ -140,6 +205,13 @@ var createHtmScreenshot = function (screenshot) { return screenshotHTML; }; +/** + * @name formatPileSize + * @function + * @description formats pile sizes + * @param {Integer} pile_size + * @returns {String} sizes[idx] + */ var formatPileSize = function (pile_size) { var idx = pile_size - 1; if (idx < 0) idx = 0; @@ -147,6 +219,13 @@ var formatPileSize = function (pile_size) { return sizes[idx]; }; +/** + * @name exportAsPDF + * @function + * @description finds pile and generates report pdf + * @param {String} pile_id + * @returns {Promise} + */ var exportAsPDF = function (pile_id) { var deferred = Q.defer(); Pile.findOne({_id: pile_id}).populate('images county city allocated.authority screenshot').exec(function (err, pile) { @@ -200,6 +279,13 @@ var exportAsPDF = function (pile_id) { return deferred.promise; }; +/** + * @name generateAuthorityReport + * @function + * @description generates report pdf and uploads to S3, updates pile + * @param {String} pile_id + * @returns {Promise} + */ exports.generateAuthorityReport = function (pile_id) { var deferred = Q.defer(); exportAsPDF(pile_id).then( @@ -226,6 +312,12 @@ exports.generateAuthorityReport = function (pile_id) { return deferred.promise; }; +/** + * @name notifyDueDatePassed + * @function + * @description finds pile and sends due date expired mail, updates pile + * @returns {Promise} + */ exports.notifyDueDatePassed = function () { var deferred = Q.defer(); Pile.find({ @@ -251,7 +343,6 @@ exports.notifyDueDatePassed = function () { ).then( function (success) { emailsSent++; - //update pile model Pile.update({_id: pile._id}, {$set: {"allocated.notified": true}}, function (err) { if (err) { callback(err); @@ -279,8 +370,15 @@ exports.notifyDueDatePassed = function () { return deferred.promise; }; +/** + * @name parseFormData + * @function + * @description parses form data + * @param {Object} req + * @param {Object} res + * @param {Object} next + */ exports.parseFormData = function (req, res, next) { - //the "multer" plugin parses our form data request and places any text field on req.body[field] if (req.body.pile) { req.body = req.body.pile; } diff --git a/server/api/state_authority/index.js b/server/api/state_authority/index.js index 5b6ae2e..ee1bc90 100644 --- a/server/api/state_authority/index.js +++ b/server/api/state_authority/index.js @@ -5,11 +5,69 @@ var controller = require('./state_authority.controller'); var router = express.Router(); +/** + * @swagger + * /state_authorities: + * get: + * responses: + * 200: + * description: get all state authorities + */ router.get('/', controller.index); +/** + * @swagger + * /state_authorities/:id: + * get: + * responses: + * state_authority: + * description: state_authority requested object + * 404: + * description: server error + */ router.get('/:id', controller.show); +/** + * @swagger + * /state_authorities: + * post: + * responses: + * 201: + * description: state_authority successfully created + * err: + * description: error object + */ router.post('/', controller.create); +/** + * @swagger + * /state_authorities/:id: + * put: + * responses: + * 200: + * description: updated statistics object + * 404: + * description: requested state_authorities not found + */ router.put('/:id', controller.update); +/** + * @swagger + * /state_authorities/:id: + * patch: + * responses: + * 200: + * description: updated statistics object + * 404: + * description: requested state_authorities not found + */ router.patch('/:id', controller.update); +/** + * @swagger + * /state_authorities/:id: + * delete: + * responses: + * 204: + * description: state_authority successfully deleted + * 404: + * description: state_authority to delete not found + */ router.delete('/:id', controller.destroy); module.exports = router; diff --git a/server/api/state_authority/state_authority.controller.js b/server/api/state_authority/state_authority.controller.js index c0bcfc3..47d1ce8 100644 --- a/server/api/state_authority/state_authority.controller.js +++ b/server/api/state_authority/state_authority.controller.js @@ -3,7 +3,13 @@ var _ = require('lodash'); var StateAuthority = require('./state_authority.model'); -// Get list of state_authoritys +/** + * @name index + * @function + * @description gets list of all authorities + * @param {Object} req + * @param {Object} res + */ exports.index = function (req, res) { StateAuthority.find(function (err, state_authoritys) { if (err) { @@ -13,7 +19,13 @@ exports.index = function (req, res) { }); }; -// Get a single state_authority +/** + * @name show + * @function + * @description gets single authority + * @param {Object} req + * @param {Object} res + */ exports.show = function (req, res) { StateAuthority.findById(req.params.id, function (err, state_authority) { if (err) { @@ -26,7 +38,13 @@ exports.show = function (req, res) { }); }; -// Creates a new state_authority in the DB. +/** + * @name create + * @function + * @description creates new authority + * @param {Object} req + * @param {Object} res + */ exports.create = function (req, res) { StateAuthority.create(req.body, function (err, state_authority) { if (err) { @@ -36,7 +54,13 @@ exports.create = function (req, res) { }); }; -// Updates an existing state_authority in the DB. +/** + * @name update + * @function + * @description updates requested authority + * @param {Object} req + * @param {Object} res + */ exports.update = function (req, res) { if (req.body._id) { delete req.body._id; @@ -58,7 +82,13 @@ exports.update = function (req, res) { }); }; -// Deletes a state_authority from the DB. +/** + * @name destroy + * @function + * @description removes specified authority + * @param {Object} req + * @param {Object} res + */ exports.destroy = function (req, res) { StateAuthority.findById(req.params.id, function (err, state_authority) { if (err) { diff --git a/server/api/user/index.js b/server/api/user/index.js index 41a215b..bf3f508 100644 --- a/server/api/user/index.js +++ b/server/api/user/index.js @@ -7,30 +7,243 @@ var auth = require('../../auth/auth.service'); var router = express.Router(); -//======================================================================== ROLE ADMIN +/** + * @swagger + * /users: + * get: + * responses: + * 200: + * description: requested user/sorted users object + * 404: + * description: requested user not found + */ router.get('/', auth.hasRole('admin'), controller.query_users); +/** + * @swagger + * /users: + * put: + * responses: + * 200: + * description: updated user object + * 404: + * description: user not found + * 403: + * description: user that initiated the requested doesn't have permissions + */ router.put('/', auth.hasRole('admin'), controller.edit_user); +/** + * @swagger + * /users: + * delete: + * responses: + * 200: + * description: user successfully removed + */ router.delete('/', auth.hasRole('admin'), controller.delete_user); -router.post('/create_supervisor', auth.hasRole('admin'), controller.create_supervisor); //create user from an admin account +/** + * @swagger + * /users/create_supervisor: + * delete: + * responses: + * 200: + * description: user with supervisor role successfully created + */ +router.post('/create_supervisor', auth.hasRole('admin'), controller.create_supervisor); +/** + * @swagger + * /users/statistics: + * get: + * responses: + * 200: + * description: all users statistics object + * 500: + * description: server error + */ router.get('/statistics', auth.hasRole('admin'), controller.getStatisticsAll); - -//========================================================================= ROLE USER +/** + * @swagger + * /users/me: + * get: + * responses: + * 200: + * description: get user that initiated the request + * 401: + * description: invalid credentials + */ router.get('/me', auth.isAuthenticated(), controller.me); +/** + * @swagger + * /users/me: + * put: + * responses: + * 200: + * description: updated user object + * 401: + * description: user to update not found + */ router.put('/me', auth.isAuthenticated(), controller.update); +/** + * @swagger + * /users/me: + * delete: + * responses: + * 204: + * description: user successfully deleted + * 500: + * description: server error + */ router.delete('/me', auth.isAuthenticated(), controller.destroy); +/** + * @swagger + * /users/stats: + * get: + * responses: + * 200: + * description: user statistics + */ router.get('/stats', auth.isAuthenticated(), controller.getUserStatistics); -router.put('/password', auth.isAuthenticated(), controller.changePasswordbyAuth); // change own password -router.post('/subscribeDevice', auth.isAuthenticated(), controller.subscribeDevice); // subscribe mobile device for push notifications -router.post('/unsubscribeDevice', auth.isAuthenticated(), controller.unsubscribeDevice); // subscribe mobile device for push notifications - -//============================================================================ PUBLIC +/** + * @swagger + * /users/password: + * put: + * responses: + * 200: + * description: password successfully changed + * 400: + * description: new/old password missing + * 403: + * description: invalid old password + */ +router.put('/password', auth.isAuthenticated(), controller.changePasswordbyAuth); +/** + * @swagger + * /users/subscribeDevice: + * post: + * responses: + * 200: + * description: device successfully subscribed + * 400: + * description: missing device type/token + */ +router.post('/subscribeDevice', auth.isAuthenticated(), controller.subscribeDevice); +/** + * @swagger + * /users/unsubscribeDevice: + * post: + * responses: + * 200: + * description: device successfully subscribed + * 400: + * description: missing device type/token + */ +router.post('/unsubscribeDevice', auth.isAuthenticated(), controller.unsubscribeDevice); +/** + * @swagger + * /users: + * post: + * responses: + * 200: + * description: user created object + * 400: + * description: missing email field + */ router.post('/', controller.create); +/** + * @swagger + * /users/activate/:token: + * get: + * responses: + * 200: + * description: active user object + * 400: + * description: missing token + * 403: + * description: user status different from pending + * 404: + * description: missing user + */ router.get('/activate/:token', controller.activate); +/** + * @swagger + * /users/resendActivation: + * post: + * responses: + * 200: + * description: activation email successfully resent + * 400: + * description: missing email + */ router.post('/resendActivation', controller.resendActivation); +/** + * @swagger + * /users/fpw: + * post: + * responses: + * 200: + * description: reset password email sent + * 400: + * description: missing email + * 403: + * description: inactive user + * 404: + * description: user not found + */ router.post('/fpw', controller.fpw); +/** + * @swagger + * /users/reset/:token: + * get: + * responses: + * 200: + * description: user object + * 400: + * description: missing token + * 404: + * description: missing user + */ router.get("/reset/:token", controller.reset); -router.put("/reset/:token", controller.changePasswordByToken); // change password based on salt -router.get('/set_password/:token', controller.findUserByToken); //identify user (created by an admin) by token -router.post('/set_password', controller.setPassByToken); //set password for user created by an admin +/** + * @swagger + * /users/reset/:token: + * put: + * responses: + * 200: + * description: password successfully changed + * 400: + * description: missing token + * 404: + * description: missing user + */ +router.put("/reset/:token", controller.changePasswordByToken); +/** + * @swagger + * /users/set_password/:token: + * get: + * responses: + * 200: + * description: requested user object + * 400: + * description: missing token + * 403: + * description: not allowed + * 404: + * description: missing user + */ +router.get('/set_password/:token', controller.findUserByToken); +/** + * @swagger + * /users/set_password: + * post: + * responses: + * 200: + * description: password successfully saved on user + * 400: + * description: missing token + * 403: + * description: not allowed + * 404: + * description: missing user + */ +router.post('/set_password', controller.setPassByToken); module.exports = router; diff --git a/server/api/user/user.controller.js b/server/api/user/user.controller.js index 5c060fd..ceedb93 100644 --- a/server/api/user/user.controller.js +++ b/server/api/user/user.controller.js @@ -24,11 +24,12 @@ function handleError(res, err) { return res.handleResponse(500); } -//=========================================================================================================== ROLE ADMIN - /** - * Get list of users - * restriction: 'admin' + * @name query_users + * @function + * @description gets list of all users, except "admin" + * @param {Object} req + * @param {Object} res */ exports.query_users = function (req, res) { if (req.query.id) { @@ -93,6 +94,13 @@ exports.query_users = function (req, res) { } }; +/** + * @name edit_user + * @function + * @description updates user, protecting user's private data from being altered + * @param {Object} req + * @param {Object} res + */ exports.edit_user = function (req, res) { User.findOne({_id: req.query.id}, function (err, user) { if (err) { @@ -102,7 +110,6 @@ exports.edit_user = function (req, res) { } else if (user.role === 'admin') { res.handleResponse(403); } else { - //protect user's private data from being altered UtilsService.discardFields(req.body, [ 'created_at', 'updated_at', 'image', 'pile_count', 'newsletter', 'sync', 'pass', 'password', 'hashedPassword', 'provider', 'salt', 'facebook', @@ -121,6 +128,13 @@ exports.edit_user = function (req, res) { }); }; +/** + * @name delete_user + * @function + * @description deletes user + * @param {Object} req + * @param {Object} res + */ exports.delete_user = function (req, res) { User.remove({_id: req.query.id}, function (err, wRes) { if (err) { @@ -131,7 +145,13 @@ exports.delete_user = function (req, res) { }); }; -// create an account from an admin account +/** + * @name create_supervisor + * @function + * @description creates supervisor from admin account + * @param {Object} req + * @param {Object} res + */ exports.create_supervisor = function (req, res) { if (!req.body.first_name || !req.body.last_name || !req.body.email) { @@ -181,6 +201,13 @@ exports.create_supervisor = function (req, res) { }); }; +/** + * @name getStatisticsAll + * @function + * @description get statistics for all users + * @param {Object} req + * @param {Object} res + */ exports.getStatisticsAll = function (req, res) { User.find({}, { first_name: 1, @@ -199,10 +226,12 @@ exports.getStatisticsAll = function (req, res) { }); }; -//======================================================================================================== GENERIC USER - /** - * Get my info + * @name me + * @function + * @description get logged in user info + * @param {Object} req + * @param {Object} res */ exports.me = function (req, res, next) { var userId = req.user._id; @@ -219,7 +248,13 @@ exports.me = function (req, res, next) { }); }; -//update user profile +/** + * @name update + * @function + * @description updates logged in user profile + * @param {Object} req + * @param {Object} res + */ exports.update = function (req, res) { UtilsService.discardFields(req.body, [ '_id', 'email', 'created_at', 'updated_at', 'pile_count', 'role', 'status', 'password', @@ -261,7 +296,11 @@ exports.update = function (req, res) { }; /** - * Delete own profile + * @name destroy + * @function + * @description removes logged in user + * @param {Object} req + * @param {Object} res */ exports.destroy = function (req, res) { User.findByIdAndRemove(req.user._id, function (err, user) { @@ -273,7 +312,11 @@ exports.destroy = function (req, res) { }; /** - * Change own password + * @name changePasswordbyAuth + * @function + * @description changes logged in user password + * @param {Object} req + * @param {Object} res */ exports.changePasswordbyAuth = function (req, res, next) { @@ -312,7 +355,13 @@ exports.changePasswordbyAuth = function (req, res, next) { }); }; -//get personal statistics +/** + * @name getUserStatistics + * @function + * @description gets logged in user stats + * @param {Object} req + * @param {Object} res + */ exports.getUserStatistics = function (req, res) { UserService.getStats(req.user._id).then( function (stats) { @@ -324,6 +373,13 @@ exports.getUserStatistics = function (req, res) { ); }; +/** + * @name subscribeDevice + * @function + * @description subscribes device for push notifications + * @param {Object} req + * @param {Object} res + */ exports.subscribeDevice = function (req, res) { var deviceType = req.body.deviceType; var deviceToken = req.body.deviceToken; @@ -341,6 +397,13 @@ exports.subscribeDevice = function (req, res) { } }; +/** + * @name unsubscribeDevice + * @function + * @description unsubscribes device for push notifications + * @param {Object} req + * @param {Object} res + */ exports.unsubscribeDevice = function (req, res) { var deviceToken = req.body.deviceToken; if (!deviceToken) { @@ -357,9 +420,13 @@ exports.unsubscribeDevice = function (req, res) { } }; -//=============================================================================================================== PUBLIC - -// creates a new account +/** + * @name create + * @function + * @description creates new user + * @param {Object} req + * @param {Object} res + */ exports.create = function (req, res) { var email = req.body.email; @@ -400,7 +467,13 @@ exports.create = function (req, res) { }); }; -//identify user created (by an admin) by token +/** + * @name findUserByToken + * @function + * @description finds user by token + * @param {Object} req + * @param {Object} res + */ exports.findUserByToken = function (req, res) { if (!req.params.token) { return res.handleResponse(400); @@ -418,7 +491,13 @@ exports.findUserByToken = function (req, res) { }); }; -//set password for user created by an admin +/** + * @name setPassByToken + * @function + * @description sets password by user created by admin + * @param {Object} req + * @param {Object} res + */ exports.setPassByToken = function (req, res) { if (!req.body.token || !req.body.password) { res.handleResponse(400, {}, 'user_4'); @@ -446,7 +525,13 @@ exports.setPassByToken = function (req, res) { } }; -//resend activation mail +/** + * @name resendActivation + * @function + * @description resends activation email + * @param {Object} req + * @param {Object} res + */ exports.resendActivation = function (req, res) { if (!req.body.email) { return res.handleResponse(400); @@ -460,7 +545,13 @@ exports.resendActivation = function (req, res) { }); }; -//finds user account based on temporary token +/** + * @name reset + * @function + * @description finds user based on temporary token + * @param {Object} req + * @param {Object} res + */ exports.reset = function (req, res, next) { var token = req.params.token; @@ -485,7 +576,13 @@ exports.reset = function (req, res, next) { }; -// changes user password based on temporary token +/** + * @name changePasswordByToken + * @function + * @description changes user password based on temporary token + * @param {Object} req + * @param {Object} res + */ exports.changePasswordByToken = function (req, res) { var token = req.params.token; @@ -519,7 +616,13 @@ exports.changePasswordByToken = function (req, res) { }; -// sends e-mail with link to reset password +/** + * @name fpw + * @function + * @description sends e-mail with link to reset password + * @param {Object} req + * @param {Object} res + */ exports.fpw = function (req, res, next) { if (!req.body.email) { @@ -577,7 +680,13 @@ exports.fpw = function (req, res, next) { }; -// activates user account based on temporary token +/** + * @name activate + * @function + * @description activates user account based on temporary token + * @param {Object} req + * @param {Object} res + */ exports.activate = function (req, res, next) { var token = req.params.token; @@ -612,7 +721,11 @@ exports.activate = function (req, res, next) { }; /** - * Authentication callback + * @name authCallback + * @function + * @description authentication callback + * @param {Object} req + * @param {Object} res */ exports.authCallback = function (req, res, next) { res.redirect('/'); diff --git a/server/api/user/user.service.js b/server/api/user/user.service.js index 5c4455f..ff69b64 100644 --- a/server/api/user/user.service.js +++ b/server/api/user/user.service.js @@ -11,6 +11,14 @@ var PileService = require('../pile/pile.service'); var ActivityService = require('../activity/activity.service'); var config = require('../../config/environment'); +/** + * @name sendActivationMail + * @function + * @description finds user, creates token or temporary one, sends mail with activation link + * @param {Object} req + * @param {String} user_email + * @param {Function} callback + */ exports.sendActivationMail = function (req, user_email, callback) { var User = require('./user.model'); User.findOne({email: user_email}).select('+createToken').exec(function (err, user) { @@ -62,6 +70,12 @@ exports.sendActivationMail = function (req, user_email, callback) { }); }; +/** + * @name removeImage + * @function + * @description removes profile image from user + * @param {String} image_id + */ exports.removeImage = function (image_id) { var User = require('./user.model'); var deferred = Q.defer(); @@ -84,6 +98,13 @@ exports.removeImage = function (image_id) { return deferred.promise; }; +/** + * @name addImage + * @function + * @description adds user profile image + * @param {String} image_id + * @param {String} user_id + */ exports.addImage = function (user_id, image_id) { var User = require('./user.model'); var deferred = Q.defer(); @@ -97,6 +118,12 @@ exports.addImage = function (user_id, image_id) { return deferred.promise; }; +/** + * @name getStats + * @function + * @description finds user, counts reported piles and unread activities + * @param {String} user_id + */ exports.getStats = function (user_id) { var User = require('./user.model'); var deferred = Q.defer(); diff --git a/server/auth/auth.service.js b/server/auth/auth.service.js index cd7c138..62eb6e7 100644 --- a/server/auth/auth.service.js +++ b/server/auth/auth.service.js @@ -15,20 +15,18 @@ var _ = require('lodash'); var ImageService = require('../api/image/image.service'); /** - * Attaches the user object to the request if authenticated - * Otherwise returns 403 + * @name isAuthenticated + * @function + * @description validate jwt, attaches the user object to the request if authenticated, otherwise returns 403 */ function isAuthenticated() { return compose() - // Validate jwt .use(function (req, res, next) { - // allow access_token to be passed through query parameter as well if (req.query && req.query.hasOwnProperty('access_token')) { req.headers.authorization = 'Bearer ' + req.query.access_token; } validateJwt(req, res, next); }) - // Attach user to request .use(function (req, res, next) { User.findById(req.user._id).exec(function (err, user) { if (err) { @@ -45,7 +43,10 @@ function isAuthenticated() { } /** - * Checks if the user role meets the minimum requirements of the route + * @name hasRole + * @function + * @description checks if the user role meets the minimum requirements of the route + * @param {String} roleRequired */ function hasRole(roleRequired) { if (!roleRequired) { @@ -65,14 +66,21 @@ function hasRole(roleRequired) { } /** - * Returns a jwt token signed by the app secret + * @name signToken + * @function + * @description returns a jwt token signed by the app secret + * @param {String} id */ function signToken(id) { return jwt.sign({_id: id}, config.secrets.session, {expiresInMinutes: 60 * 24 * 3}); } /** - * Set token cookie directly for oAuth strategies + * @name setTokenCookie + * @function + * @description set token cookie directly for oAuth strategies + * @param {Object} req + * @param {Object} res */ function setTokenCookie(req, res) { if (!req.user) { @@ -83,12 +91,21 @@ function setTokenCookie(req, res) { res.redirect(config.staticSite); } +/** + * @name loginToFacebook + * @function + * @description calls FB api with received id and token + * check if a user is already registered with this facebook id, create one if not + * synchronize info + * @param {String} accessToken + * @param {String} facebookID + * @param {Function} callback + */ var loginToFacebook = function (accessToken, facebookID, callback) { if (!facebookID || !accessToken) { callback({code: 'auth_mobile_1', status: 400}); } else { var url = config.facebook.apiURL + facebookID + '?access_token=' + accessToken + '&fields=id,first_name,last_name,email,verified'; - // CALL FB API WITH RECEIVED ID AND TOKEN var options = { url: url, method: 'GET', @@ -124,7 +141,6 @@ var loginToFacebook = function (accessToken, facebookID, callback) { facebook: parsedResponse }; - //check if a user is already registered with this facebook id User.findOne({ 'facebook.id': facebookID }, @@ -132,7 +148,6 @@ var loginToFacebook = function (accessToken, facebookID, callback) { if (err) { callback({error: err, status: 500}); } else if (!user) { - //create one; watch caveat: email is already taken User.findOne({email: fb_user.email}, function (err, user) { if (err) { callback({error: err, status: 500}); @@ -144,9 +159,7 @@ var loginToFacebook = function (accessToken, facebookID, callback) { user.status = parsedResponse.verified ? 'active' : 'pending'; user.terms = true; } - //sync facebook info _.assign(user, fb_user); - //sync profile image ImageService.createFromFB(facebookID).then( function (image) { user.image = image._id; @@ -159,7 +172,6 @@ var loginToFacebook = function (accessToken, facebookID, callback) { } }); } else { - //synchronize User.findOne({ 'facebook.id': {$ne: facebookID}, email: fb_user.email diff --git a/server/components/amazon/index.js b/server/components/amazon/index.js index 6a8c482..d4f0066 100644 --- a/server/components/amazon/index.js +++ b/server/components/amazon/index.js @@ -18,13 +18,27 @@ var s3 = new AWS.S3(); //bucket retrieved from environment variables var amazonBucket = env.amazonBucket; -//function for deleting object from amazon +/** + * @name deleteObjectS3 + * @function + * @description delete object from S3 + * @param {String} key + * @param {Function} callback + */ var deleteObjectS3 = function (key, callback) { s3.deleteObject({Bucket: amazonBucket, Key: key}, function (err, data) { callback(err, data); }); }; +/** + * @name addObjectS3 + * @function + * @description add object from S3 + * @param {String} key + * @param {Object} body + * @param {Function} callback + */ var addObjectS3 = function (key, body, callback) { var full_path = env.amazonPrefix + key; s3.upload({Bucket: amazonBucket, Key: key, Body: body, ACL: 'public-read'}, function (err, data) { diff --git a/server/components/geoJsonMiddleware/geoJsonMiddleware.js b/server/components/geoJsonMiddleware/geoJsonMiddleware.js index 06c4914..c399a90 100644 --- a/server/components/geoJsonMiddleware/geoJsonMiddleware.js +++ b/server/components/geoJsonMiddleware/geoJsonMiddleware.js @@ -2,6 +2,14 @@ var City = require('../../api/city/city.model'); var County = require('../../api/county/county.model'); var Q = require('q'); +/** + * @name getSiruta + * @function + * @description gets siruta code + * @param {Object} req + * @param {Object} res + * @param {Function} next + */ var getSiruta = function (req, res, next) { if (!req.body.location) { return res.handleResponse(400, {}, 'geoJsonMiddleware_1'); @@ -37,6 +45,12 @@ var getSiruta = function (req, res, next) { }); }; +/** + * @name checkMoldova + * @function + * @description checks if given location is in Moldova's county, return its siruta + * @param {Object} pileLocation + */ function checkMoldova(pileLocation) { var deferred = Q.defer(); County.findOne({ diff --git a/server/components/mailer/index.js b/server/components/mailer/index.js index 7951c9d..7221ff4 100644 --- a/server/components/mailer/index.js +++ b/server/components/mailer/index.js @@ -14,6 +14,17 @@ var VariableTranslations = { 'NEW_PILE_STATUS': require('../../storage/language/pileStatuses') }; +/** + * @name send + * @function + * @description sends simple mail + * @param {Object} template + * @param {Object} to + * @param {Object} vars + * @param {Object} tags + * @param {Object} from + * @param {Object} options + */ var send = function (template, to, vars, tags, from, options) { //validate params @@ -86,6 +97,17 @@ var send = function (template, to, vars, tags, from, options) { exports.send = send; +/** + * @name sendToExistingUser + * @function + * @description sends mail to existing user + * @param {Object} template + * @param {String} user_id + * @param {Object} vars + * @param {Object} tags + * @param {Object} from + * @param {Object} options + */ var sendToExistingUser = function (user_id, template, vars, tags, from, options) { var User = require('../../api/user/user.model'); var deferred = Q.defer(); @@ -103,7 +125,6 @@ var sendToExistingUser = function (user_id, template, vars, tags, from, options) vars.push({name: 'LAST_NAME', content: user.last_name}); vars.push({name: 'LANG', content: user.language}); vars = tranlateVariables(vars, user.language); - //get the translated subject if (options.subject) { options.subject = MailSubjects[user.language][options.subject] } diff --git a/server/components/pushNotifications/index.js b/server/components/pushNotifications/index.js index c3d73bf..2807848 100644 --- a/server/components/pushNotifications/index.js +++ b/server/components/pushNotifications/index.js @@ -4,6 +4,13 @@ var Mustache = require('mustache'); var env = require('../../config/environment'); var pushMessages = require('../../storage/language/pushNotifications'); +/** + * @name activityNotify + * @function + * @description map activity details, format notification message, + * use PushServerNotify function to send a message to a user + * @param {Object} activity + */ exports.activityNotify = function (activity) { if (activity.actor._id && activity.actor.role && activity.pile.user._id && activity.pile.user.flags.receivePushNotifications && activity.pile.user.role && activity.pile.nr_ord) { var actor = { @@ -17,13 +24,8 @@ exports.activityNotify = function (activity) { language: activity.pile.user.language }; var verb = activity.verb; - // We now have all the details of the new activity. - // Place all of the sending logic below. - // Use pushServerNotify function to send a message to a user if (pileOwner.notificationsEnabled) { - //we can proceed - if (actor.id !== pileOwner.id) { //prevent self notify - //format a nice message to send as notification + if (actor.id !== pileOwner.id) { var messageCode; var data = { nr_ord: activity.pile.nr_ord @@ -57,6 +59,13 @@ exports.activityNotify = function (activity) { } }; +/** + * @name pushServerNotify + * @function + * @description creates a request to push notifications server + * @param {String} user_id + * @param {String} message + */ var pushServerNotify = function (user_id, message) { try { var formattedUsers = [env.pushNotifications.userPrefix + user_id.toString()]; @@ -96,17 +105,24 @@ var pushServerNotify = function (user_id, message) { } }; +/** + * @name subscribe + * @function + * @description subscribe user for push notifications, + * first, unsubscribe this device to prevent conflicts with logging in different users on same device + * @param {String} deviceName + * @param {String} deviceToken + * @param {String} user_id + * @return {Promise} + */ exports.subscribe = function (deviceName, deviceToken, user_id) { var deferred = Q.defer(); - // if user logs in from a device, subscribe user for push notifications - if (deviceName && deviceToken) { - //first, unsubscribe this device to prevent conflicts with logging in different users on same device + // unsubscribeUser(user_id).then( function (success) { - //subscribe user for push notifications var subscribeData = { 'user': env.pushNotifications.userPrefix + user_id.toString(), 'type': deviceName, @@ -136,6 +152,13 @@ exports.subscribe = function (deviceName, deviceToken, user_id) { return deferred.promise; }; +/** + * @name unsubscribeDevice + * @function + * @description unsubscribe device from push notifications, + * @param {String} deviceToken + * @return {Promise} + */ var unsubscribeDevice = function (deviceToken) { var deferred = Q.defer(); if (deviceToken) { @@ -153,6 +176,13 @@ var unsubscribeDevice = function (deviceToken) { return deferred.promise; }; +/** + * @name unsubscribeUser + * @function + * @description unsubscribe user from push notifications, + * @param {String} user_id + * @return {Promise} + */ var unsubscribeUser = function (user_id) { var deferred = Q.defer(); if (user_id) { @@ -170,6 +200,14 @@ var unsubscribeUser = function (user_id) { return deferred.promise; }; +/** + * @name unsubscribe + * @function + * @description unsubscribe from push notifications, + * @param {String} usType + * @param {String} usData + * @return {Promise} + */ var unsubscribe = function (usType, usData) { var deferred = Q.defer(); @@ -198,6 +236,14 @@ var unsubscribe = function (usType, usData) { return deferred.promise; }; +/** + * @name generateMessage + * @function + * @description generates message + * @param {String} messageCode + * @param {Object} data + * @param {String} language + */ function generateMessage(messageCode, data, language) { var message = pushMessages[language][messageCode]; return Mustache.render(message, data) diff --git a/server/components/queue/index.js b/server/components/queue/index.js index 320f30b..21ac7fa 100644 --- a/server/components/queue/index.js +++ b/server/components/queue/index.js @@ -8,10 +8,6 @@ var config = require('../../config/environment'); var ImageService = require('../../api/image/image.service'); var TemporaryStorage = require('../../components/temporaryStorage'); -// ============================================================= configure Kue - -// Kue stores job objects in memory until they are complete/failed to be able to emit events on them. -// If you have a huge concurrency in uncompleted jobs, turn this feature off and use queue level events for better memory scaling. var queue = kue.createQueue({ jobEvents: false, prefix: 'q', @@ -21,6 +17,17 @@ var queue = kue.createQueue({ } }); +/** + * @name uploadPileImage + * @function + * @description Kue stores job objects in memory until they are complete/failed to be able to emit events on them. + * If you have a huge concurrency in uncompleted jobs, turn this feature off and use queue level events for better memory scaling. + * @param {String} file_path + * @param {String} file_extension + * @param {String} pile_id + * @param {String} image_id + * @param {Object} user + */ function uploadPileImage(file_path, file_extension, pile_id, image_id, user) { TemporaryStorage.getResource(file_path) .then(function (buffer) { diff --git a/server/components/response/index.js b/server/components/response/index.js index d2deb5c..27b33b4 100644 --- a/server/components/response/index.js +++ b/server/components/response/index.js @@ -5,16 +5,17 @@ var raven = require('raven'); var client = new raven.Client(config.sentryUrl); /** * Middleware that handles the response - * - * @name handleResponse - * @function - * @param {number} status - Status code for response. - * @param {object} data - Additional data sent in response. - * @param {String} code - The code for corresponding message - * @example - * res.handleResponse(200, {}, "user_1"); */ module.exports = function (req, res, next) { + /** + * @name handleResponse + * @function + * @param {number} status - Status code for response. + * @param {object} data - Additional data sent in response. + * @param {String} code - The code for corresponding message + * @example + * res.handleResponse(200, {}, "user_1"); + */ res.handleResponse = function (status, data, code) { if (!!data && data.error) { client.setExtraContext({status: status, data: data, code: code}); diff --git a/server/components/statistics/index.js b/server/components/statistics/index.js index 956a7ed..d546a5a 100644 --- a/server/components/statistics/index.js +++ b/server/components/statistics/index.js @@ -8,12 +8,19 @@ var UtilsService = require('../utils'); var County = require('../../api/county/county.model'); +/** + * @name formatElasticQuery + * @function + * @description formats query for elastic search + * @param {Object} county_id + * @param {Object} date_start + * @param {Object} date_end + */ var formatElasticQuery = function (county_id, date_start, date_end) { var query = { filtered: {} }; - //filter by county id if (county_id) { query.filtered.query = { match: { @@ -22,7 +29,6 @@ var formatElasticQuery = function (county_id, date_start, date_end) { }; } - //filter by date range var range_options = {}; if (UtilsService.isDate(date_start)) { @@ -57,14 +63,21 @@ var formatElasticQuery = function (county_id, date_start, date_end) { return query; }; +/** + * @name getPileStats + * @function + * @description gets pile stats, form query object, form aggregation object, if report is not requested for specific county, + * sub-aggregate for each county, place the query before the aggregations and finally, form the request payload + * @param {Object} county_id + * @param {Object} date_start + * @param {Object} date_end + */ var getPileStats = function (county_id, date_start, date_end) { var deferred = Q.defer(); - //first filter piles that need to be aggregated by forming a query object var query = formatElasticQuery(county_id, date_start, date_end); - //next, form the aggregations object var aggregations = { status: { terms: { @@ -74,7 +87,7 @@ var getPileStats = function (county_id, date_start, date_end) { content: { terms: { field: 'content', - size: 50 // default value is 10 + size: 50 } }, size: { @@ -89,7 +102,6 @@ var getPileStats = function (county_id, date_start, date_end) { } }; - //if report is not requested for a specific county, sub-aggregate for each county if (!county_id) { aggregations.county = { terms: { @@ -99,15 +111,12 @@ var getPileStats = function (county_id, date_start, date_end) { }; } - //finally, form our request payload; it is important to place the query before the aggregations - var data = {}; if (query) { data.query = query; } data.aggs = aggregations; - //send the request request({ method: 'POST', uri: env.elasticHost + '/piles/pile/_search', @@ -124,14 +133,21 @@ var getPileStats = function (county_id, date_start, date_end) { return deferred.promise; }; +/** + * @name getUserStats + * @function + * @description gets user stats, form query object, form aggregation object, if report is not requested for specific county, + * sub-aggregate for each county, place the query before the aggregations and finally, form the request payload + * @param {Object} county_id + * @param {Object} date_start + * @param {Object} date_end + */ var getUserStats = function (county_id, date_start, date_end) { var deferred = Q.defer(); - //first filter users that need to be aggregated by forming a query object var query = formatElasticQuery(county_id, date_start, date_end); - //next, form the aggregations object var aggregations = { status: { terms: { @@ -150,15 +166,12 @@ var getUserStats = function (county_id, date_start, date_end) { } }; - //finally, form our request payload; it is important to place the query before the aggregations - var data = {}; if (query) { data.query = query; } data.aggs = aggregations; - //send the request request({ method: 'POST', uri: env.elasticHost + '/users/user/_search', @@ -229,12 +242,19 @@ var parsePileAggs = function (aggs, callback) { } }; +/** + * @name getPileStats + * @function + * @description format a readable client response from our elastic server response + * @param {Object} county_id + * @param {Object} date_start + * @param {Object} date_end + */ exports.getPileStats = function (county_id, date_start, date_end) { var deferred = Q.defer(); if (county_id || (date_start && date_end)) { getPileStats(county_id, date_start, date_end).then( function (success) { - //format a readable client response from our elastic server response var total = success.hits.total; var aggs = success.aggregations; parsePileAggs(aggs, function (err, parsed) { @@ -266,11 +286,18 @@ exports.getPileStats = function (county_id, date_start, date_end) { return deferred.promise; }; +/** + * @name getUserStats + * @function + * @description format a readable client response from our elastic server response + * @param {Object} county_id + * @param {Object} date_start + * @param {Object} date_end + */ exports.getUserStats = function (county_id, date_start, date_end) { var deferred = Q.defer(); getUserStats(county_id, date_start, date_end).then( function (success) { - //format a readable client response from our elastic server response var ret = {}; ret.total = success.hits.total; var aggs = success.aggregations; diff --git a/server/components/temporaryStorage/index.js b/server/components/temporaryStorage/index.js index f2ce867..491632b 100644 --- a/server/components/temporaryStorage/index.js +++ b/server/components/temporaryStorage/index.js @@ -6,6 +6,13 @@ var env = require('../../config/environment'); var storage_path = env.formDataParser.fileSaveLocation; +/** + * @name getResource + * @function + * @description gets temporary resource + * @param {String} name + * @returns {Promise} + */ function getResource(name) { var deferred = Q.defer(); fs.readFile(path.join(storage_path, name), function (err, buffer) { @@ -18,6 +25,13 @@ function getResource(name) { return deferred.promise; } +/** + * @name saveResource + * @function + * @description saves temporary resource + * @param {String} name + * @returns {Promise} + */ function saveResource(name, buffer) { var deferred = Q.defer(); fs.writeFile(path.join(storage_path, name), buffer, function (err) { @@ -30,6 +44,13 @@ function saveResource(name, buffer) { return deferred.promise; } +/** + * @name deleteResource + * @function + * @description deletes temporary resource + * @param {String} name + * @returns {Promise} + */ function deleteResource(name) { var deferred = Q.defer(); fs.unlink(path.join(storage_path, name), function (err) { diff --git a/server/components/utils/index.js b/server/components/utils/index.js index 63dbce2..24acdd2 100644 --- a/server/components/utils/index.js +++ b/server/components/utils/index.js @@ -1,6 +1,13 @@ var Q = require('q'); var spawn = require('child_process').spawn; +/** + * @name discardFields + * @function + * @description discard fields from object + * @param {String} obj + * @param {Array} fieldsArray + */ exports.discardFields = function (obj, fieldsArray) { fieldsArray = fieldsArray || []; for (var key in obj) { @@ -9,6 +16,14 @@ exports.discardFields = function (obj, fieldsArray) { } } }; + +/** + * @name allowFields + * @function + * @description discard not allowed fields from object + * @param {String} obj + * @param {Array} fieldsArray + */ exports.allowFields = function (obj, fieldsArray) { fieldsArray = fieldsArray || []; for (var key in obj) { @@ -26,6 +41,14 @@ exports.isArray = function (obj) { exports.isEmptyObject = function (obj) { return Object.keys(obj).length === 0; }; + +/** + * @name formatDate + * @function + * @description format date + * @param {String} date + * @param {Object} options + */ exports.formatDate = function (date, options) { options = options || {}; var language = options.language || 'ro'; @@ -74,6 +97,12 @@ exports.resetTimeInDate = function (date) { return date.setHours(0, 0, 0, 0); }; +/** + * @name latinLettersOnly + * @function + * @description replaces special characters + * @param {String} str + */ exports.latinLettersOnly = function (str) { if (typeof str !== 'string') { str = ''; @@ -96,6 +125,12 @@ exports.latinLettersOnly = function (str) { .replace(/[^a-zA-Z]/g, ''); }; +/** + * @name latinLettersAndNumbersOnly + * @function + * @description replaces special characters + * @param {String} str + */ exports.latinLettersAndNumbersOnly = function (str) { if (typeof str !== 'string') { str = ''; @@ -118,6 +153,13 @@ exports.latinLettersAndNumbersOnly = function (str) { .replace(/[^a-zA-Z0-9]/g, ''); }; +/** + * @name decToDms + * @function + * @description formats location + * @param {Object} input + * @param {String} latlng + */ exports.decToDms = function (input, latlng) { var v = input.toString().split('.'); var pole = (latlng === 'lat' ? (parseInt(v[1]) < 0 ? 'S' : 'N') : (parseInt(v[1]) < 0) ? 'V' : 'E');