controllers.js 47 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199
  1. 'use strict';
  2. /* Controllers; their method are available where specified with the ng-controller
  3. * directive or for a given route/state (see app.js). They use some services to
  4. * connect to the backend (see services.js). */
  5. var eventManControllers = angular.module('eventManControllers', []);
  6. /* A controller that can be used to navigate. */
  7. eventManControllers.controller('NavigationCtrl', ['$scope', '$rootScope', '$location', 'Setting', '$state',
  8. function ($scope, $rootScope, $location, Setting, $state) {
  9. $scope.logo = {};
  10. $scope.getLocation = function() {
  11. return $location.absUrl();
  12. };
  13. $scope.go = function(url) {
  14. $location.url(url);
  15. };
  16. Setting.query({setting: 'logo'}, function(data) {
  17. if (data && data.length) {
  18. $scope.logo = data[0];
  19. }
  20. });
  21. $scope.isActive = function(view) {
  22. if (view === $location.path()) {
  23. return true;
  24. }
  25. if (view[view.length-1] !== '/') {
  26. view = view + '/';
  27. }
  28. return $location.path().indexOf(view) == 0;
  29. };
  30. }]
  31. );
  32. /* Controller for a group of date and time pickers. */
  33. eventManControllers.controller('DatetimePickerCtrl', ['$scope',
  34. function ($scope) {
  35. $scope.open = function() {
  36. $scope.opened = true;
  37. };
  38. }]
  39. );
  40. /* Controller for modals. */
  41. eventManControllers.controller('ModalConfirmInstanceCtrl', ['$scope', '$uibModalInstance', 'message',
  42. function ($scope, $uibModalInstance, message) {
  43. $scope.message = message;
  44. $scope.ok = function () {
  45. $uibModalInstance.close($scope);
  46. };
  47. $scope.cancel = function () {
  48. $uibModalInstance.dismiss('cancel');
  49. };
  50. }]
  51. );
  52. eventManControllers.controller('EventsListCtrl', ['$scope', 'Event', 'EventTicket', '$uibModal', '$log', '$translate', '$rootScope', '$state', '$filter', 'toaster',
  53. function ($scope, Event, EventTicket, $uibModal, $log, $translate, $rootScope, $state, $filter, toaster) {
  54. $scope.query = '';
  55. $scope.tickets = [];
  56. $scope.eventsOrderProp = "-begin_date";
  57. $scope.ticketsOrderProp = ["name", "surname"];
  58. $scope.groupByEmail = false;
  59. $scope.shownItems = [];
  60. $scope.currentPage = 1;
  61. $scope.itemsPerPage = 10;
  62. $scope.filteredLength = 0;
  63. $scope.maxPaginationSize = 10;
  64. var query_params = {};
  65. if (!$state.is('tickets')) {
  66. query_params['_summary'] = true
  67. }
  68. $scope.events = Event.all(query_params, function(events) {
  69. if (events && $state.is('tickets')) {
  70. angular.forEach(events, function(evt, idx) {
  71. var evt_tickets = (evt.tickets || []).slice(0);
  72. angular.forEach(evt_tickets, function(obj, obj_idx) {
  73. obj.event_title = evt.title;
  74. obj.event_id = evt._id;
  75. });
  76. $scope.tickets.push.apply($scope.tickets, evt_tickets || []);
  77. });
  78. $scope.filterTickets();
  79. }
  80. });
  81. $scope.filterTickets = function() {
  82. var tickets = angular.copy($scope.tickets || []);
  83. if ($scope.groupByEmail) {
  84. var newDict = {};
  85. var newList = [];
  86. angular.forEach(tickets, function(item, idx) {
  87. if (!newDict[item.email]) {
  88. newDict[item.email] = {};
  89. newDict[item.email]['name'] = item.name;
  90. newDict[item.email]['surname'] = item.surname;
  91. newDict[item.email]['email'] = item.email;
  92. newDict[item.email]['job title'] = item.job;
  93. newDict[item.email]['company'] = item.company;
  94. newDict[item.email]['tickets'] = [];
  95. }
  96. newDict[item.email]['tickets'].push(item);
  97. });
  98. angular.forEach(newDict, function(value, key) {
  99. newList.push(value);
  100. });
  101. tickets = newList;
  102. }
  103. tickets = $filter('splittedFilter')(tickets, $scope.query);
  104. tickets = $filter('orderBy')(tickets, $scope.ticketsOrderProp);
  105. $scope.filteredLength = tickets.length;
  106. tickets = $filter('pagination')(tickets, $scope.currentPage, $scope.itemsPerPage);
  107. $scope.shownItems = tickets;
  108. };
  109. $scope.$watch('query', function() {
  110. if (!$scope.query) {
  111. $scope.currentPage = 1;
  112. }
  113. $scope.filterTickets();
  114. });
  115. $scope.$watch('groupByEmail', function() {
  116. $scope.filterTickets();
  117. });
  118. $scope.$watch('currentPage + itemsPerPage', function() {
  119. $scope.filterTickets();
  120. });
  121. $scope.confirm_delete = 'Do you really want to delete this event?';
  122. $scope.confirm_delete_all_tickets = 'Do you really want to delete all tickets from this event?';
  123. $scope.deleted_all_tickets = 'successfully removed all tickets from event';
  124. $rootScope.$on('$translateChangeSuccess', function () {
  125. $translate('Do you really want to delete this event?').then(function (translation) {
  126. $scope.confirm_delete = translation;
  127. });
  128. $translate('Do you really want to delete all tickets from this event?').then(function (translation) {
  129. $scope.confirm_delete_all_tickets = translation;
  130. });
  131. $translate('successfully removed all tickets from event').then(function (translation) {
  132. $scope.deleted_all_tickets = translation;
  133. });
  134. });
  135. $scope.deleteEvent = function(_id) {
  136. var modalInstance = $uibModal.open({
  137. scope: $scope,
  138. templateUrl: 'modal-confirm-action.html',
  139. controller: 'ModalConfirmInstanceCtrl',
  140. resolve: {
  141. message: function() { return $scope.confirm_delete; }
  142. }
  143. });
  144. modalInstance.result.then(function() {
  145. Event.delete({'id': _id}, function() {
  146. $scope.events = Event.all();
  147. });
  148. });
  149. };
  150. $scope.deleteAllTickets = function(_id) {
  151. var modalInstance = $uibModal.open({
  152. scope: $scope,
  153. templateUrl: 'modal-confirm-action.html',
  154. controller: 'ModalConfirmInstanceCtrl',
  155. resolve: {
  156. message: function() { return $scope.confirm_delete_all_tickets; }
  157. }
  158. });
  159. modalInstance.result.then(function() {
  160. EventTicket.delete({
  161. event_id: _id
  162. }, function() {
  163. toaster.pop({type: 'error', title: $scope.deleted_all_tickets});
  164. $scope.events = Event.all();
  165. });
  166. });
  167. };
  168. $scope.updateOrded = function(key) {
  169. var new_order = [key];
  170. var inv_key;
  171. if (key && key[0] === '-') {
  172. inv_key = key.substring(1);
  173. } else {
  174. inv_key = '-' + key;
  175. }
  176. angular.forEach($scope.ticketsOrderProp,
  177. function(value, idx) {
  178. if (value !== key && value !== inv_key) {
  179. new_order.push(value);
  180. }
  181. }
  182. );
  183. $scope.ticketsOrderProp = new_order;
  184. $scope.filterTickets();
  185. };
  186. }]
  187. );
  188. var default_formSchema = {
  189. "btnSubmitText": "Submit",
  190. "formlyFieldsModel": [
  191. {
  192. "className": "row",
  193. "fieldGroup": [
  194. {
  195. "templateOptions": {
  196. "description": "",
  197. "type": "",
  198. "required": false,
  199. "label": "Name",
  200. "placeholder": "",
  201. "options": []
  202. },
  203. "className": "col-xs-4",
  204. "expressionProperties": {},
  205. "key": "input-1512294560560",
  206. "validators": {},
  207. "validation": {
  208. "messages": {}
  209. },
  210. "type": "input"
  211. },
  212. {
  213. "templateOptions": {
  214. "description": "",
  215. "type": "",
  216. "required": false,
  217. "label": "Surname",
  218. "placeholder": "",
  219. "options": []
  220. },
  221. "className": "col-xs-4",
  222. "expressionProperties": {},
  223. "key": "input-1512294555929",
  224. "validators": {},
  225. "validation": {
  226. "messages": {}
  227. },
  228. "type": "input"
  229. },
  230. {
  231. "templateOptions": {
  232. "description": "",
  233. "type": "",
  234. "required": false,
  235. "label": "Email",
  236. "placeholder": "",
  237. "options": []
  238. },
  239. "className": "col-xs-4",
  240. "expressionProperties": {},
  241. "key": "input-1512294566386",
  242. "validators": {},
  243. "validation": {
  244. "messages": {}
  245. },
  246. "type": "input"
  247. }
  248. ]
  249. },
  250. {
  251. "className": "row",
  252. "fieldGroup": [
  253. {
  254. "templateOptions": {
  255. "description": "",
  256. "type": "",
  257. "required": false,
  258. "label": "Job title",
  259. "placeholder": "",
  260. "options": []
  261. },
  262. "className": "col-xs-6",
  263. "expressionProperties": {},
  264. "key": "input-1512294529739",
  265. "validators": {},
  266. "validation": {
  267. "messages": {}
  268. },
  269. "type": "input"
  270. },
  271. {
  272. "templateOptions": {
  273. "description": "",
  274. "type": "",
  275. "required": false,
  276. "label": "Company",
  277. "placeholder": "",
  278. "options": []
  279. },
  280. "className": "col-xs-6",
  281. "expressionProperties": {},
  282. "key": "input-1512294538113",
  283. "validators": {},
  284. "validation": {
  285. "messages": {}
  286. },
  287. "type": "input"
  288. }
  289. ]
  290. }
  291. ],
  292. "dataModel": {},
  293. "edaFieldsModelStringified": "[{\"line\":1,\"activeColumn\":1,\"columns\":[{\"numColumn\":1,\"exist\":true,\"control\":{\"type\":\"input\",\"key\":\"input-1512294560560\",\"selectedControl\":\"TextInput\",\"subtype\":\"\",\"templateOptions\":{\"label\":\"Name\",\"required\":false,\"description\":\"\",\"placeholder\":\"\",\"options\":[]},\"formlyExpressionProperties\":{},\"formlyValidators\":{},\"formlyValidation\":{\"messages\":{}},\"edited\":true}},{\"numColumn\":2,\"exist\":true,\"control\":{\"type\":\"input\",\"key\":\"input-1512294555929\",\"subtype\":\"\",\"selectedControl\":\"TextInput\",\"templateOptions\":{\"label\":\"Surname\",\"required\":false,\"description\":\"\",\"placeholder\":\"\",\"options\":[]},\"formlyExpressionProperties\":{},\"formlyValidators\":{},\"formlyValidation\":{\"messages\":{}},\"edited\":true}},{\"numColumn\":3,\"exist\":true,\"control\":{\"type\":\"input\",\"key\":\"input-1512294566386\",\"subtype\":\"\",\"selectedControl\":\"TextInput\",\"templateOptions\":{\"label\":\"Email\",\"required\":false,\"description\":\"\",\"placeholder\":\"\",\"options\":[]},\"formlyExpressionProperties\":{},\"formlyValidators\":{},\"formlyValidation\":{\"messages\":{}},\"edited\":true}}]},{\"line\":-1,\"activeColumn\":1,\"columns\":[{\"numColumn\":1,\"exist\":true,\"control\":{\"type\":\"input\",\"key\":\"input-1512294529739\",\"selectedControl\":\"TextInput\",\"subtype\":\"\",\"templateOptions\":{\"label\":\"Job title\",\"required\":false,\"description\":\"\",\"placeholder\":\"\",\"options\":[]},\"formlyExpressionProperties\":{},\"formlyValidators\":{},\"formlyValidation\":{\"messages\":{}},\"edited\":true}},{\"numColumn\":2,\"exist\":true,\"control\":{\"type\":\"input\",\"key\":\"input-1512294538113\",\"subtype\":\"\",\"selectedControl\":\"TextInput\",\"templateOptions\":{\"label\":\"Company\",\"required\":false,\"description\":\"\",\"placeholder\":\"\",\"options\":[]},\"formlyExpressionProperties\":{},\"formlyValidators\":{},\"formlyValidation\":{\"messages\":{}},\"edited\":true}}]}]",
  294. "edaFieldsModel": [
  295. {
  296. "line": 1,
  297. "activeColumn": 1,
  298. "columns": [
  299. {
  300. "control": {
  301. "edited": true,
  302. "templateOptions": {
  303. "options": [],
  304. "required": false,
  305. "placeholder": "",
  306. "description": "",
  307. "label": "Name"
  308. },
  309. "formlyExpressionProperties": {},
  310. "subtype": "",
  311. "formlyValidators": {},
  312. "key": "input-1512294560560",
  313. "selectedControl": "TextInput",
  314. "type": "input",
  315. "formlyValidation": {
  316. "messages": {}
  317. }
  318. },
  319. "exist": true,
  320. "numColumn": 1
  321. },
  322. {
  323. "control": {
  324. "edited": true,
  325. "templateOptions": {
  326. "options": [],
  327. "required": false,
  328. "placeholder": "",
  329. "description": "",
  330. "label": "Surname"
  331. },
  332. "formlyExpressionProperties": {},
  333. "subtype": "",
  334. "formlyValidators": {},
  335. "key": "input-1512294555929",
  336. "selectedControl": "TextInput",
  337. "type": "input",
  338. "formlyValidation": {
  339. "messages": {}
  340. }
  341. },
  342. "exist": true,
  343. "numColumn": 2
  344. },
  345. {
  346. "control": {
  347. "edited": true,
  348. "templateOptions": {
  349. "options": [],
  350. "required": false,
  351. "placeholder": "",
  352. "description": "",
  353. "label": "Email"
  354. },
  355. "formlyExpressionProperties": {},
  356. "subtype": "",
  357. "formlyValidators": {},
  358. "key": "input-1512294566386",
  359. "selectedControl": "TextInput",
  360. "type": "input",
  361. "formlyValidation": {
  362. "messages": {}
  363. }
  364. },
  365. "exist": true,
  366. "numColumn": 3
  367. }
  368. ]
  369. },
  370. {
  371. "line": -1,
  372. "activeColumn": 1,
  373. "columns": [
  374. {
  375. "control": {
  376. "edited": true,
  377. "templateOptions": {
  378. "options": [],
  379. "required": false,
  380. "placeholder": "",
  381. "description": "",
  382. "label": "Job title"
  383. },
  384. "formlyExpressionProperties": {},
  385. "subtype": "",
  386. "formlyValidators": {},
  387. "key": "input-1512294529739",
  388. "selectedControl": "TextInput",
  389. "type": "input",
  390. "formlyValidation": {
  391. "messages": {}
  392. }
  393. },
  394. "exist": true,
  395. "numColumn": 1
  396. },
  397. {
  398. "control": {
  399. "edited": true,
  400. "templateOptions": {
  401. "options": [],
  402. "required": false,
  403. "placeholder": "",
  404. "description": "",
  405. "label": "Company"
  406. },
  407. "formlyExpressionProperties": {},
  408. "subtype": "",
  409. "formlyValidators": {},
  410. "key": "input-1512294538113",
  411. "selectedControl": "TextInput",
  412. "type": "input",
  413. "formlyValidation": {
  414. "messages": {}
  415. }
  416. },
  417. "exist": true,
  418. "numColumn": 2
  419. }
  420. ]
  421. }
  422. ],
  423. "btnCancelText": "Cancel",
  424. "formName": "registration_form"
  425. };
  426. eventManControllers.controller('EventDetailsCtrl', ['$scope', '$state', 'Event', '$log', '$translate', '$rootScope',
  427. function ($scope, $state, Event, $log, $translate, $rootScope) {
  428. $scope.event = {};
  429. $scope.event.tickets = [];
  430. $scope.event.formSchema = {};
  431. $scope.eventFormDisabled = false;
  432. if ($state.params.id) {
  433. var params = angular.copy($state.params);
  434. params['_summary'] = true;
  435. $scope.event = Event.get(params);
  436. if ($state.is('event.view') || !$rootScope.hasPermission('event|update')) {
  437. $scope.eventFormDisabled = true;
  438. }
  439. } else if (!($scope.event.formSchema && $scope.event.formSchema.formlyFieldsModel)) {
  440. $scope.event.formSchema = default_formSchema;
  441. }
  442. // store a new Event or update an existing one
  443. $scope.save = function() {
  444. // avoid override of event.tickets list.
  445. var this_event = angular.copy($scope.event);
  446. if (this_event.tickets) {
  447. delete this_event.tickets;
  448. }
  449. if (this_event._id === undefined) {
  450. $scope.event = Event.save(this_event);
  451. } else {
  452. $scope.event = Event.update(this_event);
  453. }
  454. $scope.eventForm.$setPristine(false);
  455. };
  456. $scope.saveForm = function(easyFormGeneratorModel) {
  457. $scope.event.formSchema = easyFormGeneratorModel;
  458. $scope.save();
  459. };
  460. }]
  461. );
  462. eventManControllers.controller('EventTicketsCtrl', ['$scope', '$state', 'Event', 'EventTicket', 'Setting', '$log', '$translate', '$rootScope', 'EventUpdates', '$uibModal', '$filter', 'toaster',
  463. function ($scope, $state, Event, EventTicket, Setting, $log, $translate, $rootScope, EventUpdates, $uibModal, $filter, toaster) {
  464. $scope.ticketsOrder = ["name", "surname"];
  465. $scope.countAttendees = 0;
  466. $scope.query = '';
  467. $scope.event = {};
  468. $scope.event.tickets = [];
  469. $scope.shownItems = [];
  470. $scope.ticket = {}; // current ticket, for the event.ticket.* states
  471. $scope.tickets = []; // list of all tickets, for the 'tickets' state
  472. $scope.filteredTickets = [];
  473. $scope.formSchema = {};
  474. $scope.formData = {};
  475. $scope.guiOptions = {dangerousActionsEnabled: false};
  476. $scope.customFields = Setting.query({setting: 'ticket_custom_field', in_event_details: true});
  477. $scope.registeredFilterOptions = {all: false};
  478. $scope.formFieldsMap = {};
  479. $scope.formFieldsMapRev = {};
  480. $scope.currentPage = 1;
  481. $scope.itemsPerPage = 10;
  482. $scope.filteredLength = 0;
  483. $scope.maxPaginationSize = 10;
  484. $scope.maxAllPersons = 10;
  485. $scope.filterTickets = function() {
  486. var tickets = $scope.event.tickets || [];
  487. tickets = $filter('splittedFilter')(tickets, $scope.query);
  488. tickets = $filter('registeredFilter')(tickets, $scope.registeredFilterOptions);
  489. tickets = $filter('orderBy')(tickets, $scope.ticketsOrder);
  490. $scope.filteredTickets = angular.copy(tickets);
  491. $scope.filteredLength = $scope.filteredTickets.length;
  492. tickets = $filter('pagination')(tickets, $scope.currentPage, $scope.itemsPerPage);
  493. $scope.shownItems = tickets;
  494. $scope.updateCSV();
  495. };
  496. $scope.$watch('query', function() {
  497. if (!$scope.query) {
  498. $scope.currentPage = 1;
  499. }
  500. $scope.filterTickets();
  501. });
  502. $scope.$watchCollection('registeredFilterOptions', function() {
  503. $scope.filterTickets();
  504. });
  505. $scope.$watch('currentPage + itemsPerPage', function() {
  506. $scope.filterTickets();
  507. });
  508. if ($state.params.id) {
  509. $scope.event = Event.get({id: $state.params.id}, function(data) {
  510. $scope.$watchCollection(function() {
  511. return $scope.event.tickets;
  512. }, function(new_collection, old_collection) {
  513. $scope.calcAttendees();
  514. $scope.filterTickets();
  515. }
  516. );
  517. if (!(data && data.formSchema)) {
  518. return;
  519. }
  520. $scope.formSchema = data.formSchema.edaFieldsModel;
  521. $scope.extractFormFields(data.formSchema.formlyFieldsModel);
  522. // Editing an existing ticket
  523. if ($state.params.ticket_id) {
  524. EventTicket.get({id: $state.params.id, ticket_id: $state.params.ticket_id}, function(data) {
  525. $scope.ticket = data;
  526. angular.forEach(data, function(value, key) {
  527. if (!$scope.formFieldsMapRev[key]) {
  528. return;
  529. }
  530. $scope.formData[$scope.formFieldsMapRev[key]] = value;
  531. });
  532. });
  533. }
  534. });
  535. // Managing the list of tickets.
  536. if ($state.is('event.tickets')) {
  537. $scope.allPersons = Event.group_persons({id: $state.params.id});
  538. // Handle WebSocket connection used to update the list of tickets.
  539. $scope.EventUpdates = EventUpdates;
  540. $scope.EventUpdates.open();
  541. $scope.$watchCollection(function() {
  542. return $scope.EventUpdates.data;
  543. }, function(new_collection, old_collection) {
  544. if (!($scope.EventUpdates.data && $scope.EventUpdates.data.update)) {
  545. $log.debug('no data received from the WebSocket');
  546. return;
  547. }
  548. var data = $scope.EventUpdates.data.update;
  549. $log.debug('received ' + data.action + ' action from websocket source ' + data.uuid + ' . Full data:');
  550. $log.debug(data);
  551. if ($rootScope.app_uuid == data.uuid) {
  552. $log.debug('do not process our own message');
  553. return false;
  554. }
  555. if (data.error && data.message && $scope.info.user.username == data.username) {
  556. if (data.searchFor) {
  557. $scope.query = angular.copy(data.searchFor);
  558. }
  559. toaster.pop({type: 'error', title: 'Error', body: data.message, timeout: 0, showCloseButton: true});
  560. return;
  561. }
  562. if (!$scope.event.tickets) {
  563. $scope.event.tickets = [];
  564. }
  565. var ticket_id = data._id || (data.ticket && data.ticket._id);
  566. var ticket_idx = $scope.event.tickets.findIndex(function(el, idx, array) {
  567. return ticket_id && (ticket_id == el._id);
  568. });
  569. if (ticket_idx != -1) {
  570. $log.debug('_id ' + data._id + ' found');
  571. } else {
  572. $log.debug('_id ' + data._id + ' not found');
  573. }
  574. if (data.action == 'update' && ticket_idx != -1 && $scope.event.tickets[ticket_idx] != data.ticket) {
  575. // if we're updating the 'attended' key and the action came from us (same user, possibly on
  576. // a different station), also show a message.
  577. if (data.ticket.attended != $scope.event.tickets[ticket_idx].attended &&
  578. $scope.info.user.username == data.username) {
  579. $scope.showAttendedMessage(data.ticket, data.ticket.attended);
  580. }
  581. $scope.event.tickets.splice(ticket_idx, 1, data.ticket);
  582. } else if (data.action == 'add' && ticket_idx == -1) {
  583. $scope._localAddTicket(data.ticket);
  584. } else if (data.action == 'delete' && ticket_idx != -1) {
  585. $scope._localRemoveTicket({_id: data._id});
  586. }
  587. }
  588. );
  589. /* event listners; needed because otherwise, adding a ticket with the Quick add form,
  590. * we'd be changing the $scope outside of the AngularJS's $digest. */
  591. $scope.$on('event:ticket:new', function(evt, ticket, callback) {
  592. $scope._localAddTicket(ticket);
  593. if (callback) {
  594. callback(ticket);
  595. }
  596. });
  597. $scope.$on('event:ticket:update', function(evt, ticket) {
  598. if (!$scope.event.tickets) {
  599. $scope.event.tickets = [];
  600. }
  601. var ticket_idx = $scope.event.tickets.findIndex(function(el, idx, array) {
  602. return ticket._id == el._id;
  603. });
  604. if (ticket_idx == -1) {
  605. $log.debug('ticket not present: not updated');
  606. return false;
  607. }
  608. $scope.event.tickets.splice(ticket_idx, 1, ticket);
  609. });
  610. $scope.$on('event:ticket:set-attr', function(evt, ticket, key, value, callback, hideMessage) {
  611. $scope.setTicketAttribute(ticket, key, value, callback, hideMessage);
  612. });
  613. }
  614. } else if ($state.is('tickets')) {
  615. $scope.tickets = EventTicket.all();
  616. }
  617. $scope.calcAttendees = function() {
  618. if (!($scope.event && $scope.event.tickets)) {
  619. $scope.countAttendees = 0;
  620. return;
  621. }
  622. var attendees = 0;
  623. angular.forEach($scope.event.tickets, function(value, key) {
  624. if (value.attended && !value.cancelled) {
  625. attendees += 1;
  626. }
  627. });
  628. $scope.countAttendees = attendees;
  629. };
  630. /* Stuff to do when a ticket is added, modified or removed locally. */
  631. $scope._localAddTicket = function(ticket, original_ticket) {
  632. if (!$state.is('event.tickets')) {
  633. return true;
  634. }
  635. var ret = true;
  636. if (!$scope.event.tickets) {
  637. $scope.event.tickets = [];
  638. }
  639. var ticket_idx = $scope.event.tickets.findIndex(function(el, idx, array) {
  640. return ticket._id == el._id;
  641. });
  642. if (ticket_idx != -1) {
  643. $log.warn('ticket already present: not added');
  644. ret = false;
  645. } else {
  646. $scope.event.tickets.push(ticket);
  647. }
  648. // Try to remove this person from the allPersons list using ID of the original entry or email.
  649. var field = null;
  650. var field_value = null;
  651. if (original_ticket && original_ticket._id) {
  652. field = '_id';
  653. field_value = original_ticket._id;
  654. } else if (ticket.email) {
  655. field = 'email';
  656. field_value = ticket.email;
  657. }
  658. if (field) {
  659. var all_person_idx = $scope.allPersons.findIndex(function(el, idx, array) {
  660. return field_value == el[field];
  661. });
  662. if (all_person_idx != -1) {
  663. $scope.allPersons.splice(all_person_idx, 1);
  664. }
  665. }
  666. return ret;
  667. };
  668. $scope._localUpdateTicket = function(ticket) {
  669. if (!$state.is('event.tickets')) {
  670. return;
  671. }
  672. if (!$scope.event.tickets) {
  673. $scope.event.tickets = [];
  674. }
  675. var ticket_idx = $scope.event.tickets.findIndex(function(el, idx, array) {
  676. return ticket._id == el._id;
  677. });
  678. if (ticket_idx == -1) {
  679. $log.warn('ticket not present: not updated');
  680. return false;
  681. }
  682. $scope.event.tickets.splice(ticket_idx, 1, ticket);
  683. };
  684. $scope._localRemoveTicket = function(ticket) {
  685. if (!(ticket && ticket._id && $scope.event.tickets)) {
  686. return;
  687. }
  688. var ticket_idx = $scope.event.tickets.findIndex(function(el, idx, array) {
  689. return ticket._id == el._id;
  690. });
  691. if (ticket_idx == -1) {
  692. $log.warn('unable to find and delete ticket _id ' + ticket._id);
  693. return;
  694. }
  695. var removed_person = $scope.event.tickets.splice(ticket_idx, 1);
  696. // to be used to populate allPersons, if needed.
  697. var person = null;
  698. if (removed_person.length) {
  699. person = removed_person[0];
  700. } else {
  701. return;
  702. }
  703. if (!$scope.allPersons) {
  704. $scope.allPersons = [];
  705. }
  706. var all_person_idx = $scope.allPersons.findIndex(function(el, idx, array) {
  707. return person._id == el._id;
  708. });
  709. if (all_person_idx == -1 && person._id) {
  710. $scope.allPersons.push(person);
  711. }
  712. };
  713. $scope.buildTicketLabel = function(ticket) {
  714. var name = ticket.name || '';
  715. if (ticket.surname) {
  716. if (name) {
  717. name = name + ' ';
  718. }
  719. name = name + ticket.surname;
  720. }
  721. if (!name && ticket.email) {
  722. name = ticket.email;
  723. }
  724. if (!name) {
  725. name = 'ticket';
  726. }
  727. return name;
  728. };
  729. $scope.setTicketAttribute = function(ticket, key, value, callback, hideMessage) {
  730. $log.debug('setTicketAttribute for _id ' + ticket._id + ' key: ' + key + ' value: ' + value);
  731. var newData = {event_id: $state.params.id, _id: ticket._id};
  732. newData[key] = value;
  733. EventTicket.update(newData, function(data) {
  734. if (!(data && data._id && data.ticket)) {
  735. return;
  736. }
  737. if (callback) {
  738. callback(data);
  739. }
  740. if (!$state.is('event.tickets')) {
  741. return;
  742. }
  743. var ticket_idx = $scope.event.tickets.findIndex(function(el, idx, array) {
  744. return data._id == el._id;
  745. });
  746. if (ticket_idx == -1) {
  747. $log.warn('unable to find ticket _id ' + data._id);
  748. return;
  749. }
  750. if ($scope.event.tickets[ticket_idx] != data.ticket) {
  751. $scope.event.tickets.splice(ticket_idx, 1, data.ticket);
  752. }
  753. if (key === 'attended' && !hideMessage) {
  754. $scope.showAttendedMessage(data.ticket, value);
  755. }
  756. });
  757. };
  758. $scope.showAttendedMessage = function(ticket, attends) {
  759. var msg = {};
  760. var msg_type = 'success';
  761. var name = $scope.buildTicketLabel(ticket);
  762. if (attends) {
  763. msg.message = name + ' successfully added to event ' + $scope.event.title;
  764. } else {
  765. msg.message = name + ' successfully removed from event ' + $scope.event.title;
  766. msg_type = 'warning';
  767. }
  768. toaster.pop({type: msg_type, title: msg.message});
  769. };
  770. $scope.setTicketAttributeAndRefocus = function(ticket, key, value) {
  771. $scope.setTicketAttribute(ticket, key, value);
  772. $scope.query = '';
  773. };
  774. $scope._setAttended = function(ticket) {
  775. $scope.setTicketAttribute(ticket, 'attended', true, null, true);
  776. };
  777. $scope.deleteTicket = function(ticket) {
  778. EventTicket.delete({
  779. event_id: $state.params.id,
  780. ticket_id: ticket._id
  781. }, function() {
  782. $scope._localRemoveTicket(ticket);
  783. var msg = $scope.buildTicketLabel(ticket);
  784. msg += ' successfully removed from event ' + $scope.event.title;
  785. toaster.pop({type: 'error', title: msg});
  786. });
  787. };
  788. $scope.addTicket = function(ticket, cb) {
  789. ticket.event_id = $state.params.id;
  790. if ($scope.modalInstance && $scope.modalInstance.opened) {
  791. $scope.modalInstance.close();
  792. }
  793. EventTicket.add(ticket, function(ret_ticket) {
  794. $log.debug('addTicket');
  795. $log.debug(ret_ticket);
  796. $scope.$emit('event:ticket:new', ret_ticket, function() {
  797. $scope.$emit('event:ticket:set-attr', ret_ticket, 'attended', true, null, true);
  798. });
  799. if (cb) {
  800. cb(ticket);
  801. }
  802. if (!$state.is('event.tickets')) {
  803. $state.go('event.ticket.edit', {id: $scope.event._id, ticket_id: ret_ticket._id});
  804. } else {
  805. $scope.query = '';
  806. if ($scope.modalInstance) {
  807. // Close the Quick ticket modal.
  808. $scope.modalInstance.dismiss('no reason');
  809. }
  810. var msg = $scope.buildTicketLabel(ret_ticket);
  811. msg += ' successfully added to event ' + $scope.event.title;
  812. toaster.pop({type: 'success', title: msg});
  813. }
  814. });
  815. };
  816. $scope.updateTicket = function(ticket, cb) {
  817. ticket.event_id = $state.params.id;
  818. EventTicket.update(ticket, function(t) {
  819. $scope.$emit('event:ticket:update', t.ticket);
  820. if (cb) {
  821. cb(t);
  822. }
  823. });
  824. };
  825. $scope.toggleCancelledTicket = function() {
  826. if (!$scope.ticket._id) {
  827. return;
  828. }
  829. $scope.ticket.cancelled = !$scope.ticket.cancelled;
  830. $scope.setTicketAttribute($scope.ticket, 'cancelled', $scope.ticket.cancelled, function() {
  831. $scope.guiOptions.dangerousActionsEnabled = false;
  832. });
  833. };
  834. $scope.openQuickAddTicket = function(_id) {
  835. $scope.modalInstance = $uibModal.open({
  836. templateUrl: 'modal-quick-add-ticket.html',
  837. scope: $scope
  838. });
  839. };
  840. $scope.submitForm = function(dataModelSubmitted) {
  841. $scope.ticket = {_id: $scope.ticket._id};
  842. angular.forEach(dataModelSubmitted, function(value, key) {
  843. key = $scope.formFieldsMap[key] || key;
  844. $scope.ticket[key] = value;
  845. });
  846. if ($state.is('event.ticket.edit')) {
  847. $scope.updateTicket($scope.ticket, function() {
  848. toaster.pop({type: 'info', title: 'ticket successfully updated'});
  849. });
  850. } else {
  851. $scope.addTicket($scope.ticket);
  852. }
  853. };
  854. $scope.cancelForm = function() {
  855. if (!$state.is('event.tickets')) {
  856. $state.go('events');
  857. } else if ($scope.modalInstance) {
  858. $scope.modalInstance.dismiss('no reason');
  859. }
  860. };
  861. $scope.extractFormFields = function(formlyFieldsModel) {
  862. if (!formlyFieldsModel) {
  863. return;
  864. }
  865. angular.forEach(formlyFieldsModel, function(row, idx) {
  866. if (!row.className == 'row') {
  867. return;
  868. }
  869. angular.forEach(row.fieldGroup || [], function(item, idx) {
  870. if (!(item.key && item.templateOptions && item.templateOptions.label)) {
  871. return;
  872. }
  873. var value = item.templateOptions.label.toLowerCase();
  874. $scope.formFieldsMap[item.key] = value;
  875. $scope.formFieldsMapRev[value] = item.key;
  876. });
  877. });
  878. };
  879. $scope.updateOrded = function(key) {
  880. var new_order = [key];
  881. var inv_key;
  882. if (key && key[0] === '-') {
  883. inv_key = key.substring(1);
  884. } else {
  885. inv_key = '-' + key;
  886. }
  887. angular.forEach($scope.ticketsOrder,
  888. function(value, idx) {
  889. if (value !== key && value !== inv_key) {
  890. new_order.push(value);
  891. }
  892. }
  893. );
  894. $scope.ticketsOrder = new_order;
  895. $scope.filterTickets();
  896. };
  897. $scope.updateCSV = function() {
  898. if (!$scope.filteredTickets.length) {
  899. return;
  900. }
  901. try {
  902. var csv = json2csv({data: $scope.filteredTickets});
  903. var blob = new Blob([csv], {type: 'text/csv'});
  904. $scope.downloadURL = (window.URL || window.webkitURL).createObjectURL(blob);
  905. } catch(err) {}
  906. };
  907. $scope.resetInput = function() {
  908. $scope.query = "";
  909. };
  910. $scope.$on('$destroy', function() {
  911. $scope.EventUpdates && $scope.EventUpdates.close();
  912. });
  913. }]
  914. );
  915. eventManControllers.controller('UsersCtrl', ['$scope', '$rootScope', '$state', '$log', 'User', '$uibModal', '$filter',
  916. function ($scope, $rootScope, $state, $log, User, $uibModal, $filter) {
  917. $scope.loginData = {};
  918. $scope.user = {};
  919. $scope.user.tickets = [];
  920. $scope.updateUserInfo = {};
  921. $scope.users = [];
  922. $scope.usersOrderProp = 'username';
  923. $scope.query = "";
  924. $scope.currentPage = 1;
  925. $scope.itemsPerPage = 10;
  926. $scope.filteredLength = 0;
  927. $scope.maxPaginationSize = 10;
  928. $scope.shownItems = [];
  929. $scope.userQuery = "";
  930. $scope.userCurrentPage = 1;
  931. $scope.userItemsPerPage = 10;
  932. $scope.userFilteredLength = 0;
  933. $scope.userMaxPaginationSize = 10;
  934. $scope.userShownItems = [];
  935. $scope.filterUsers = function() {
  936. var users = $scope.users || [];
  937. users = $filter('splittedFilter')(users, $scope.query);
  938. users = $filter('orderBy')(users, $scope.usersOrderProp);
  939. $scope.filteredUsers = angular.copy(users);
  940. $scope.filteredUsersLength = $scope.filteredUsers.length;
  941. users = $filter('pagination')(users, $scope.currentPage, $scope.itemsPerPage);
  942. $scope.shownItems = users;
  943. };
  944. $scope.$watch('query', function() {
  945. if (!$scope.query) {
  946. $scope.currentPage = 1;
  947. }
  948. $scope.filterUsers();
  949. });
  950. $scope.$watch('currentPage + itemsPerPage', function() {
  951. $scope.filterUsers();
  952. });
  953. $scope.$watch('usersOrderProp', function() {
  954. $scope.filterUsers();
  955. });
  956. $scope.userFilterTickets = function() {
  957. var tickets = $scope.user.tickets || [];
  958. tickets = $filter('splittedFilter')(tickets, $scope.userQuery);
  959. $scope.userFilteredTickets = angular.copy(tickets);
  960. $scope.userFilteredLength = $scope.userFilteredTickets.length;
  961. tickets = $filter('pagination')(tickets, $scope.userCurrentPage, $scope.userItemsPerPage);
  962. $scope.userShownItems = tickets;
  963. };
  964. $scope.$watch('userQuery', function() {
  965. if (!$scope.userQuery) {
  966. $scope.userCurrentPage = 1;
  967. }
  968. $scope.userFilterTickets();
  969. });
  970. $scope.$watch('userCurrentPage + userItemsPerPage', function() {
  971. $scope.userFilterTickets();
  972. });
  973. $scope.confirm_delete = 'Do you really want to delete this user?';
  974. $rootScope.$on('$translateChangeSuccess', function () {
  975. $translate('Do you really want to delete this user?').then(function (translation) {
  976. $scope.confirm_delete = translation;
  977. });
  978. });
  979. $scope.updateUsersList = function() {
  980. if ($state.is('users')) {
  981. $scope.users = User.all(function() {
  982. $scope.filterUsers();
  983. });
  984. }
  985. };
  986. $scope.updateUsersList();
  987. if ($state.is('user.edit') && $state.params.id) {
  988. $scope.user = User.get({id: $state.params.id}, function() {
  989. $scope.updateUserInfo = $scope.user;
  990. $scope.updateUserInfo.isAdmin = $rootScope.hasPermission('admin|all', $scope.updateUserInfo);
  991. $scope.userFilterTickets();
  992. });
  993. }
  994. $scope.updateUser = function() {
  995. User.update($scope.updateUserInfo);
  996. };
  997. $scope.deleteUser = function(user_id) {
  998. var modalInstance = $uibModal.open({
  999. scope: $scope,
  1000. templateUrl: 'modal-confirm-action.html',
  1001. controller: 'ModalConfirmInstanceCtrl',
  1002. resolve: {
  1003. message: function() { return $scope.confirm_delete; }
  1004. }
  1005. });
  1006. modalInstance.result.then(function() {
  1007. User.delete({id: user_id}, $scope.updateUsersList);
  1008. });
  1009. };
  1010. $scope.register = function() {
  1011. User.add($scope.newUser, function(data) {
  1012. $scope.login($scope.newUser);
  1013. });
  1014. };
  1015. $scope.login = function(loginData) {
  1016. if (!loginData) {
  1017. loginData = $scope.loginData;
  1018. }
  1019. User.login(loginData, function(data) {
  1020. if (!data.error) {
  1021. $rootScope.readInfo(function(info) {
  1022. $log.debug('logged in user: ' + $scope.info.user.username);
  1023. $rootScope.clearError();
  1024. $state.go('events');
  1025. });
  1026. }
  1027. });
  1028. };
  1029. $scope.logout = function() {
  1030. User.logout({}, function(data) {
  1031. if (!data.error) {
  1032. $rootScope.readInfo(function() {
  1033. $log.debug('logged out user');
  1034. $state.go('login');
  1035. });
  1036. }
  1037. });
  1038. };
  1039. }]
  1040. );
  1041. eventManControllers.controller('FileUploadCtrl', ['$scope', '$log', '$upload', 'EbAPI', 'Event', 'toaster',
  1042. function ($scope, $log, $upload, EbAPI, Event, toaster) {
  1043. $scope.file = null;
  1044. $scope.progress = 0;
  1045. $scope.progressbarType = 'warning';
  1046. $scope.deduplicate = false;
  1047. $scope.targetEvent = null;
  1048. $scope.createNewEvent = true;
  1049. $scope.ebAPIkey = '';
  1050. $scope.ebEventID = '';
  1051. $scope.reply = {};
  1052. $scope.events = Event.all();
  1053. $scope.importRunning = false;
  1054. $scope.apiImport = function() {
  1055. if (!($scope.ebAPIkey && $scope.ebEventID)) {
  1056. $log.warn('missing Eventbrite API key or Event ID');
  1057. return;
  1058. }
  1059. $scope.importRunning = true;
  1060. var watingToaster = toaster.pop({type: 'wait', title: 'importing tickets',
  1061. body: 'this may take a while...',
  1062. timeout: 0, showCloseButton: false,
  1063. tapToDismiss: false});
  1064. EbAPI.apiImport({
  1065. create: $scope.createNewEvent,
  1066. eventID: $scope.ebEventID,
  1067. targetEvent: $scope.targetEvent,
  1068. oauthToken: $scope.ebAPIkey
  1069. }, function(data) {
  1070. toaster.clear(watingToaster);
  1071. toaster.pop({type: 'info', title: 'tickets imported!',
  1072. body: 'total: ' + data.total + ' errors: ' + (data.total - data.valid)})
  1073. $scope.importRunning = false;
  1074. }, function(data) {
  1075. toaster.clear(watingToaster);
  1076. $scope.importRunning = false;
  1077. });
  1078. };
  1079. $scope.upload = function(file, url) {
  1080. $log.debug("FileUploadCtrl.upload");
  1081. $scope.progress = 0;
  1082. $scope.progressbarType = 'warning';
  1083. $upload.upload({
  1084. url: url,
  1085. file: file,
  1086. fields: {targetEvent: $scope.targetEvent, deduplicate: $scope.deduplicate}
  1087. }).progress(function(evt) {
  1088. $scope.progress = parseInt(100.0 * evt.loaded / evt.total);
  1089. $log.debug('progress: ' + $scope.progress + '%');
  1090. }).success(function(data, status, headers, config) {
  1091. $scope.file = null;
  1092. $scope.progress = 100;
  1093. $scope.progressbarType = 'success';
  1094. $scope.reply = angular.fromJson(data);
  1095. });
  1096. };
  1097. }]
  1098. );