├── .arcconfig ├── .buildpacks ├── .dockerignore ├── .editorconfig ├── .github ├── ISSUE_TEMPLATE.md ├── PULL_REQUEST_TEMPLATE.md └── workflows │ └── test-and-ship.yml ├── .gitignore ├── .travis.yml ├── Dockerfile ├── LICENSE-AGPL ├── LICENSE.md ├── Procfile ├── README.md ├── api ├── .eslintrc ├── .gitignore ├── .prettierignore ├── babel.config.json ├── jest.config.js ├── package-lock.json ├── package.json ├── src │ ├── config │ │ ├── configEndpoint.js │ │ └── settings.js │ └── ushahidi-api.js └── webpack.config.js ├── app ├── config.js.j2 ├── config.json └── config.json.j2 ├── buildargs.env.encrypted ├── codeship-services.yml ├── codeship-steps.yml ├── deployment.env.encrypted ├── docker.env.encrypted ├── docker ├── build.Dockerfile ├── build.run.sh ├── nginx.default.conf ├── nginx.run.sh ├── release.Dockerfile ├── release.run.sh ├── test.Dockerfile └── test.run.sh ├── legacy ├── .arclint ├── .babelrc ├── .eslintignore ├── .eslintrc ├── .gitignore ├── app.json ├── app │ ├── .well-known │ │ ├── apple-app-site-association │ │ └── assetlinks.json │ ├── activity │ │ ├── activity-module.js │ │ ├── activity-routes.js │ │ ├── activity-timeline.directive.js │ │ ├── activity-timeline.html │ │ ├── activity.controller.js │ │ ├── activity.html │ │ ├── bar-chart.directive.js │ │ ├── bar-chart.html │ │ ├── crowdsourced-survey-table.directive.js │ │ ├── crowdsourced-survey-table.html │ │ ├── targeted-survey-table.directive.js │ │ ├── targeted-survey-table.html │ │ ├── time-chart.directive.js │ │ └── time-chart.html │ ├── app.js │ ├── auth │ │ ├── 404.controller.js │ │ ├── 404.html │ │ ├── auth-module.js │ │ ├── auth-routes.js │ │ ├── authentication-events.run.js │ │ ├── authentication-interceptor.config.js │ │ ├── authentication.service.js │ │ ├── forbidden.controller.js │ │ ├── forbidden.html │ │ ├── login.controller.js │ │ ├── login.directive.js │ │ ├── login.html │ │ ├── password-reset-confirm.controller.js │ │ ├── password-reset-confirm.directive.js │ │ ├── password-reset-confirm.html │ │ ├── password-reset.controller.js │ │ ├── password-reset.directive.js │ │ ├── password-reset.html │ │ ├── password-reset.service.js │ │ ├── register.controller.js │ │ ├── register.directive.js │ │ ├── register.html │ │ ├── registration.service.js │ │ ├── services │ │ │ └── terms-of-service-endpoint.js │ │ ├── session.service.js │ │ ├── tos.directive.js │ │ ├── tos.html │ │ └── tos.service.js │ ├── bootstrap.js │ ├── common │ │ ├── common-module.js │ │ ├── common-routes.js │ │ ├── configs │ │ │ ├── cache-config.js │ │ │ ├── loading.interceptor-config.js │ │ │ ├── locale-config.js │ │ │ ├── ui-bootstrap-template-decorators.js │ │ │ └── uib-pagination.html │ │ ├── controllers │ │ │ ├── intercom.js │ │ │ └── navigation.js │ │ ├── directives │ │ │ ├── adaptive-input.js │ │ │ ├── add-language.directive.js │ │ │ ├── add-language.html │ │ │ ├── custom-on-change.js │ │ │ ├── dropdown.js │ │ │ ├── embed-only.directive.js │ │ │ ├── file-upload.directive.js │ │ │ ├── file-upload.html │ │ │ ├── first-time-config.html │ │ │ ├── first-time-config.js │ │ │ ├── focus.js │ │ │ ├── language-switch.directive.js │ │ │ ├── language-switch.html │ │ │ ├── layout-class.directive.js │ │ │ ├── list-toolbar.html │ │ │ ├── list-toolbar.js │ │ │ ├── loading-dots-button.directive.js │ │ │ ├── loading-dots-button.html │ │ │ ├── mainsheet-container.directive.js │ │ │ ├── mainsheet-container.html │ │ │ ├── modal-body.directive.js │ │ │ ├── modal-container.directive.js │ │ │ ├── modal-container.html │ │ │ ├── modal.html │ │ │ ├── modal.js │ │ │ ├── role-selector.directive.js │ │ │ ├── role-selector.html │ │ │ ├── translations-switch.directive.js │ │ │ └── translations-switch.html │ │ ├── donation │ │ │ ├── donation-button.directive.js │ │ │ ├── donation-button.html │ │ │ ├── donation-modal.directive.js │ │ │ ├── donation-modal.html │ │ │ ├── donation-module.js │ │ │ ├── donation-toolbar.directive.js │ │ │ ├── donation-toolbar.html │ │ │ ├── donation.directive.js │ │ │ ├── donation.html │ │ │ └── donation.service.js │ │ ├── factories │ │ │ └── loading.interceptor-factory.js │ │ ├── global │ │ │ ├── event-handlers.js │ │ │ ├── language-list.json │ │ │ └── language-settings.js │ │ ├── locales │ │ │ ├── ar.json │ │ │ ├── bg-BG.json │ │ │ ├── cs.json │ │ │ ├── de.json │ │ │ ├── en.json │ │ │ ├── es.json │ │ │ ├── fa-IR.json │ │ │ ├── fr-FR.json │ │ │ ├── fr.json │ │ │ ├── hr.json │ │ │ ├── ht.json │ │ │ ├── hu.json │ │ │ ├── hy.json │ │ │ ├── id.json │ │ │ ├── it.json │ │ │ ├── ja.json │ │ │ ├── languages.json │ │ │ ├── nl.json │ │ │ ├── pt-BR.json │ │ │ ├── ru.json │ │ │ ├── sq-AL.json │ │ │ ├── sw.json │ │ │ ├── vi-VN.json │ │ │ ├── vi.json │ │ │ ├── zh-TW.json │ │ │ └── zh.json │ │ ├── notifications │ │ │ ├── api-errors.html │ │ │ ├── limit.html │ │ │ ├── notify.service.js │ │ │ ├── slider.directive.js │ │ │ ├── slider.html │ │ │ └── slider.service.js │ │ ├── raven │ │ │ ├── raven.js │ │ │ └── raven.service.js │ │ ├── services │ │ │ ├── collections.service.js │ │ │ ├── data-export.service.js │ │ │ ├── data-import.service.js │ │ │ ├── endpoints │ │ │ │ ├── MediaEndpoint.js │ │ │ │ ├── collection.js │ │ │ │ ├── config.js │ │ │ │ ├── contact.js │ │ │ │ ├── data-import.js │ │ │ │ ├── export-jobs.js │ │ │ │ ├── form-attributes.js │ │ │ │ ├── form-stats-endpoint.js │ │ │ │ ├── form.js │ │ │ │ ├── hxl-tag-endpoint.js │ │ │ │ ├── notification.js │ │ │ │ ├── post-endpoint.js │ │ │ │ ├── post-lock-endpoint.js │ │ │ │ ├── role.js │ │ │ │ ├── savedsearch.js │ │ │ │ ├── sdk │ │ │ │ │ ├── CategoriesSdk.js │ │ │ │ │ ├── PostsSdk.js │ │ │ │ │ ├── SurveysSdk.js │ │ │ │ │ └── UtilsSdk.js │ │ │ │ ├── tag.js │ │ │ │ └── user-endpoint.js │ │ │ ├── features.js │ │ │ ├── geocoding.js │ │ │ ├── import-complete.html │ │ │ ├── import.notify.service.js │ │ │ ├── languages.js │ │ │ ├── loadingProgress.service.js │ │ │ ├── mainsheet.service.js │ │ │ ├── maps.js │ │ │ ├── modal.service.js │ │ │ ├── post-filters.service.js │ │ │ ├── post-lock.service.js │ │ │ ├── post-survey.service.js │ │ │ ├── translation.service.js │ │ │ └── util.js │ │ ├── user-profile │ │ │ ├── account-settings.directive.js │ │ │ ├── account_settings.html │ │ │ ├── admin-user-setup.directive.js │ │ │ ├── admin-user-setup.html │ │ │ ├── notifications.directive.js │ │ │ ├── notifications.html │ │ │ ├── user-profile-module.js │ │ │ ├── user-profile.directive.js │ │ │ └── user-profile.html │ │ └── verifier │ │ │ ├── verifier.controller.js │ │ │ ├── verifier.html │ │ │ ├── verifier.js │ │ │ └── verifier.service.js │ ├── data │ │ ├── add-post-text-button.directive.js │ │ ├── add-post-text-button.html │ │ ├── collection-toggle │ │ │ ├── collection-toggle-button.html │ │ │ └── collection-toggle-button.js │ │ ├── common │ │ │ ├── post-edit-create │ │ │ │ ├── location.directive.js │ │ │ │ ├── location.html │ │ │ │ ├── media-edit.service.js │ │ │ │ ├── media.html │ │ │ │ ├── post-category-editor.html │ │ │ │ ├── post-category-editor.js │ │ │ │ ├── post-datetime-value.directive.js │ │ │ │ ├── post-datetime-value.html │ │ │ │ ├── post-edit.controller.js │ │ │ │ ├── post-edit.service.js │ │ │ │ ├── post-media.directive.js │ │ │ │ ├── post-relation.directive.js │ │ │ │ ├── post-tabs.directive.js │ │ │ │ ├── post-tabs.html │ │ │ │ ├── post-value-edit.directive.js │ │ │ │ ├── post-value-edit.html │ │ │ │ ├── post-video.directive.js │ │ │ │ ├── relation.html │ │ │ │ └── video.html │ │ │ ├── post-edit-detail-create │ │ │ │ ├── post-entity.service.js │ │ │ │ ├── survey-language-selector.directive.js │ │ │ │ └── survey-language-selector.html │ │ │ └── post-edit-detail │ │ │ │ ├── post-messages-reply.html │ │ │ │ ├── post-messages.directive.js │ │ │ │ └── post-messages.html │ │ ├── data-module.js │ │ ├── data-routes.js │ │ ├── post-create │ │ │ ├── main.html │ │ │ ├── post-create.controller.js │ │ │ ├── post-editor.directive.js │ │ │ └── post-editor.html │ │ ├── post-detail │ │ │ ├── add-form.html │ │ │ ├── map.directive.js │ │ │ ├── map.html │ │ │ ├── post-add-form.directive.js │ │ │ ├── post-category-value.directive.js │ │ │ ├── post-category-value.html │ │ │ ├── post-detail-data.directive.js │ │ │ ├── post-detail-data.html │ │ │ ├── post-lock.directive.js │ │ │ ├── post-lock.html │ │ │ ├── post-media-value.directive.js │ │ │ ├── post-media-value.html │ │ │ ├── post-value.directive.js │ │ │ ├── post-value.html │ │ │ ├── post-video-value.directive.js │ │ │ └── post-video-value.html │ │ ├── post-edit │ │ │ ├── post-data-editor.directive.js │ │ │ ├── post-data-editor.html │ │ │ ├── post-toolbox.directive.js │ │ │ ├── post-toolbox.html │ │ │ ├── post-translation-editor.directive.js │ │ │ └── post-translation-editor.html │ │ ├── post-view-data.directive.js │ │ ├── post-view-data.html │ │ ├── post-view.service.js │ │ └── services │ │ │ └── message.js │ ├── gtm-userprops.js │ ├── index.html │ ├── map │ │ ├── collections │ │ │ ├── editor.directive.js │ │ │ ├── editor.html │ │ │ ├── listing.directive.js │ │ │ ├── listing.html │ │ │ ├── mode-context.directive.js │ │ │ └── mode-context.html │ │ ├── directives │ │ │ └── overflow-toggle.js │ │ ├── map-module.js │ │ ├── map-routes.js │ │ ├── mode-context │ │ │ ├── filter-by-datasource.directive.js │ │ │ ├── filter-by-datasource.html │ │ │ ├── filter-by-survey-dropdown.directive.js │ │ │ ├── mode-context-form-filter.directive.js │ │ │ ├── mode-context-form-filter.html │ │ │ ├── mode-context.directive.js │ │ │ └── mode-context.html │ │ ├── post-card │ │ │ ├── card.html │ │ │ ├── collection-toggle │ │ │ │ ├── collection-toggle-link.html │ │ │ │ └── collection-toggle-link.js │ │ │ ├── post-actions.directive.js │ │ │ ├── post-actions.html │ │ │ ├── post-actions.service.js │ │ │ ├── post-card.directive.js │ │ │ ├── post-metadata.directive.js │ │ │ ├── post-metadata.html │ │ │ ├── post-metadata.service.js │ │ │ ├── post-preview-media.directive.js │ │ │ └── post-preview-media.html │ │ ├── post-toolbar │ │ │ ├── add-post │ │ │ │ ├── add-post-button.directive.js │ │ │ │ ├── add-post-button.html │ │ │ │ ├── add-post-survey-list.directive.js │ │ │ │ └── add-post-survey-list.html │ │ │ ├── filter-posts.directive.js │ │ │ ├── filter-posts.html │ │ │ ├── filters │ │ │ │ ├── active-search-filters.directive.js │ │ │ │ ├── active-search-filters.html │ │ │ │ ├── filter-category.directive.js │ │ │ │ ├── filter-category.html │ │ │ │ ├── filter-date.directive.js │ │ │ │ ├── filter-date.html │ │ │ │ ├── filter-form.directive.js │ │ │ │ ├── filter-form.html │ │ │ │ ├── filter-has-location.directive.js │ │ │ │ ├── filter-has-location.html │ │ │ │ ├── filter-location.directive.js │ │ │ │ ├── filter-location.html │ │ │ │ ├── filter-post-order-asc-desc.directive.js │ │ │ │ ├── filter-post-order-asc-desc.html │ │ │ │ ├── filter-post-sorting-options.directive.js │ │ │ │ ├── filter-post-sorting-options.html │ │ │ │ ├── filter-saved-search.directive.js │ │ │ │ ├── filter-saved-search.html │ │ │ │ ├── filter-source.directive.js │ │ │ │ ├── filter-source.html │ │ │ │ ├── filter-status.directive.js │ │ │ │ ├── filter-status.html │ │ │ │ ├── filter-transformers.service.js │ │ │ │ ├── filter-unlocked-on-top.directive.js │ │ │ │ ├── filter-unlocked-on-top.html │ │ │ │ ├── filter-visible-to.directive.js │ │ │ │ ├── filter-visible-to.html │ │ │ │ ├── filters-dropdown.directive.js │ │ │ │ └── filters-dropdown.html │ │ │ ├── post-toolbar.directive.js │ │ │ ├── post-toolbar.html │ │ │ ├── share │ │ │ │ ├── post-export.directive.js │ │ │ │ ├── post-export.html │ │ │ │ ├── post-share.directive.js │ │ │ │ ├── post-share.html │ │ │ │ ├── share-menu-modal.directive.js │ │ │ │ ├── share-menu-modal.html │ │ │ │ ├── share-menu.directive.js │ │ │ │ └── share-menu.html │ │ │ ├── sort-and-filter-counter.directive.js │ │ │ └── sort-and-filter-counter.html │ │ ├── post-view-map.directive.js │ │ ├── post-view-map.html │ │ ├── post-view-noui.controller.js │ │ ├── post-view-noui.html │ │ ├── savedsearches │ │ │ ├── editor-directive.js │ │ │ ├── mode-context.directive.js │ │ │ ├── mode-context.html │ │ │ └── savedsearch-editor.html │ │ └── services │ │ │ └── view-helper.js │ ├── mock-backend-config.js │ ├── mode-bar │ │ ├── mode-bar.directive.js │ │ ├── mode-bar.html │ │ ├── mode-bar.module.js │ │ ├── support-links.html │ │ ├── ush-logo.directive.js │ │ ├── ush-logo.html │ │ └── ushahidi-logo.html │ ├── settings │ │ ├── categories │ │ │ ├── categories-edit.html │ │ │ ├── categories.controller.js │ │ │ ├── categories.html │ │ │ ├── category-translation-editor.directive.js │ │ │ ├── category-translation-editor.html │ │ │ └── edit.controller.js │ │ ├── data-export │ │ │ ├── data-export.controller.js │ │ │ ├── data-export.html │ │ │ ├── hdx-details.directive.js │ │ │ ├── hdx-details.html │ │ │ ├── hdx-export.controller.js │ │ │ └── hdx-export.html │ │ ├── data-import │ │ │ ├── after-import.html │ │ │ ├── data-after-import.controller.js │ │ │ ├── data-after-import.directive.js │ │ │ ├── data-import.controller.js │ │ │ ├── data-import.directive.js │ │ │ └── data-import.html │ │ ├── datasources │ │ │ ├── datasources.controller.js │ │ │ ├── datasources.html │ │ │ ├── gmail-auth.directive.js │ │ │ └── gmail-auth.html │ │ ├── directives │ │ │ ├── category-selector.directive.js │ │ │ ├── category-selector.html │ │ │ ├── color-picker.html │ │ │ ├── color-picker.js │ │ │ ├── filter-system │ │ │ │ ├── filter-role.html │ │ │ │ ├── filter-role.js │ │ │ │ ├── filter-searchbar.html │ │ │ │ └── filter-searchbar.js │ │ │ ├── loading-dots.directive.js │ │ │ └── loading-dots.html │ │ ├── donation │ │ │ ├── donation.controller.js │ │ │ ├── donation.directive.js │ │ │ └── donation.html │ │ ├── roles │ │ │ ├── editor.directive.js │ │ │ ├── roles-edit.html │ │ │ ├── roles.controller.js │ │ │ ├── roles.directive.js │ │ │ └── roles.html │ │ ├── services │ │ │ ├── accessibility.service.js │ │ │ ├── endpoints │ │ │ │ ├── apikey.js │ │ │ │ ├── country-code-endpoint.js │ │ │ │ ├── data-providers.js │ │ │ │ ├── form-contact.js │ │ │ │ ├── form-roles.js │ │ │ │ ├── form-stages.js │ │ │ │ ├── hxl-license-endpoint.js │ │ │ │ ├── hxl-metadata-endpoint.js │ │ │ │ ├── hxl-organisations-endpoint.js │ │ │ │ ├── permission.js │ │ │ │ ├── user-settings.js │ │ │ │ └── webhooks.js │ │ │ └── hxl-export.service.js │ │ ├── settings-list.controller.js │ │ ├── settings-list.html │ │ ├── settings-list.routes.js │ │ ├── settings.controller.js │ │ ├── settings.html │ │ ├── settings.module.js │ │ ├── settings.routes.js │ │ ├── site │ │ │ ├── editor.directive.js │ │ │ ├── map.directive.js │ │ │ ├── map.html │ │ │ ├── settings-editor.html │ │ │ ├── settings-general.html │ │ │ └── site.controller.js │ │ ├── surveys │ │ │ ├── attribute-create.directive.js │ │ │ ├── attribute-create.html │ │ │ ├── attribute-editor.directive.js │ │ │ ├── attribute-editor.html │ │ │ ├── edit.controller.js │ │ │ ├── field-translation-editor.directive.js │ │ │ ├── field-translation-editor.html │ │ │ ├── survey-edit.html │ │ │ ├── survey-editor.directive.js │ │ │ ├── survey-editor.html │ │ │ ├── survey-success.html │ │ │ ├── survey-translation-editor.directive.js │ │ │ ├── survey-translation-editor.html │ │ │ ├── survey.notify.service.js │ │ │ ├── surveys.controller.js │ │ │ ├── surveys.html │ │ │ ├── targeted-surveys │ │ │ │ ├── targeted-edit.controller.js │ │ │ │ ├── targeted-question-modal.html │ │ │ │ ├── targeted-question.directive.js │ │ │ │ └── targeted-survey-edit.html │ │ │ ├── task-create.directive.js │ │ │ └── task-create.html │ │ ├── user-settings │ │ │ ├── user-settings.controller.js │ │ │ └── user-settings.html │ │ ├── users │ │ │ ├── create.controller.js │ │ │ ├── edit.controller.js │ │ │ ├── filter-users.directive.js │ │ │ ├── filter-users.html │ │ │ ├── users-edit.html │ │ │ ├── users.controller.js │ │ │ └── users.html │ │ └── webhooks │ │ │ ├── editor.directive.js │ │ │ ├── webhooks-edit.html │ │ │ ├── webhooks.controller.js │ │ │ ├── webhooks.directive.js │ │ │ └── webhooks.html │ └── test-bootstrap.js ├── gulp │ ├── transifex-download.js │ └── verifier.js ├── gulpfile.babel.js ├── mocked_backend │ └── api │ │ └── v3 │ │ ├── attributes.json │ │ ├── collections.json │ │ ├── config.json │ │ ├── config │ │ ├── features.json │ │ ├── map.json │ │ └── site.json │ │ ├── forms.json │ │ ├── forms │ │ ├── 1.json │ │ └── 3.json │ │ ├── posts.json │ │ ├── posts │ │ ├── 120.json │ │ └── 999.json │ │ ├── roles.json │ │ ├── sets.json │ │ ├── stages.json │ │ ├── stages │ │ └── 4.json │ │ ├── tags.json │ │ ├── tasks.json │ │ ├── users.json │ │ └── users │ │ └── me.json ├── package-lock.json ├── package.json ├── sass │ ├── overrides │ │ ├── _dropdown.scss │ │ ├── _filters.scss │ │ ├── _intercom.scss │ │ ├── _leaflet.scss │ │ ├── _modal.scss │ │ └── _tui-markdown.scss │ └── vendor.scss ├── test │ ├── karma.conf.js │ ├── pre_test.sh │ ├── test.sh │ └── unit │ │ ├── common │ │ ├── auth │ │ │ ├── authentication-events.run.spec.js │ │ │ ├── authentication-interceptor.config.spec.js │ │ │ ├── authentication.service.spec.js │ │ │ ├── login.directive.spec.js │ │ │ ├── password-reset-confirm.directive.spec.js │ │ │ ├── password-reset.directive.spec.js │ │ │ ├── session-spec.js │ │ │ └── tos.service.spec.js │ │ ├── controllers │ │ │ └── intercom.js │ │ ├── directives │ │ │ ├── category-selector.directive.spec.js │ │ │ ├── category-selector.parentsEnabled.directive.spec.js │ │ │ ├── embed-only.directive.spec.js │ │ │ ├── file-upload.directive.spec.js │ │ │ ├── language-switch.directive.spec.js │ │ │ ├── layout-class.directive.spec.js │ │ │ └── role-selector.directive.spec.js │ │ ├── global │ │ │ └── event-handlers-spec.js │ │ ├── notifications │ │ │ └── notify.service.spec.js │ │ ├── raven.spec.js │ │ ├── services │ │ │ ├── LoadingProgress.service.spec.js │ │ │ ├── endpoints │ │ │ │ ├── form-attributes.js │ │ │ │ ├── form-stages.js │ │ │ │ ├── form.js │ │ │ │ ├── permission-endpoint-spec.js │ │ │ │ ├── post-endpoint-spec.js │ │ │ │ ├── role-endpoint-spec.js │ │ │ │ ├── tag.js │ │ │ │ └── user-endpoint-spec.js │ │ │ ├── features.js │ │ │ ├── util-spec.js │ │ │ └── view-helper-spec.js │ │ └── user-profile │ │ │ └── directives │ │ │ ├── notifications-directive-spec.js │ │ │ └── user-profile-directive-spec.js │ │ ├── main │ │ ├── activity │ │ │ ├── activity.controller.spec.js │ │ │ ├── bar-chart.directive.spec.js │ │ │ └── time-chart.directive.spec.js │ │ └── post │ │ │ ├── collections │ │ │ └── mode-context.spec.js │ │ │ ├── common │ │ │ ├── post-actions.directive.spec.js │ │ │ ├── post-actions.service.spec.js │ │ │ └── post-metadata.service.spec.js │ │ │ ├── detail │ │ │ ├── post-detail-data.directive.spec.js │ │ │ ├── post-media-value.directive.spec.js │ │ │ ├── post-messages.directive.spec.js │ │ │ └── post-value.directive.spec.js │ │ │ ├── modify │ │ │ ├── location.directive.spec.js │ │ │ ├── media-edit.service.spec.js │ │ │ ├── post-create.controller.spec.js │ │ │ ├── post-edit.controller.spec.js │ │ │ ├── post-edit.service.spec.js │ │ │ ├── post-editor.directive.spec.js │ │ │ ├── post-media.directive.spec.js │ │ │ ├── post-relation.directive.spec.js │ │ │ ├── post-tabs.directive.spec.js │ │ │ ├── post-value-edit.directive.spec.js │ │ │ └── post-video.directive.spec.js │ │ │ ├── savedsearches │ │ │ └── mode-context.spec.js │ │ │ └── views │ │ │ ├── filter-by-datasource.spec.js │ │ │ ├── filters │ │ │ ├── active-search-filters.directive.spec.js │ │ │ ├── filter-category.directive.spec.js │ │ │ ├── filter-post-order-asc-desc.spec.js │ │ │ ├── filter-post-sorting-options.directive.spec.js │ │ │ ├── filter-unlocked-on-top.directive.spec.js │ │ │ ├── filters-dropdown.directive.spec.js │ │ │ ├── filters-posts.directive.spec.js │ │ │ ├── post-filters-add-if-current-matches-original.service.spec.js │ │ │ ├── post-filters-clean-ui-filters.service.spec.js │ │ │ ├── post-filters.service.spec.js │ │ │ └── sort-and-filter-counter.directive.spec.js │ │ │ ├── mode-context-form-filter.directive.spec.js │ │ │ ├── post-card.directive.spec.js │ │ │ ├── post-preview-media.directive.spec.js │ │ │ ├── post-view-data.directive.spec.js │ │ │ ├── post-view-map.directive.spec.js │ │ │ └── share │ │ │ └── post-export.directive.spec.js │ │ ├── make-test-app.js │ │ ├── mock │ │ ├── controllers │ │ │ └── navigation.controller.mock.js │ │ ├── factories │ │ │ └── socket-factory.mock.js │ │ ├── mock-modules.js │ │ └── services │ │ │ ├── accessibility.service.js │ │ │ ├── authentication.js │ │ │ ├── collection.js │ │ │ ├── config.js │ │ │ ├── contact.js │ │ │ ├── country-code-endpoint.js │ │ │ ├── data-export.js │ │ │ ├── data-import.js │ │ │ ├── data-import.service.js │ │ │ ├── data-provider.js │ │ │ ├── data-retriever.js │ │ │ ├── features.js │ │ │ ├── form-attributes.js │ │ │ ├── form-contact.js │ │ │ ├── form-role.js │ │ │ ├── form-stages.js │ │ │ ├── form-stats-endpoint.js │ │ │ ├── form.js │ │ │ ├── global-filters.js │ │ │ ├── hxl-export.js │ │ │ ├── importnotify.js │ │ │ ├── languages.js │ │ │ ├── loadingProgress.service.js │ │ │ ├── maps.js │ │ │ ├── media-edit-service.js │ │ │ ├── media.js │ │ │ ├── message.js │ │ │ ├── modal.service.js │ │ │ ├── notification.js │ │ │ ├── notify.js │ │ │ ├── permission.js │ │ │ ├── post-actions-service.js │ │ │ ├── post-edit-service.js │ │ │ ├── post-filters.js │ │ │ ├── post-lock-endpoint.js │ │ │ ├── post-lock.service.js │ │ │ ├── post-metadata-service.js │ │ │ ├── post-survey-service.js │ │ │ ├── post-view-service.js │ │ │ ├── post.js │ │ │ ├── role.js │ │ │ ├── savedsearch.js │ │ │ ├── sdk │ │ │ ├── CategoriesSdk.js │ │ │ ├── PostsSdk.js │ │ │ ├── SurveysSdk.js │ │ │ └── UtilsSdk.js │ │ │ ├── session.js │ │ │ ├── survey-notify.js │ │ │ ├── tag.js │ │ │ ├── third_party │ │ │ ├── leaflet.js │ │ │ └── transitions.js │ │ │ ├── translate.js │ │ │ ├── translation-service.js │ │ │ ├── user-settings.js │ │ │ └── user.js │ │ ├── settings │ │ ├── categories │ │ │ ├── categories-controller-spec.js │ │ │ └── categories-edit-controller-spec.js │ │ ├── data-export │ │ │ ├── data-export.controller.spec.js │ │ │ └── hdx-export.controller.spec.js │ │ ├── data-import │ │ │ ├── after-data-import.directive.spec.js │ │ │ ├── data-import-controller-spec.js │ │ │ └── setting-data-import-directive-spec.js │ │ ├── datasources │ │ │ └── datasources-controller-spec.js │ │ ├── roles │ │ │ ├── roles-controller-spec.js │ │ │ ├── setting-roles-directive-spec.js │ │ │ └── setting-roles-editor-directive-spec.js │ │ ├── site │ │ │ ├── general-controller-spec.js │ │ │ ├── setting-editor-directive-spec.js │ │ │ └── setting-map-directive-spec.js │ │ ├── surveys │ │ │ ├── settings-survey-editor.directive.spec.js │ │ │ ├── survey-translation-editor.directive.spec.js │ │ │ └── targeted-edit.controller.spec.js │ │ └── users │ │ │ ├── users-controller-spec.js │ │ │ ├── users-create-controller-spec.js │ │ │ └── users-edit-controller-spec.js │ │ └── spec.bundle.js ├── webpack.config.js ├── webpack.dev.config.js ├── webpack.dist.config.js └── webpack.test.config.js ├── package-lock.json ├── package.json ├── root ├── .eslintignore ├── .eslintrc ├── .gitignore ├── .prettierignore ├── babel.config.json ├── package-lock.json ├── package.json ├── src │ ├── config.js │ ├── datalayer.js │ ├── importmap.json │ ├── index.ejs │ ├── loading.scss │ ├── microfrontend-layout.html │ └── ushahidi-root-config.js └── webpack.config.js ├── server ├── nginx-site.conf ├── rewrite.htaccess └── scripts │ ├── generateImportMap.js │ ├── proxy.js │ ├── ready.js │ └── start.js ├── single.stage.Dockerfile └── utilities ├── .eslintrc ├── .gitignore ├── .prettierignore ├── babel.config.json ├── jest.config.js ├── package-lock.json ├── package.json ├── src └── ushahidi-utilities.js └── webpack.config.js /.arcconfig: -------------------------------------------------------------------------------- 1 | { 2 | "phabricator.uri" : "https://phabricator.ushahidi.com/", 3 | "repository.callsign" : "UWEB" 4 | } 5 | -------------------------------------------------------------------------------- /.buildpacks: -------------------------------------------------------------------------------- 1 | https://github.com/heroku/heroku-buildpack-nodejs 2 | https://github.com/rjmackay/heroku-buildpack-gulp 3 | -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | .git 2 | node_modules 3 | Dockerfile 4 | *.Dockerfile 5 | tmp 6 | .out 7 | codeship-* 8 | deployment.env 9 | deployment.env.encrypted 10 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = spaces 6 | indent_size = 4 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ### Expected behaviour 2 | 3 | ### Actual behaviour 4 | 5 | ### Steps to reproduce the behaviour/error 6 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | This pull request makes the following changes: 2 | - 3 | 4 | Testing checklist: 5 | - [ ] 6 | 7 | - [ ] I certify that I ran my checklist 8 | 9 | Fixes ushahidi/platform# . 10 | 11 | Ping @ushahidi/platform 12 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # dotrun package 9 | .docker-project 10 | .yarn.*.hash 11 | .dotrun.json 12 | 13 | npm-debug.log* 14 | yarn-debug.log* 15 | yarn-error.log* 16 | 17 | # build 18 | /build 19 | /tmp 20 | 21 | # local configuratinon 22 | .env.*.local 23 | .env.local 24 | .env 25 | 26 | # junk 27 | *.DS_Store 28 | *.fuse* 29 | -------------------------------------------------------------------------------- /Procfile: -------------------------------------------------------------------------------- 1 | web: npm start 2 | -------------------------------------------------------------------------------- /api/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["important-stuff", "plugin:prettier/recommended"], 3 | "parser": "@babel/eslint-parser" 4 | } 5 | -------------------------------------------------------------------------------- /api/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | *.pid.lock 13 | 14 | # Directory for instrumented libs generated by jscoverage/JSCover 15 | lib-cov 16 | 17 | # Coverage directory used by tools like istanbul 18 | coverage 19 | 20 | # nyc test coverage 21 | .nyc_output 22 | 23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 24 | .grunt 25 | 26 | # Bower dependency directory (https://bower.io/) 27 | bower_components 28 | 29 | # node-waf configuration 30 | .lock-wscript 31 | 32 | # Compiled binary addons (https://nodejs.org/api/addons.html) 33 | build/Release 34 | 35 | # Dependency directories 36 | node_modules/ 37 | jspm_packages/ 38 | 39 | # TypeScript v1 declaration files 40 | typings/ 41 | 42 | # Optional npm cache directory 43 | .npm 44 | 45 | # Optional eslint cache 46 | .eslintcache 47 | 48 | # Optional REPL history 49 | .node_repl_history 50 | 51 | # Output of 'npm pack' 52 | *.tgz 53 | 54 | # Yarn Integrity file 55 | .yarn-integrity 56 | 57 | # dotenv environment variables file 58 | .env 59 | 60 | # next.js build output 61 | .next 62 | dist 63 | 64 | # Editor directories and files 65 | .idea 66 | .vscode 67 | *.suo 68 | *.ntvs* 69 | *.njsproj 70 | *.sln 71 | *.sw? 72 | .DS_Store 73 | -------------------------------------------------------------------------------- /api/.prettierignore: -------------------------------------------------------------------------------- 1 | .gitignore 2 | .prettierignore 3 | yarn.lock 4 | yarn-error.log 5 | package-lock.json 6 | dist 7 | coverage 8 | pnpm-lock.yaml -------------------------------------------------------------------------------- /api/babel.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["@babel/preset-env"], 3 | "plugins": [ 4 | [ 5 | "@babel/plugin-transform-runtime", 6 | { 7 | "useESModules": true, 8 | "regenerator": false 9 | } 10 | ] 11 | ], 12 | "env": { 13 | "test": { 14 | "presets": [ 15 | [ 16 | "@babel/preset-env", 17 | { 18 | "targets": "current node" 19 | } 20 | ] 21 | ] 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /api/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | transform: { 3 | "^.+\\.(j|t)sx?$": "babel-jest", 4 | }, 5 | moduleNameMapper: { 6 | "\\.(css)$": "identity-obj-proxy", 7 | }, 8 | }; 9 | -------------------------------------------------------------------------------- /api/src/config/configEndpoint.js: -------------------------------------------------------------------------------- 1 | import * as UshahidiSdk from "ushahidi-platform-sdk/build/src/index"; 2 | import { getBackendUrl } from "./settings.js"; 3 | 4 | const backendUrl = getBackendUrl(); 5 | const ushahidi = new UshahidiSdk.Config(backendUrl); 6 | 7 | export const getConfig = function (id = "") { 8 | return ushahidi.getConfig(id); 9 | }; 10 | -------------------------------------------------------------------------------- /api/src/config/settings.js: -------------------------------------------------------------------------------- 1 | export const getBackendUrl = function () { 2 | let backendUrl = ""; 3 | // window.ushahidi.backendUrl is configured in ./root/src/config.js 4 | // BACKEND_URL is set on build-time with Webpack from environment variables 5 | if (window.ushahidi && window.ushahidi.backendUrl) { 6 | backendUrl = window.ushahidi.backendUrl; 7 | } else { 8 | backendUrl = BACKEND_URL; 9 | } 10 | 11 | // REGEX to format the url correctly 12 | return backendUrl.replace(/\/$/, ""); 13 | }; 14 | -------------------------------------------------------------------------------- /api/src/ushahidi-api.js: -------------------------------------------------------------------------------- 1 | export { getConfig } from "./config/configEndpoint"; 2 | -------------------------------------------------------------------------------- /api/webpack.config.js: -------------------------------------------------------------------------------- 1 | const webpack = require("webpack"); 2 | const { merge } = require("webpack-merge"); 3 | const singleSpaDefaults = require("webpack-config-single-spa"); 4 | 5 | module.exports = (webpackConfigEnv, argv) => { 6 | const defaultConfig = singleSpaDefaults({ 7 | orgName: "ushahidi", 8 | projectName: "api", 9 | webpackConfigEnv, 10 | argv, 11 | }); 12 | let filename = defaultConfig.mode === 'development' ? 'ushahidi-api.js' : 'ushahidi-api.[chunkhash].js'; 13 | 14 | return merge(defaultConfig, { 15 | output: { 16 | filename, 17 | clean: true 18 | }, 19 | plugins: [ 20 | new webpack.DefinePlugin({ 21 | BACKEND_URL: JSON.stringify( 22 | process.env.BACKEND_URL || "http://backend.url.undefined" 23 | ), 24 | }), 25 | ], 26 | }); 27 | }; 28 | -------------------------------------------------------------------------------- /app/config.js.j2: -------------------------------------------------------------------------------- 1 | // Configure your Ushahidi deployment 2 | 3 | window.ushahidi = { 4 | backendUrl: '{{ BACKEND_URL }}', 5 | mapboxApiKey: '{{ MAPBOX_API_KEY }}', 6 | {% if GA_KEY %} 7 | gaEnabled: true, 8 | gaKey: '{{ GA_KEY }}', 9 | {% else %} 10 | gaEnabled: false, 11 | {% endif %} 12 | {% if GOOGLE_MAPS_API_KEY %} 13 | googleMapsApiKey: '{{ GOOGLE_MAPS_API_KEY }}', 14 | {% endif %} 15 | {% if GTM_CONTAINER_ID %} 16 | googleTagManager: '{{ GTM_CONTAINER_ID }}', 17 | {% endif %} 18 | intercomAppId: '{{ INTERCOM_APPID }}', 19 | appStoreId: '{{ APP_STORE_ID }}', 20 | ravenUrl: '{{ RAVEN_URL }}', 21 | tosReleaseDate: '{{ TOS_RELEASE_DATE }}', 22 | {% if ENABLED_SOURCES %}} 23 | sources: {{ ENABLED_SOURCES.split(',') | map('trim') | list }}, 24 | {% endif %} 25 | } 26 | -------------------------------------------------------------------------------- /app/config.json: -------------------------------------------------------------------------------- 1 | // Set configuration for Ushahidi mobile app 2 | 3 | //{ 4 | // client_id: "", 5 | // client_secret: "", 6 | // backend_url: "", 7 | // google_analytics_id: "", 8 | // intercom_app_id: "", 9 | // mapbox_api_key: "", 10 | // raven_url: "" 11 | //} 12 | -------------------------------------------------------------------------------- /app/config.json.j2: -------------------------------------------------------------------------------- 1 | { 2 | "client_id": "{{ OAUTH_CLIENT_ID | default('ushahidiui') }}", 3 | "client_secret": "{{ OAUTH_CLIENT_SECRET | default('35e7f0bca957836d05ca0492211b0ac707671261') }}", 4 | "backend_url": "{{ BACKEND_URL }}", 5 | "google_analytics_id": "{{ GA_KEY }}", 6 | "intercom_app_id": "{{ INTERCOM_APPID }}", 7 | "mapbox_api_key": "{{ MAPBOX_API_KEY }}", 8 | "raven_url": "{{ RAVEN_URL }}" 9 | } 10 | -------------------------------------------------------------------------------- /buildargs.env.encrypted: -------------------------------------------------------------------------------- 1 | aUXiCjDBqCPhEAYhlXLXpC+lGUL9jevdDHq4jpNE497/BEwS2gQXdBtjIp3OHly/66Jcaloj1FSlpRizlpBDk4HHs8k= -------------------------------------------------------------------------------- /codeship-steps.yml: -------------------------------------------------------------------------------- 1 | # run 'jet run test gulp test' for tests 2 | 3 | - name: "Build client" 4 | service: build 5 | command: build 6 | 7 | 8 | - type: parallel 9 | steps: 10 | - name: "Release bundle" 11 | service: release 12 | command: release 13 | tag: '^v[0-9]\.[0-9]+.[0-9]+([\-a-zA-Z0-9\.]+)?$' 14 | - name: "Deployment director" 15 | service: deploy 16 | command: CI_NAME=codeship ush-deployment-director.sh 17 | 18 | -------------------------------------------------------------------------------- /docker.env.encrypted: -------------------------------------------------------------------------------- 1 | codeship:v2 2 | CB3n+FyxdRS8Za5VdpyiyNnyP9Io1Yj0NKWf6LDrN7/GOo/0ACbNhWjJvKCXTfFiR38XGXrxFGv85yg+FirQeXYjKRpZs8dReWAZKDXrzGl2UL4p82yUJSVDPKMwyEgVANVzrYi8uAAEEjzKv+ocRITTqp5JS2rjMIkb7KifzvMJgQsUO7iBcCiK3giyUF3QpmsSgB2nomwhf7JBDppzIC/xXF8A/g== -------------------------------------------------------------------------------- /docker/build.Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ushahidi/node-ci:node-10-gulp-4 2 | 3 | RUN mkdir -p /var/app 4 | WORKDIR /var/app 5 | COPY ./package.json ./ 6 | COPY ./root/package.json ./root/package.json 7 | COPY ./legacy/package.json ./legacy/package.json 8 | COPY ./utilities/package.json ./utilities/package.json 9 | COPY ./api/package.json ./api/package.json 10 | RUN npm run install:all 11 | 12 | COPY docker/build.run.sh /build.run.sh 13 | 14 | ENTRYPOINT [ "/bin/bash", "/build.run.sh" ] 15 | -------------------------------------------------------------------------------- /docker/nginx.default.conf: -------------------------------------------------------------------------------- 1 | server { 2 | 3 | listen $HTTP_PORT default_server; 4 | server_name _; 5 | 6 | root /usr/share/nginx/html; 7 | index index.html index.htm; 8 | 9 | location / { 10 | try_files $uri $uri/ @missing; 11 | } 12 | 13 | # Rewrite 404s back to index.html for pushState support 14 | # All routing is handled by Angular. 15 | location @missing { 16 | rewrite ^ /index.html last; 17 | } 18 | 19 | } -------------------------------------------------------------------------------- /docker/nginx.run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | if [ "$1" = "noop" ]; then 4 | # do nothing operator 5 | sleep infinity 6 | exit 0; 7 | fi 8 | 9 | # patch in frontend configuration 10 | if [ -z "$BACKEND_URL" ]; then 11 | echo "ERROR! You must provide a BACKEND_URL variable pointing at an ushahidi API host" 12 | exit 1 13 | fi 14 | 15 | if [ -n "`which jinja`" ]; then 16 | if [ -f config.js.j2 ]; then 17 | echo "- Generating config.js from template:" 18 | python3 -c 'import os, json ; print(json.dumps(dict(os.environ)))' | \ 19 | jinja -d - -f json config.js.j2 | \ 20 | tee config.js 21 | fi 22 | 23 | if [ -f config.json.j2 ]; then 24 | echo "- Generating config.json from template:" 25 | python3 -c 'import os, json ; print(json.dumps(dict(os.environ)))' | \ 26 | jinja -d - -f json config.json.j2 | \ 27 | tee config.json 28 | fi 29 | fi 30 | 31 | # execute the provided command 32 | exec "$@" 33 | -------------------------------------------------------------------------------- /docker/release.Dockerfile: -------------------------------------------------------------------------------- 1 | FROM golang:1.14 2 | 3 | RUN go get github.com/ushahidi/github-release 4 | 5 | COPY docker/release.run.sh /release.run.sh 6 | 7 | ENTRYPOINT [ "/bin/bash", "/release.run.sh" ] 8 | -------------------------------------------------------------------------------- /docker/release.run.sh: -------------------------------------------------------------------------------- 1 | #/bin/sh 2 | 3 | set -ex 4 | 5 | if [ -z "$GITHUB_RELEASE_TOKEN" ]; then 6 | echo "Please provide a GITHUB_RELEASE_TOKEN environment variable!" 7 | fi 8 | 9 | export GITHUB_TOKEN=$GITHUB_RELEASE_TOKEN 10 | 11 | GITHUB_ORG=${GITHUB_ORG:-ushahidi} 12 | GITHUB_REPO_NAME=${GITHUB_REPO_NAME:-$CI_REPO_NAME} 13 | GITHUB_VERSION=${GITHUB_VERSION:-$CI_BRANCH} 14 | 15 | ghr() { 16 | local cmd=$1 17 | shift 1 18 | /go/bin/github-release $cmd \ 19 | --user $GITHUB_ORG \ 20 | --repo $GITHUB_REPO_NAME \ 21 | $* 22 | } 23 | 24 | if ghr info --tag $GITHUB_VERSION ; then 25 | # release already exists, leave it alone 26 | echo "Release already exists, leaving it alone" 27 | else 28 | # release has to be created 29 | ghr release --tag $GITHUB_VERSION --name $GITHUB_VERSION 30 | fi 31 | 32 | for f in $(find /release -type f); do 33 | ghr upload --tag $GITHUB_VERSION --name $(basename $f) --file $f 34 | done 35 | -------------------------------------------------------------------------------- /docker/test.Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ushahidi/node-ci:node-10-gulp-4 2 | 3 | RUN mkdir -p /var/app 4 | WORKDIR /var/app 5 | COPY package.json /var/app 6 | RUN npm-install-silent.sh 7 | 8 | COPY docker/test.run.sh /test.run.sh 9 | 10 | ENTRYPOINT [ "/bin/bash", "/test.run.sh" ] 11 | -------------------------------------------------------------------------------- /docker/test.run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | # Ensure volume with source code is present 6 | check_vols_src() { 7 | if [ ! -d /vols/src ]; then 8 | echo "No /vols/src with code" 9 | exit 1 10 | fi 11 | } 12 | 13 | # Sync from source code to the build directory, exclude any folders and file 14 | # that are result of the build process 15 | function sync { 16 | check_vols_src 17 | { 18 | echo "- .git" 19 | echo "- .bin" 20 | echo "- node_modules" 21 | echo "- tmp" 22 | } > /tmp/rsync_exclude 23 | rsync -ar --exclude-from=/tmp/rsync_exclude --delete-during /vols/src/ ./ 24 | } 25 | 26 | install() { 27 | npm-install-silent.sh 28 | } 29 | 30 | sync 31 | install 32 | test/pre_test.sh 33 | test/test.sh 34 | -------------------------------------------------------------------------------- /legacy/.arclint: -------------------------------------------------------------------------------- 1 | { 2 | "linters" : { 3 | "jshint" : { 4 | "type" : "jshint", 5 | "include" : "(\\.js$)", 6 | "exclude" : "@/bower_components/.*\\.js$@", 7 | "jshint.jshintrc" : ".jshintrc", 8 | "jshint.jshintignore" : ".jshintignore" 9 | }, 10 | "jscs" : { 11 | "type" : "jscs", 12 | "include" : "(\\.js$)" 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /legacy/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": ["transform-runtime"], 3 | "presets": ["es2015", "stage-0"], 4 | "env": { 5 | "test": { 6 | "plugins": [ "istanbul" ] 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /legacy/.eslintignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | bower_components 3 | test/coverage/ 4 | server/www 5 | -------------------------------------------------------------------------------- /legacy/.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | .sass-cache 3 | bower_components 4 | node_modules 5 | npm-debug.log 6 | .gulpconfig.json 7 | .env 8 | test/coverage/ 9 | build/* 10 | dist/* 11 | .DS_Store 12 | server/www/locales/ 13 | *.aes 14 | *.swp 15 | *.swo 16 | buildargs.env 17 | deployment.env 18 | docker.env 19 | vault.txt 20 | *.swo 21 | *.swp 22 | *.svg 23 | server/www/img/icons/ 24 | server/www/ 25 | app/locales/ 26 | app/stats.html 27 | -------------------------------------------------------------------------------- /legacy/app.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Ushahidi Platform Client", 3 | "description": "The JS client for the Ushahidi Platform.", 4 | "keywords": [ 5 | "ushahidi", 6 | "crowdmap" 7 | ], 8 | "website": "http://ushahidi.com", 9 | "repository": "https://github.com/ushahidi/platform-client", 10 | "logo": "http://www.ushahidi.com/assets/img/favicon.ico", 11 | "success_url": "/", 12 | "env": { 13 | "BUILDPACK_URL": "https://github.com/heroku/heroku-buildpack-multi.git", 14 | "NODE_ENV": "dev", 15 | "NPM_CONFIG_PRODUCTION": "false", 16 | "BACKEND_URL": { 17 | "description" : "A deployment of ushahidi/platform to use", 18 | "value" : "https://ushahidi-platform-api-master.herokuapp.com", 19 | "required" : true 20 | }, 21 | "TX_USERNAME": { 22 | "description" : "Your username in transifex in order to download translation files (optional)", 23 | "required": false 24 | }, 25 | "TX_PASSWORD": { 26 | "description": "Your password in transifex (optional)", 27 | "required": false 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /legacy/app/.well-known/apple-app-site-association: -------------------------------------------------------------------------------- 1 | { 2 | "applinks": { 3 | "apps": [], 4 | "details": [ 5 | { 6 | "appID": "{{ appStoreLinkingId }}", 7 | "paths": [ "*"] 8 | } 9 | ] 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /legacy/app/.well-known/assetlinks.json: -------------------------------------------------------------------------------- 1 | [{ 2 | "relation": ["delegate_permission/common.handle_all_urls"], 3 | "target": { 4 | "namespace": "android_app", 5 | "package_name": "com.ushahidi.mobile", 6 | "sha256_cert_fingerprints": 7 | ["2E:ED:51:63:46:74:11:3C:4B:B5:2D:2B:FA:51:93:18:34:7E:AB:24:84:3E:97:C6:F2:1B:00:20:ED:23:8F:63"] 8 | } 9 | }] 10 | -------------------------------------------------------------------------------- /legacy/app/activity/activity-module.js: -------------------------------------------------------------------------------- 1 | export const ACTIVITY_MODULE = angular.module('ushahidi.activity', []) 2 | 3 | .directive('activityTimeline', require('./activity-timeline.directive.js')) 4 | .directive('activityBarChart', require('./bar-chart.directive.js')) 5 | .directive('activityTimeChart', require('./time-chart.directive.js')) 6 | .directive('targetedSurveyTable', require('./targeted-survey-table.directive.js')) 7 | .directive('crowdsourcedSurveyTable', require('./crowdsourced-survey-table.directive.js')) 8 | ; 9 | -------------------------------------------------------------------------------- /legacy/app/activity/activity-routes.js: -------------------------------------------------------------------------------- 1 | angular.module('ushahidi.activity.routes', []) 2 | 3 | .config([ 4 | '$stateProvider', 5 | '$urlMatcherFactoryProvider', 6 | function ( 7 | $stateProvider, 8 | $urlMatcherFactoryProvider 9 | ) { 10 | $urlMatcherFactoryProvider.strictMode(false); 11 | 12 | $stateProvider 13 | .state({ 14 | name: 'activity', 15 | url: '/activity', 16 | controller: require('./activity.controller.js'), 17 | template: require('./activity.html'), 18 | lazyLoad: function ($transition$) { 19 | const $ocLazyLoad = $transition$.injector().get('$ocLazyLoad'); 20 | return System.import('@ushahidi/legacy-activity').then(mod => { 21 | $ocLazyLoad.load(mod.ACTIVITY_MODULE); 22 | }); 23 | } 24 | }); 25 | }] 26 | ); 27 | -------------------------------------------------------------------------------- /legacy/app/activity/bar-chart.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 | Compare... 5 | Compare... 6 | 7 | 8 | 9 | 10 | 11 | 18 |
19 | 20 |

graph.no_data

21 | 22 |
23 | -------------------------------------------------------------------------------- /legacy/app/auth/404.controller.js: -------------------------------------------------------------------------------- 1 | module.exports = [ 2 | '$scope', 3 | function ( 4 | $scope 5 | ) { 6 | 7 | }]; 8 | -------------------------------------------------------------------------------- /legacy/app/auth/404.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |

nav.404

4 | 5 |

6 | app.404 7 |

8 |
9 |
-------------------------------------------------------------------------------- /legacy/app/auth/auth-module.js: -------------------------------------------------------------------------------- 1 | angular.module('ushahidi.auth', []) 2 | 3 | // Authentication 4 | .service('Authentication', require('./authentication.service.js')) 5 | .service('Registration', require('./registration.service.js')) 6 | .service('Session', require('./session.service.js')) 7 | .service('PasswordReset', require('./password-reset.service.js')) 8 | .service('TermsOfService', require('./tos.service.js')) 9 | .directive('login', require('./login.directive.js')) 10 | .directive('register', require('./register.directive.js')) 11 | .directive('passwordReset', require('./password-reset.directive.js')) 12 | .directive( 13 | 'passwordResetConfirm', 14 | require('./password-reset-confirm.directive.js') 15 | ) 16 | .directive('termsOfService', require('./tos.directive.js')) 17 | 18 | // From common module 19 | .service('TermsOfServiceEndpoint', require('./services/terms-of-service-endpoint.js')) 20 | 21 | .config(require('./authentication-interceptor.config.js')) 22 | .run(require('./authentication-events.run.js')) 23 | 24 | .config(require('./auth-routes.js')) 25 | -------------------------------------------------------------------------------- /legacy/app/auth/forbidden.controller.js: -------------------------------------------------------------------------------- 1 | module.exports = [ 2 | '$scope', 3 | function ( 4 | $scope 5 | ) { 6 | 7 | }]; 8 | -------------------------------------------------------------------------------- /legacy/app/auth/forbidden.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |

nav.forbidden

4 | 5 |

6 | app.forbidden 7 |

8 |
9 |
10 | -------------------------------------------------------------------------------- /legacy/app/auth/login.controller.js: -------------------------------------------------------------------------------- 1 | module.exports = LoginController; 2 | 3 | LoginController.$inject = ['Authentication','$location']; 4 | function LoginController(Authentication, $location) { 5 | Authentication.openLogin(); 6 | $location.url('/'); 7 | } 8 | -------------------------------------------------------------------------------- /legacy/app/auth/login.html: -------------------------------------------------------------------------------- 1 |
2 | 18 | 24 |
25 | -------------------------------------------------------------------------------- /legacy/app/auth/password-reset-confirm.controller.js: -------------------------------------------------------------------------------- 1 | module.exports = PasswordResetConfirmController; 2 | 3 | PasswordResetConfirmController.$inject = ['$rootScope', 'PasswordReset', '$location', '$transition$']; 4 | function PasswordResetConfirmController($rootScope, PasswordReset, $location, $transition$) { 5 | var $scope = $rootScope.$new(); 6 | $scope.token = $transition$.params().token; 7 | 8 | PasswordReset.openResetConfirm($scope); 9 | $location.url('/'); 10 | } 11 | -------------------------------------------------------------------------------- /legacy/app/auth/password-reset.controller.js: -------------------------------------------------------------------------------- 1 | module.exports = [ 2 | 'PasswordReset', 3 | '$location', 4 | function ( 5 | PasswordReset, 6 | $location 7 | ) { 8 | PasswordReset.openReset(); 9 | $location.url('/'); 10 | }]; 11 | -------------------------------------------------------------------------------- /legacy/app/auth/password-reset.directive.js: -------------------------------------------------------------------------------- 1 | module.exports = PasswordResetDirective; 2 | 3 | PasswordResetDirective.$inject = []; 4 | function PasswordResetDirective() { 5 | return { 6 | restrict: 'E', 7 | scope: true, 8 | controller: PasswordResetController, 9 | template: require('./password-reset.html') 10 | }; 11 | } 12 | PasswordResetController.$inject = [ 13 | '$scope', 14 | 'PasswordReset', 15 | 'Authentication' 16 | ]; 17 | function PasswordResetController( 18 | $scope, 19 | PasswordReset, 20 | Authentication 21 | ) { 22 | $scope.processing = false; 23 | $scope.email = ''; 24 | 25 | $scope.submit = submit; 26 | $scope.cancel = cancel; 27 | 28 | activate(); 29 | 30 | function activate() { 31 | // If we're already logged in 32 | if (Authentication.getLoginStatus()) { 33 | $scope.$parent.closeModal(); 34 | } 35 | } 36 | 37 | $scope.processing = false; 38 | 39 | function resetDone() { 40 | $scope.processing = false; 41 | PasswordReset.openResetConfirm(); 42 | } 43 | 44 | function submit() { 45 | $scope.processing = true; 46 | 47 | PasswordReset 48 | .reset($scope.email) 49 | .finally(resetDone); 50 | } 51 | 52 | function cancel() { 53 | $scope.$parent.closeModal(); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /legacy/app/auth/password-reset.html: -------------------------------------------------------------------------------- 1 | 25 | -------------------------------------------------------------------------------- /legacy/app/auth/password-reset.service.js: -------------------------------------------------------------------------------- 1 | module.exports = [ 2 | '$http', 3 | 'Util', 4 | 'ModalService', 5 | function ( 6 | $http, 7 | Util, 8 | ModalService 9 | ) { 10 | 11 | return { 12 | 13 | reset: function (email) { 14 | var payload = { 15 | email: email 16 | }; 17 | 18 | return $http.post(Util.apiUrl('/passwordreset'), payload); 19 | }, 20 | 21 | resetConfirm: function (token, password) { 22 | var payload = { 23 | token: token, 24 | password: password 25 | }; 26 | 27 | return $http.post(Util.apiUrl('/passwordreset/confirm'), payload); 28 | }, 29 | 30 | openReset: function () { 31 | ModalService.openTemplate('', 'nav.forgotyourpassword', false, false, true, false); 32 | }, 33 | 34 | openResetConfirm: function (scope) { 35 | ModalService.openTemplate('', 'nav.resetpassword', false, scope, true, false); 36 | } 37 | }; 38 | 39 | }]; 40 | -------------------------------------------------------------------------------- /legacy/app/auth/register.controller.js: -------------------------------------------------------------------------------- 1 | module.exports = RegisterController; 2 | 3 | RegisterController.$inject = ['Registration','$location']; 4 | function RegisterController(Registration, $location) { 5 | Registration.openRegister(); 6 | $location.url('/'); 7 | } 8 | -------------------------------------------------------------------------------- /legacy/app/auth/registration.service.js: -------------------------------------------------------------------------------- 1 | module.exports = [ 2 | '$rootScope', 3 | '$http', 4 | '$q', 5 | 'Util', 6 | '$location', 7 | 'ModalService', 8 | function ( 9 | $rootScope, 10 | $http, 11 | $q, 12 | Util, 13 | $location, 14 | ModalService 15 | ) { 16 | 17 | return { 18 | 19 | register: function (realname, email, password) { 20 | var payload = { 21 | realname: realname, 22 | email: email, 23 | password: password 24 | }, 25 | 26 | deferred = $q.defer(), 27 | 28 | handleRequestError = function (response) { 29 | deferred.reject(response); 30 | $rootScope.$broadcast('event:registration:register:failed'); 31 | }, 32 | 33 | handleRequestSuccess = function (response) { 34 | $rootScope.$broadcast('event:registration:register:succeeded'); 35 | deferred.resolve(response); 36 | }; 37 | 38 | $http.post(Util.apiUrl('/register'), payload).then(handleRequestSuccess, handleRequestError); 39 | 40 | return deferred.promise; 41 | }, 42 | 43 | openRegister: function () { 44 | ModalService.openTemplate('', 'nav.register', false, false, true, false); 45 | } 46 | }; 47 | 48 | }]; 49 | -------------------------------------------------------------------------------- /legacy/app/auth/services/terms-of-service-endpoint.js: -------------------------------------------------------------------------------- 1 | module.exports = [ 2 | '$resource', 3 | 'Util', 4 | function ( 5 | $resource, 6 | Util 7 | ) { 8 | 9 | var TermsOfServiceEndpoint = $resource(Util.apiUrl('/tos/'), { 10 | 11 | }, { 12 | get: { 13 | method: 'GET' 14 | } 15 | }); 16 | 17 | return TermsOfServiceEndpoint; 18 | }]; 19 | -------------------------------------------------------------------------------- /legacy/app/auth/tos.directive.js: -------------------------------------------------------------------------------- 1 | module.exports = TermsOfServiceDirective; 2 | 3 | TermsOfServiceDirective.$inject = []; 4 | function TermsOfServiceDirective() { 5 | return { 6 | restrict: 'E', 7 | scope: {}, 8 | controller: TosController, 9 | template: require('./tos.html') 10 | }; 11 | } 12 | 13 | TosController.$inject = [ 14 | '$scope', 15 | 'Authentication', 16 | 'TermsOfService', 17 | 'TermsOfServiceEndpoint', 18 | 'Session', 19 | 'CONST' 20 | ]; 21 | function TosController( 22 | $scope, 23 | Authentication, 24 | TermsOfService, 25 | TermsOfServiceEndpoint, 26 | Session, 27 | CONST 28 | ) { 29 | $scope.terms = { 30 | accept: false 31 | }; 32 | 33 | $scope.tosSubmit = function () { 34 | if (!$scope.terms.accept) { 35 | return; 36 | } 37 | 38 | TermsOfServiceEndpoint.save({tos_version_date: CONST.TOS_RELEASE_DATE}) 39 | .$promise.then(function (tosSessionData) { 40 | // Don't really need this if, but it's just a backup so that you can't access the site if tos is not set properly 41 | if (tosSessionData.agreement_date) { 42 | $scope.$parent.confirm(); 43 | } 44 | }); 45 | }; 46 | } 47 | -------------------------------------------------------------------------------- /legacy/app/auth/tos.html: -------------------------------------------------------------------------------- 1 | 18 | -------------------------------------------------------------------------------- /legacy/app/bootstrap.js: -------------------------------------------------------------------------------- 1 | require('./app.js'); 2 | import singleSpaAngularJS from 'single-spa-angularjs'; 3 | 4 | //exporting lifecycle-functions for angular-app 5 | const ngLifecycles = singleSpaAngularJS({ 6 | angular: angular, 7 | mainAngularModule: 'app', 8 | uiRouter: true, 9 | preserveGlobal: false, 10 | strictDi: true, 11 | template: require('./index.html') 12 | }); 13 | 14 | export const bootstrap = ngLifecycles.bootstrap; 15 | 16 | export const mount = ngLifecycles.mount; 17 | export const unmount = ngLifecycles.unmount; 18 | 19 | -------------------------------------------------------------------------------- /legacy/app/common/common-routes.js: -------------------------------------------------------------------------------- 1 | module.exports = ['$stateProvider', '$urlMatcherFactoryProvider', function ($stateProvider, $urlMatcherFactoryProvider) { 2 | 3 | $urlMatcherFactoryProvider.strictMode(false); 4 | 5 | $stateProvider 6 | .state({ 7 | name: 'verifier', 8 | url: '/verifier', 9 | controller: require('./verifier/verifier.controller.js'), 10 | template: require('./verifier/verifier.html') 11 | }); 12 | }]; 13 | -------------------------------------------------------------------------------- /legacy/app/common/configs/cache-config.js: -------------------------------------------------------------------------------- 1 | module.exports = ['CacheFactoryProvider', function (CacheFactoryProvider) { 2 | angular.extend(CacheFactoryProvider.defaults, { 3 | maxAge: 15 * 60 * 1000, // 15 mins 4 | cacheFlushInterval: 60 * 60 * 1000, // This cache will clear itself every hour 5 | storageMode: 'localStorage', 6 | storagePrefix: 'ush-caches.', 7 | deleteOnExpire: 'aggressive' 8 | }); 9 | }]; 10 | -------------------------------------------------------------------------------- /legacy/app/common/configs/loading.interceptor-config.js: -------------------------------------------------------------------------------- 1 | module.exports = ['$httpProvider', function ($httpProvider) { 2 | $httpProvider.interceptors.push('loading'); 3 | }]; 4 | -------------------------------------------------------------------------------- /legacy/app/common/configs/locale-config.js: -------------------------------------------------------------------------------- 1 | module.exports = ['$translateProvider', function ($translateProvider) { 2 | $translateProvider.useSanitizeValueStrategy('escaped'); 3 | 4 | $translateProvider.translations('en', require('../locales/en.json')); 5 | 6 | $translateProvider.useStaticFilesLoader({ 7 | prefix: 'locales/', 8 | suffix: '.json' 9 | }); 10 | 11 | $translateProvider.preferredLanguage('en'); 12 | $translateProvider.fallbackLanguage('en'); 13 | }]; 14 | -------------------------------------------------------------------------------- /legacy/app/common/configs/ui-bootstrap-template-decorators.js: -------------------------------------------------------------------------------- 1 | module.exports = [ 2 | '$templateCache', 3 | function ( 4 | $templateCache 5 | ) { 6 | $templateCache.put('uib/template/pagination/pagination.html', require('./uib-pagination.html')); 7 | }]; 8 | -------------------------------------------------------------------------------- /legacy/app/common/controllers/navigation.js: -------------------------------------------------------------------------------- 1 | module.exports = NavigationController; 2 | 3 | NavigationController.$inject = ['Authentication', 'ConfigEndpoint', 'BootstrapConfig', '$rootScope', 'Features']; 4 | function NavigationController(Authentication, ConfigEndpoint, BootstrapConfig, $rootScope, Features) { 5 | var vm = this; 6 | 7 | vm.site = BootstrapConfig; 8 | vm.reloadSiteConfig = reloadSiteConfig; 9 | //vm.canCreatePost = canCreatePost; 10 | //vm.canRegister = canRegister; 11 | //vm.logoutClick = logoutClick; 12 | 13 | activate(); 14 | 15 | $rootScope.$on('event:update:header', reloadSiteConfig); 16 | 17 | function activate() { 18 | 19 | Features.loadFeatures().then(function () { 20 | vm.activityIsAvailable = Features.isViewEnabled('activity'); 21 | vm.planIsAvailable = Features.isViewEnabled('plan'); 22 | }); 23 | 24 | reloadSiteConfig(); 25 | } 26 | 27 | function reloadSiteConfig() { 28 | ConfigEndpoint.get({ id: 'site' }).$promise.then(function (site) { 29 | vm.site = site; 30 | }); 31 | } 32 | 33 | // Move to add post button (or associated service) 34 | // function canCreatePost() { 35 | // return $rootScope.loggedin || !vm.site.private; 36 | // }; 37 | } 38 | -------------------------------------------------------------------------------- /legacy/app/common/directives/custom-on-change.js: -------------------------------------------------------------------------------- 1 | angular.module('ushahidi.common.custom-on-change', []) 2 | 3 | .directive('customOnChange', function () { 4 | return { 5 | restricet: 'A', 6 | link: function ($scope, $element, $attrs) { 7 | var onChangeFunc = $scope.$eval($attrs.customOnChange); 8 | $element.bind('change', onChangeFunc); 9 | } 10 | }; 11 | }); 12 | -------------------------------------------------------------------------------- /legacy/app/common/directives/embed-only.directive.js: -------------------------------------------------------------------------------- 1 | module.exports = EmbedOnlyDirective; 2 | 3 | EmbedOnlyDirective.$inject = []; 4 | function EmbedOnlyDirective() { 5 | return { 6 | restrict: 'A', 7 | controller: EmbedOnlyController 8 | }; 9 | } 10 | 11 | EmbedOnlyController.$inject = ['$scope', '$element', '$attrs', '$rootScope', '_', '$window']; 12 | function EmbedOnlyController($scope, $element, $attrs, $rootScope, _, $window) { 13 | var globalEmbed = ($window.self !== $window.top) ? true : false; 14 | 15 | if (globalEmbed && ($attrs.embedOnly === 'false')) { 16 | $element.addClass('hidden'); 17 | } else if (!globalEmbed && ($attrs.embedOnly === 'true')) { 18 | $element.addClass('hidden'); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /legacy/app/common/directives/file-upload.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /legacy/app/common/directives/focus.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Focus directive. 3 | * Use this to set focus on input fields that may otherwise not have focus when they become available. 4 | */ 5 | 6 | module.exports = Focus; 7 | 8 | Focus.$inject = [ 9 | '$timeout' 10 | ]; 11 | 12 | function Focus($timeout) { 13 | return { 14 | restrict: 'A', 15 | link: function (scope, element, attrs) { 16 | scope.$watch(attrs.focus, function (value) { 17 | if (value) { 18 | $timeout(function () { 19 | element[0].focus(); 20 | }); 21 | } 22 | }); 23 | } 24 | }; 25 | } 26 | -------------------------------------------------------------------------------- /legacy/app/common/directives/language-switch.directive.js: -------------------------------------------------------------------------------- 1 | module.exports = LanguageSwitchDirective; 2 | 3 | LanguageSwitchDirective.$inject = []; 4 | 5 | function LanguageSwitchDirective() { 6 | return { 7 | restrict: 'E', 8 | scope: { 9 | site: '=?' 10 | }, 11 | controller: LanguageSwitchController, 12 | template: require('./language-switch.html') 13 | }; 14 | } 15 | LanguageSwitchController.$inject = ['$scope', 'Languages', 'TranslationService', '$location']; 16 | function LanguageSwitchController($scope, Languages, TranslationService, $location) { 17 | $scope.changeLanguage = changeLanguage; 18 | $scope.$on('event:authentication:login:succeeded', TranslationService.setStartLanguage); 19 | $scope.$on('event:authentication:logout:succeeded', TranslationService.setStartLanguage); 20 | activate(); 21 | 22 | function activate() { 23 | $scope.languages = Languages.getLanguages(); 24 | } 25 | 26 | function changeLanguage(code) { 27 | if ($location.path() !== '/settings/general') { 28 | TranslationService.setLanguage(code); 29 | TranslationService.translate(code); 30 | } 31 | } 32 | } 33 | 34 | -------------------------------------------------------------------------------- /legacy/app/common/directives/language-switch.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 10 |
11 |
12 | -------------------------------------------------------------------------------- /legacy/app/common/directives/layout-class.directive.js: -------------------------------------------------------------------------------- 1 | module.exports = LayoutClassDirective; 2 | 3 | LayoutClassDirective.$inject = []; 4 | function LayoutClassDirective() { 5 | return { 6 | restrict: 'E', 7 | scope: { 8 | layout: '@' 9 | }, 10 | controller: LayoutClassController 11 | }; 12 | } 13 | 14 | LayoutClassController.$inject = ['$scope', '$rootScope', '$window']; 15 | function LayoutClassController($scope, $rootScope, $window) { 16 | var isEmbed = ($window.self !== $window.top) ? true : false; 17 | if (!isEmbed) { 18 | $rootScope.setLayout('layout-' + $scope.layout); 19 | } else { 20 | // If we are in embed mode 21 | // we must append the layout to the embed layout 22 | $rootScope.setLayout('layout-embed layout-' + $scope.layout); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /legacy/app/common/directives/list-toolbar.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 | 5 | 6 |
7 | 8 |
9 | 10 |
11 |
12 | -------------------------------------------------------------------------------- /legacy/app/common/directives/loading-dots-button.directive.js: -------------------------------------------------------------------------------- 1 | module.exports = LoadingDotsButtonDirective; 2 | 3 | LoadingDotsButtonDirective.$inject = []; 4 | 5 | function LoadingDotsButtonDirective() { 6 | return { 7 | restrict: 'E', 8 | scope: { 9 | buttonClass: '@', 10 | label: '=', 11 | disabled: '=' 12 | }, 13 | controller: LoadingDotsButtonController, 14 | template: require('./loading-dots-button.html') 15 | }; 16 | } 17 | LoadingDotsButtonController.$inject = ['$scope']; 18 | 19 | function LoadingDotsButtonController($scope) { 20 | } 21 | -------------------------------------------------------------------------------- /legacy/app/common/directives/loading-dots-button.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /legacy/app/common/directives/mainsheet-container.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 10 |

11 | {{ title | translate }} 12 |

13 | 14 |
15 |
16 |
17 | -------------------------------------------------------------------------------- /legacy/app/common/directives/modal-body.directive.js: -------------------------------------------------------------------------------- 1 | module.exports = ModalBody; 2 | 3 | ModalBody.$inject = ['$window']; 4 | function ModalBody($window) { 5 | return { 6 | restrict: 'AC', 7 | link: ModalBodyLink 8 | }; 9 | 10 | function ModalBodyLink($scope, $element) { 11 | activate(); 12 | 13 | function activate() { 14 | $element.css('max-height', modalBodyHeight()); 15 | } 16 | 17 | angular.element($window).bind('resize', handleResize); 18 | // Unbind on destroy 19 | $scope.$on('$destroy', function (event) { 20 | angular.element($window).unbind('resize', handleResize); 21 | }); 22 | 23 | function modalBodyHeight() { 24 | return $window.innerHeight * 0.66 + 'px'; 25 | } 26 | 27 | function handleResize() { 28 | activate(); 29 | 30 | // Manual $digest required as resize event 31 | // is outside of angular 32 | $scope.$digest(); 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /legacy/app/common/directives/modal-container.html: -------------------------------------------------------------------------------- 1 | 23 | -------------------------------------------------------------------------------- /legacy/app/common/directives/modal.html: -------------------------------------------------------------------------------- 1 | 22 | -------------------------------------------------------------------------------- /legacy/app/common/directives/translations-switch.directive.js: -------------------------------------------------------------------------------- 1 | module.exports = TranslationSwitchDirective; 2 | 3 | TranslationSwitchDirective.$inject = []; 4 | 5 | function TranslationSwitchDirective() { 6 | return { 7 | restrict: 'E', 8 | scope: { 9 | languages:'=', 10 | languagesToSelect:'=', 11 | removeLanguage:'&' 12 | }, 13 | controller: TranslationSwitchController, 14 | template: require('./translations-switch.html') 15 | }; 16 | } 17 | TranslationSwitchController.$inject = ['$scope', 'ModalService']; 18 | 19 | function TranslationSwitchController($scope, ModalService) { 20 | activate(); 21 | 22 | function activate() { 23 | } 24 | 25 | $scope.switchToLanguage = function(language) { 26 | $scope.languages.active = language; 27 | }; 28 | 29 | $scope.openLanguages = function() { 30 | ModalService.openTemplate('', 'form.select_language', false, $scope, true, true); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /legacy/app/common/directives/translations-switch.html: -------------------------------------------------------------------------------- 1 |
2 | 6 | 12 | 18 | 19 |
20 | -------------------------------------------------------------------------------- /legacy/app/common/donation/donation-button.directive.js: -------------------------------------------------------------------------------- 1 | module.exports = DonationButtonDirective; 2 | 3 | DonationButtonDirective.$inject = []; 4 | function DonationButtonDirective() { 5 | return { 6 | restrict: 'E', 7 | replace: true, 8 | scope: { 9 | button: '=?' 10 | }, 11 | controller: DonationButtonController, 12 | template: require('./donation-button.html') 13 | }; 14 | } 15 | 16 | DonationButtonController.$inject = ['$scope', '$window', 'DonationService']; 17 | function DonationButtonController($scope, $window, DonationService) { 18 | $scope.loading = false; 19 | $scope.openDonationModal = DonationService.openDonationModal; 20 | $scope.isButton = isButton; 21 | 22 | function isButton() { 23 | return $scope.button; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /legacy/app/common/donation/donation-button.html: -------------------------------------------------------------------------------- 1 | 17 | -------------------------------------------------------------------------------- /legacy/app/common/donation/donation-modal.directive.js: -------------------------------------------------------------------------------- 1 | const { config } = require('raven-js'); 2 | 3 | module.exports = DonationModalDirective; 4 | 5 | DonationModalDirective.$inject = []; 6 | function DonationModalDirective() { 7 | return { 8 | restrict: 'E', 9 | scope: {}, 10 | replace: true, 11 | controller: DonationModalController, 12 | template: require('./donation-modal.html') 13 | }; 14 | } 15 | 16 | DonationModalController.$inject = ['$scope', '$rootScope']; 17 | function DonationModalController($scope, $rootScope) { 18 | $scope.donation = $rootScope.donation; 19 | $scope.donationClientEnabled = $rootScope.donationClientEnabled; 20 | } 21 | -------------------------------------------------------------------------------- /legacy/app/common/donation/donation-module.js: -------------------------------------------------------------------------------- 1 | angular 2 | .module('ushahidi.donation', []) 3 | 4 | .directive('donation', require('./donation.directive.js')) 5 | 6 | .directive('donationButton', require('./donation-button.directive.js')) 7 | 8 | .directive('donationModal', require('./donation-modal.directive.js')) 9 | 10 | .directive('donationToolbar', require('./donation-toolbar.directive.js')) 11 | 12 | .service('DonationService', require('./donation.service.js')); 13 | -------------------------------------------------------------------------------- /legacy/app/common/donation/donation-toolbar.directive.js: -------------------------------------------------------------------------------- 1 | module.exports = DonationToolbarDirective; 2 | 3 | DonationToolbarDirective.$inject = []; 4 | function DonationToolbarDirective() { 5 | return { 6 | restrict: 'E', 7 | scope: {}, 8 | replace: true, 9 | controller: DonationToolbarController, 10 | template: require('./donation-toolbar.html') 11 | }; 12 | } 13 | 14 | DonationToolbarController.$inject = ['$scope', '$rootScope', 'DonationService']; 15 | function DonationToolbarController($scope, $rootScope, DonationService) { 16 | $scope.formattedAmount = 0.0; 17 | $scope.openDonationModal = DonationService.openDonationModal; 18 | 19 | $rootScope.$on('setDonatedAmount', function (event, value) { 20 | $scope.formattedAmount = value; 21 | $scope.$apply(); 22 | }); 23 | } 24 | -------------------------------------------------------------------------------- /legacy/app/common/donation/donation-toolbar.html: -------------------------------------------------------------------------------- 1 | 16 | -------------------------------------------------------------------------------- /legacy/app/common/donation/donation.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /legacy/app/common/factories/loading.interceptor-factory.js: -------------------------------------------------------------------------------- 1 | module.exports = LoadingInterceptor; 2 | 3 | LoadingInterceptor.$inject = ['LoadingProgress', '$q', '$injector']; 4 | 5 | function LoadingInterceptor(LoadingProgress, $q, $injector) { 6 | /* an interceptor that triggers loading-state in the beginning of 7 | * a http-request and remove it when all requests are done */ 8 | 9 | return { 10 | request: function (config) { 11 | if (LoadingProgress.getLoadingState() !== true) { 12 | LoadingProgress.setLoadingState(true); 13 | } 14 | // we want this to trigger isSaving everytime except when a lock-updates 15 | if (config.method === 'PUT' && config.url.indexOf('lock') === -1) { 16 | LoadingProgress.setSavingState(true); 17 | } 18 | return config; 19 | }, 20 | response: function (response) { 21 | var httpService = $injector.get('$http'); 22 | if (httpService.pendingRequests.length === 0) { 23 | LoadingProgress.setLoadingState(false); 24 | LoadingProgress.setSavingState(false); 25 | } 26 | return response || $q.when(response); 27 | } 28 | }; 29 | } 30 | -------------------------------------------------------------------------------- /legacy/app/common/global/event-handlers.js: -------------------------------------------------------------------------------- 1 | module.exports = [ 2 | '$rootScope', 3 | function ( 4 | $rootScope 5 | ) { 6 | // Setup PL layout and switching function 7 | $rootScope.globalLayout = 'layout-a'; 8 | $rootScope.setLayout = function (layout) { 9 | $rootScope.globalLayout = layout; 10 | }; 11 | // Setup PL modal visible and switching function 12 | $rootScope.modalVisible = false; 13 | 14 | $rootScope.toggleModalVisible = function (state) { 15 | $rootScope.modalVisible = (typeof state !== 'undefined') ? state : !$rootScope.modalVisible; 16 | }; 17 | }]; 18 | -------------------------------------------------------------------------------- /legacy/app/common/global/language-settings.js: -------------------------------------------------------------------------------- 1 | module.exports = [ 2 | // '$scope', 3 | '$rootScope', 4 | '$translate', 5 | 'TranslationService', 6 | function ( 7 | // $scope, 8 | $rootScope, 9 | $translate, 10 | TranslationService 11 | ) { 12 | 13 | $rootScope.rtlEnabled = false; 14 | 15 | $rootScope.switchRtl = function () { 16 | $rootScope.rtlEnabled = !$rootScope.rtlEnabled; 17 | }; 18 | TranslationService.getLanguage().then(function (language) { 19 | translate(language); 20 | }); 21 | 22 | function translate(language) { 23 | TranslationService.translate(language); 24 | } 25 | }]; 26 | -------------------------------------------------------------------------------- /legacy/app/common/notifications/api-errors.html: -------------------------------------------------------------------------------- 1 |

2 | {{error}} 3 |

4 | -------------------------------------------------------------------------------- /legacy/app/common/notifications/limit.html: -------------------------------------------------------------------------------- 1 |

{{ message }}

2 |
3 | limit.upgrade 4 | 7 |
8 | -------------------------------------------------------------------------------- /legacy/app/common/notifications/slider.html: -------------------------------------------------------------------------------- 1 | 2 |
7 | 8 |
Loading...

9 | 10 |
15 | 16 | 17 | 18 |
19 | 20 |
23 | 24 | 25 | 28 |
29 |
30 | -------------------------------------------------------------------------------- /legacy/app/common/raven/raven.service.js: -------------------------------------------------------------------------------- 1 | class RavenService { 2 | constructor($rootScope, Session, Raven) { 3 | 'ngInject'; 4 | this.$rootScope = $rootScope; 5 | this.Session = Session; 6 | this.Raven = Raven; 7 | } 8 | 9 | init() { 10 | this.$rootScope.$on('event:authentication:login:succeeded', this.handleLogin.bind(this)); 11 | this.$rootScope.$on('event:authentication:logout:succeeded', this.handleLogout.bind(this)); 12 | 13 | if (this.Session.getSessionDataEntry('userId')) { 14 | this.handleLogin(); 15 | } 16 | } 17 | 18 | handleLogin() { 19 | if (this.Session.getSessionDataEntry('userId')) { 20 | this.Raven.setUserContext({ 21 | id: this.Session.getSessionDataEntry('userId') 22 | }); 23 | } else { 24 | this.Raven.setUserContext({}); 25 | } 26 | } 27 | 28 | handleLogout() { 29 | this.Raven.setUserContext({}); 30 | } 31 | 32 | } 33 | 34 | export default RavenService; 35 | -------------------------------------------------------------------------------- /legacy/app/common/services/endpoints/MediaEndpoint.js: -------------------------------------------------------------------------------- 1 | module.exports = [ 2 | '$resource', 3 | '$rootScope', 4 | 'Util', 5 | function ( 6 | $resource, 7 | $rootScope, 8 | Util 9 | ) { 10 | 11 | var MediaEndpoint = $resource(Util.apiUrl('/media/:id'), { 12 | id: '@id' 13 | }, { 14 | query: { 15 | method: 'GET', 16 | isArray: true, 17 | transformResponse: function (data /*, header*/) { 18 | return Util.transformResponse(data).results; 19 | } 20 | }, 21 | update: { 22 | method: 'PUT' 23 | } 24 | }); 25 | 26 | 27 | return MediaEndpoint; 28 | 29 | }]; 30 | -------------------------------------------------------------------------------- /legacy/app/common/services/endpoints/form-stats-endpoint.js: -------------------------------------------------------------------------------- 1 | module.exports = [ 2 | '$resource', 3 | 'Util', 4 | function ( 5 | $resource, 6 | Util 7 | ) { 8 | 9 | var FormStatsEndpoint = $resource(Util.apiUrl('/forms/:formId/stats/:extra'), { 10 | formId: '@formId' 11 | }, { 12 | query: { 13 | method: 'GET', 14 | isArray: false, 15 | paramSerializer: '$httpParamSerializerJQLike', 16 | transformResponse: function (data /*, header*/) { 17 | return angular.fromJson(data); 18 | } 19 | }, 20 | get: { 21 | method: 'GET' 22 | } 23 | }); 24 | 25 | return FormStatsEndpoint; 26 | }]; 27 | -------------------------------------------------------------------------------- /legacy/app/common/services/endpoints/hxl-tag-endpoint.js: -------------------------------------------------------------------------------- 1 | module.exports = [ 2 | '$resource', 3 | 'Util', 4 | function ( 5 | $resource, 6 | Util 7 | ) { 8 | 9 | var HxlTagEndpoint = $resource(Util.apiUrl('/hxl/tags'), { 10 | id: '@id' 11 | }, { 12 | get: { 13 | method: 'GET' 14 | }, 15 | update: { 16 | method: 'PUT' 17 | }, 18 | deleteEntity: { 19 | method: 'DELETE' 20 | } 21 | }); 22 | 23 | return HxlTagEndpoint; 24 | 25 | }]; 26 | -------------------------------------------------------------------------------- /legacy/app/common/services/endpoints/notification.js: -------------------------------------------------------------------------------- 1 | module.exports = [ 2 | '$resource', 3 | 'Util', 4 | function ( 5 | $resource, 6 | Util 7 | ) { 8 | 9 | var NotificationEndpoint = $resource(Util.apiUrl('/notifications/:id'), { 10 | id: '@id' 11 | }, { 12 | query: { 13 | method: 'GET', 14 | isArray: true, 15 | transformResponse: function (data /*, header*/) { 16 | return angular.fromJson(data).results; 17 | } 18 | }, 19 | get: { 20 | method: 'GET', 21 | // Short term fix to handle boucing to login when unviewable 22 | // notification is returned 23 | params: {'ignore403': '@ignore403'} 24 | }, 25 | update: { 26 | method: 'PUT' 27 | }, 28 | delete: { 29 | method: 'DELETE' 30 | } 31 | }); 32 | 33 | return NotificationEndpoint; 34 | }]; 35 | -------------------------------------------------------------------------------- /legacy/app/common/services/endpoints/post-lock-endpoint.js: -------------------------------------------------------------------------------- 1 | module.exports = [ 2 | '$resource', 3 | '$rootScope', 4 | 'Util', 5 | '_', 6 | '$http', 7 | function ( 8 | $resource, 9 | $rootScope, 10 | Util, 11 | _, 12 | $http 13 | ) { 14 | 15 | var PostLockEndpoint = $resource(Util.apiUrl('/posts/:post_id/lock/'), { 16 | post_id: '@post_id' 17 | }, { 18 | getLock: { 19 | method: 'PUT' 20 | }, 21 | unlockByPost: { 22 | method: 'DELETE' 23 | }, 24 | unlock: { 25 | method: 'DELETE' 26 | }, 27 | options: { 28 | method: 'OPTIONS' 29 | } 30 | }); 31 | 32 | return PostLockEndpoint; 33 | 34 | }]; 35 | -------------------------------------------------------------------------------- /legacy/app/common/services/endpoints/savedsearch.js: -------------------------------------------------------------------------------- 1 | module.exports = [ 2 | '$resource', 3 | 'Util', 4 | function ( 5 | $resource, 6 | Util 7 | ) { 8 | 9 | var SavedSearchEndpoint = $resource(Util.apiUrl('/savedsearches/:id'), { 10 | id: '@id' 11 | }, { 12 | query: { 13 | method: 'GET', 14 | isArray: true, 15 | transformResponse: function (data /*, header*/) { 16 | return angular.fromJson(data).results; 17 | } 18 | }, 19 | get: { 20 | method: 'GET' 21 | }, 22 | update: { 23 | method: 'PUT' 24 | }, 25 | delete: { 26 | method: 'DELETE' 27 | } 28 | }); 29 | 30 | return SavedSearchEndpoint; 31 | 32 | }]; 33 | -------------------------------------------------------------------------------- /legacy/app/common/services/endpoints/sdk/CategoriesSdk.js: -------------------------------------------------------------------------------- 1 | module.exports = [ 2 | 'Util', 3 | 'Session', 4 | 'UshahidiSdk', 5 | function ( 6 | Util, 7 | Session, 8 | UshahidiSdk 9 | ) { 10 | 11 | let _ushahidi = null; 12 | 13 | const ushahidi = function () { 14 | if (_ushahidi) { return _ushahidi; } 15 | return new UshahidiSdk.Categories( 16 | Util.url(''), 17 | Session.getSessionDataEntry('accessToken'), 18 | Session.getSessionDataEntry('accessTokenExpires') 19 | ); 20 | } 21 | 22 | const getCategories = function(id) { 23 | return ushahidi() 24 | .getCategories(id); 25 | } 26 | 27 | const saveCategory = function(category) { 28 | return ushahidi() 29 | .saveCategory(category); 30 | } 31 | 32 | const deleteCategory = function(id) { 33 | return ushahidi() 34 | .deleteCategory(id); 35 | } 36 | 37 | return { getCategories, saveCategory, deleteCategory }; 38 | }]; 39 | -------------------------------------------------------------------------------- /legacy/app/common/services/endpoints/sdk/UtilsSdk.js: -------------------------------------------------------------------------------- 1 | module.exports = [ 2 | 'Util', 3 | 'UshahidiSdk', 4 | function ( 5 | Util, 6 | UshahidiSdk 7 | ) { 8 | 9 | const url = Util.url(''); 10 | const getLanguages = function() { 11 | return UshahidiSdk.getLanguages(url); 12 | } 13 | 14 | return {getLanguages}; 15 | }]; 16 | -------------------------------------------------------------------------------- /legacy/app/common/services/features.js: -------------------------------------------------------------------------------- 1 | module.exports = [ 2 | 'ConfigEndpoint', 3 | 'Util', 4 | '$q', 5 | function ( 6 | ConfigEndpoint, 7 | Util, 8 | $q 9 | ) { 10 | 11 | var Features = { 12 | features: undefined, 13 | loadFeatures: function () { 14 | var deferred = $q.defer(); 15 | if (Features.features) { 16 | deferred.resolve(Features.features); 17 | } else { 18 | ConfigEndpoint.getFresh({id: 'features'}).$promise.then(function (features) { 19 | Features.features = features; 20 | deferred.resolve(Features.features); 21 | }); 22 | } 23 | return deferred.promise; 24 | }, 25 | isFeatureEnabled: function (feature) { 26 | return Features.features[feature].enabled; 27 | }, 28 | isViewEnabled: function (view) { 29 | return Features.features.views[view]; 30 | }, 31 | getLimit: function (feature) { 32 | return Features.features.limits[feature]; 33 | } 34 | }; 35 | 36 | return Util.bindAllFunctionsToSelf(Features); 37 | }]; 38 | -------------------------------------------------------------------------------- /legacy/app/common/services/import-complete.html: -------------------------------------------------------------------------------- 1 |

2 | Your CSV import is complete. {{processed}} records imported, {{errors}} records failed. 3 |

4 |

5 | The data from your CSV spreadsheet, {{filename}}, was successfully imported into your {{form_name}} survey. 6 |

7 | See imported posts 8 | Import another CSV file 9 | 12 | -------------------------------------------------------------------------------- /legacy/app/common/services/import.notify.service.js: -------------------------------------------------------------------------------- 1 | module.exports = ImportNotify; 2 | 3 | var scope; 4 | 5 | ImportNotify.$inject = ['_', '$q', '$rootScope', '$translate', 'SliderService']; 6 | function ImportNotify(_, $q, $rootScope, $translate, SliderService) { 7 | return { 8 | importComplete: importComplete 9 | }; 10 | 11 | function importComplete(values) { 12 | var scope = getScope(); 13 | 14 | scope = _.extend(scope, values); 15 | 16 | showSlider(); 17 | 18 | function showSlider() { 19 | SliderService.openTemplate(require('./import-complete.html'), 'thumb-up', 'confirmation', scope, false, false); 20 | } 21 | } 22 | 23 | function getScope() { 24 | if (scope) { 25 | scope.$destroy(); 26 | } 27 | scope = $rootScope.$new(); 28 | return scope; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /legacy/app/common/services/languages.js: -------------------------------------------------------------------------------- 1 | module.exports = [ 2 | '$http', 3 | function ( 4 | $http 5 | ) { 6 | 7 | // Get translated languages if they have been downloaded from https://www.transifex.com/api/2/languages 8 | const languages = require('../locales/languages.json') 9 | return { 10 | getLanguages: function () { 11 | if (languages.languages && languages.languages.length > 0) { 12 | return languages.languages; 13 | } else { 14 | return [ 15 | { 16 | 'rtl': false, 17 | 'pluralequation': 'language.pluralequation', 18 | 'code': 'en', 19 | 'name': 'English', 20 | 'nplurals': 2 21 | } 22 | ]; 23 | } 24 | } 25 | } 26 | }]; 27 | -------------------------------------------------------------------------------- /legacy/app/common/user-profile/account-settings.directive.js: -------------------------------------------------------------------------------- 1 | module.exports = [ 2 | '$rootScope', 3 | 'UserEndpoint', 4 | 'ModalService', 5 | function ( 6 | $rootScope, 7 | UserEndpoint, 8 | ModalService 9 | ) { 10 | return { 11 | restrict: 'E', 12 | replace: true, 13 | scope: {}, 14 | template: require('./account_settings.html'), 15 | link: function (scope) { 16 | scope.user = UserEndpoint.getFresh({id: 'me'}); 17 | 18 | scope.general = true; 19 | scope.notifications = false; 20 | 21 | scope.showGeneral = function () { 22 | scope.general = true; 23 | scope.notifications = false; 24 | }; 25 | 26 | scope.showNotifications = function () { 27 | scope.general = false; 28 | scope.notifications = true; 29 | }; 30 | 31 | scope.$on('event:close', function () { 32 | ModalService.close(); 33 | }); 34 | } 35 | }; 36 | }]; 37 | -------------------------------------------------------------------------------- /legacy/app/common/user-profile/account_settings.html: -------------------------------------------------------------------------------- 1 |
2 | 5 | 6 | 20 | 21 | 25 |
26 | -------------------------------------------------------------------------------- /legacy/app/common/user-profile/admin-user-setup.directive.js: -------------------------------------------------------------------------------- 1 | module.exports = [ 2 | '$rootScope', 3 | 'ModalService', 4 | function ( 5 | $rootScope, 6 | ModalService 7 | ) { 8 | return { 9 | restrict: 'E', 10 | replace: true, 11 | scope: {}, 12 | template: require('./admin-user-setup.html'), 13 | link: function (scope) { 14 | scope.$on('event:close', function () { 15 | ModalService.close(); 16 | }); 17 | } 18 | }; 19 | }]; 20 | -------------------------------------------------------------------------------- /legacy/app/common/user-profile/admin-user-setup.html: -------------------------------------------------------------------------------- 1 |
2 | 5 |
-------------------------------------------------------------------------------- /legacy/app/common/user-profile/user-profile-module.js: -------------------------------------------------------------------------------- 1 | angular.module('ushahidi.user-profile', []) 2 | .directive('accountSettings', require('./account-settings.directive.js')) 3 | .directive('adminUserSetup', require('./admin-user-setup.directive')) 4 | .directive('userProfile', require('./user-profile.directive.js')) 5 | .directive('notifications', require('./notifications.directive.js')) 6 | ; 7 | -------------------------------------------------------------------------------- /legacy/app/common/verifier/verifier.service.js: -------------------------------------------------------------------------------- 1 | module.exports = [ 2 | 'Verifier', 3 | 'Notify', 4 | '$rootScope', 5 | 'Util', 6 | function ( 7 | Verifier, 8 | Notify, 9 | $rootScope, 10 | Util 11 | ) { 12 | return { 13 | debugModeCheck: function () { 14 | Verifier.checkDebugMode(Util.apiUrl('/verifier/db')) 15 | .then(function (result) { 16 | if (result) { 17 | Notify.notifyPermanent(`You have debug-mode switched on. If you are an admin of this deployment, 18 | we recommend you disable this check and NOT leaving it enabled in the API. 19 | You may disable the check by running the "composer installdebug:disable" command in the API folder.`); 20 | } 21 | }); 22 | } 23 | }; 24 | } 25 | ]; 26 | 27 | -------------------------------------------------------------------------------- /legacy/app/data/add-post-text-button.html: -------------------------------------------------------------------------------- 1 | 10 | 11 | 20 | -------------------------------------------------------------------------------- /legacy/app/data/collection-toggle/collection-toggle-button.html: -------------------------------------------------------------------------------- 1 | 7 | -------------------------------------------------------------------------------- /legacy/app/data/collection-toggle/collection-toggle-button.js: -------------------------------------------------------------------------------- 1 | module.exports = [ 2 | '$rootScope', 3 | '_', 4 | 'CollectionsService', 5 | function ( 6 | $rootScope, 7 | _, 8 | CollectionsService 9 | ) { 10 | return { 11 | restrict: 'E', 12 | replace: true, 13 | scope: { 14 | posts: '=', 15 | selectedPosts: '=', 16 | onDone: '&' 17 | }, 18 | link: function ($scope, $element, $attrs, ngModel) { 19 | $scope.toggleCollection = function () { 20 | // Reduce set of post of objects to only those currently selected 21 | var selectedPostObjects = _.filter($scope.posts, function (post) { 22 | return _.contains($scope.selectedPosts, post.id); 23 | }); 24 | 25 | CollectionsService.showAddToCollection(selectedPostObjects); 26 | // Trigger done handler (clear selected posts) 27 | $scope.onDone(); 28 | }; 29 | }, 30 | template: require('./collection-toggle-button.html') 31 | }; 32 | }]; 33 | -------------------------------------------------------------------------------- /legacy/app/data/common/post-edit-create/post-datetime-value.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | 5 | 9 | 10 | 11 |
12 |
13 |
14 | -------------------------------------------------------------------------------- /legacy/app/data/common/post-edit-create/video.html: -------------------------------------------------------------------------------- 1 | 2 |
3 |
4 |

Enter a video URL from Youtube or Vimeo. 5 |

6 | 7 | 8 |
9 |
10 | 11 |
12 |
13 |
14 |
-------------------------------------------------------------------------------- /legacy/app/data/common/post-edit-detail-create/post-entity.service.js: -------------------------------------------------------------------------------- 1 | module.exports = [ 2 | 'CONST', 3 | function ( 4 | CONST 5 | ) { 6 | return function (data) { 7 | return angular.extend({}, { 8 | // id: 0, 9 | title: '', 10 | description: '', 11 | locale: CONST.DEFAULT_LOCALE, 12 | post_content: [], 13 | completed_stages: [], 14 | published_to: [], 15 | post_date: new Date(), 16 | enabled_languages: {} 17 | }, data); 18 | }; 19 | }]; 20 | -------------------------------------------------------------------------------- /legacy/app/data/common/post-edit-detail-create/survey-language-selector.directive.js: -------------------------------------------------------------------------------- 1 | module.exports = SurveyLanguageSelector; 2 | 3 | SurveyLanguageSelector.$inject = [ 4 | ]; 5 | 6 | function SurveyLanguageSelector() { 7 | return { 8 | restrict: 'E', 9 | scope: { 10 | languages:'=', 11 | title: '=' 12 | }, 13 | controller: SurveyLanguageSelectorController, 14 | template: require('./survey-language-selector.html') 15 | }; 16 | } 17 | 18 | SurveyLanguageSelectorController.$inject = ['$scope']; 19 | 20 | function SurveyLanguageSelectorController($scope) { 21 | 22 | $scope.changeLanguage = changeLanguage; 23 | 24 | 25 | function changeLanguage(language) { 26 | $scope.languages.active = language; 27 | $scope.languages.default = language; 28 | } 29 | }; 30 | -------------------------------------------------------------------------------- /legacy/app/data/common/post-edit-detail/post-messages-reply.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 |
5 | 6 |
7 |
8 | 12 |
13 |
14 |
15 | 16 | 17 | -------------------------------------------------------------------------------- /legacy/app/data/post-create/main.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /legacy/app/data/post-create/post-create.controller.js: -------------------------------------------------------------------------------- 1 | module.exports = [ 2 | '$scope', 3 | '$translate', 4 | '$location', 5 | '$controller', 6 | '$transition$', 7 | 'PostEntity', 8 | 'PostEndpoint', 9 | function ( 10 | $scope, 11 | $translate, 12 | $location, 13 | $controller, 14 | $transition$, 15 | postEntity, 16 | PostEndpoint 17 | ) { 18 | $translate('post.create_post').then(function (title) { 19 | $scope.title = title; 20 | $scope.$emit('setPageTitle', title); 21 | }); 22 | 23 | $scope.post = postEntity(); 24 | 25 | PostEndpoint.options().$promise.then(function (options) { 26 | $scope.post.allowed_privileges = options.allowed_privileges; 27 | }); 28 | $scope.formId = $transition$.params().id; 29 | }]; 30 | -------------------------------------------------------------------------------- /legacy/app/data/post-detail/add-form.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |

post.unstructured.add_survey.title

4 |
5 | 6 |
7 |

8 |
9 | 10 |
11 |
12 | 13 | post.unstructured.add_survey.choose 14 | 15 | 16 |
17 | 18 | 19 |
20 |
21 | 22 |
23 | 29 |
30 |
31 |
32 | -------------------------------------------------------------------------------- /legacy/app/data/post-detail/map.html: -------------------------------------------------------------------------------- 1 | 2 |
3 |

{{label}}

4 |
5 |

{{ feature.geometry.coordinates[1] }}, {{ feature.geometry.coordinates[0] }}

6 |
7 | -------------------------------------------------------------------------------- /legacy/app/data/post-detail/post-category-value.directive.js: -------------------------------------------------------------------------------- 1 | module.exports = PostCategoryValue; 2 | 3 | PostCategoryValue.$inject = []; 4 | 5 | function PostCategoryValue() { 6 | return { 7 | restrict: 'E', 8 | controller: PostCategoryValueController, 9 | scope: { 10 | categories: '=', 11 | activeLanguage:'=' 12 | }, 13 | template: require('./post-category-value.html') 14 | }; 15 | } 16 | PostCategoryValueController.$inject = ['$scope', '_']; 17 | 18 | function PostCategoryValueController($scope, _) { 19 | // Make a list of parent category ids referenced by categories in the list 20 | let parent_ids = _.uniq(_.without(_.pluck($scope.categories, 'parent_id'), null)); 21 | $scope.display = $scope.categories.filter(f => { 22 | // Hide categories that have been marked as inaccessible by the API 23 | if (_.isUndefined(f._ush_hidden)) { 24 | // Hide categories that have been referenced as their parent categories by some 25 | // other category in the list 26 | if (!parent_ids.includes(f.id)) { 27 | return f; 28 | } 29 | } 30 | }); 31 | function activate() {} 32 | activate(); 33 | } 34 | -------------------------------------------------------------------------------- /legacy/app/data/post-detail/post-category-value.html: -------------------------------------------------------------------------------- 1 |

2 | 3 | 4 | 5 | 6 | {{category.translations[activeLanguage].tag || category.tag}}, 7 | 8 |

9 | -------------------------------------------------------------------------------- /legacy/app/data/post-detail/post-lock.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 | 5 | 6 |
7 | 8 |
9 |

The post is locked because Seth Hall is working on it right now. Try editing a different post.

10 |

The post is locked because Seth Hall is working on it right now. Click the unlock button to break lock.

11 | 12 |
13 | 14 |
15 |
16 |
17 | -------------------------------------------------------------------------------- /legacy/app/data/post-detail/post-media-value.directive.js: -------------------------------------------------------------------------------- 1 | module.exports = ['MediaEndpoint', '_', function (MediaEndpoint, _) { 2 | return { 3 | restrict: 'E', 4 | replace: true, 5 | scope: { 6 | mediaId: '=', 7 | label: '@', 8 | mediaHasCaption: '=' 9 | }, 10 | template: require('./post-media-value.html'), 11 | link: MediaValueLink 12 | }; 13 | 14 | function MediaValueLink($scope) { 15 | function loadMedia() { 16 | $scope.mediaLoaded = true; 17 | if ($scope.mediaId) { 18 | $scope.mediaLoaded = false; 19 | MediaEndpoint.get({id: $scope.mediaId}).$promise.then(function (media) { 20 | $scope.media = media; 21 | $scope.mediaLoaded = true; 22 | }); 23 | } 24 | } 25 | loadMedia(); 26 | 27 | $scope.$watch('mediaId', function (newMediaId, oldMediaId) { 28 | if (newMediaId !== oldMediaId) { 29 | loadMedia(); 30 | } 31 | }); 32 | } 33 | 34 | }]; 35 | -------------------------------------------------------------------------------- /legacy/app/data/post-detail/post-media-value.html: -------------------------------------------------------------------------------- 1 |
2 |

3 | {{label}} 4 |

5 | 13 | 14 |

{{ media.caption }}

15 |
16 | -------------------------------------------------------------------------------- /legacy/app/data/post-detail/post-video-value.directive.js: -------------------------------------------------------------------------------- 1 | module.exports = PostVideoValue; 2 | 3 | PostVideoValue.$inject = []; 4 | 5 | function PostVideoValue() { 6 | return { 7 | restrict: 'E', 8 | scope: { 9 | videoUrl: '=', 10 | label: '@' 11 | }, 12 | template: require('./post-video-value.html'), 13 | controller: PostVideoValueController 14 | }; 15 | } 16 | 17 | PostVideoValueController.$inject = [ 18 | '$scope', 19 | '$sce' 20 | ]; 21 | 22 | function PostVideoValueController( 23 | $scope, 24 | $sce 25 | ) { 26 | activate(); 27 | 28 | function activate() { 29 | if ($scope.videoUrl && $scope.videoUrl.length > 0) { 30 | $scope.videoUrl = $sce.trustAsResourceUrl($scope.videoUrl); 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /legacy/app/data/post-detail/post-video-value.html: -------------------------------------------------------------------------------- 1 |
2 |

3 | {{label}} 4 |

5 |
6 | {{videoUrl}} 7 | 8 |
9 |
10 | -------------------------------------------------------------------------------- /legacy/app/data/post-view.service.js: -------------------------------------------------------------------------------- 1 | module.exports = [ 2 | '_', 3 | 'Util', 4 | '$translate', 5 | '$rootScope', 6 | 'SliderService', 7 | function ( 8 | _, 9 | Util, 10 | $translate, 11 | $rootScope, 12 | SliderService 13 | ) { 14 | var scope; 15 | 16 | var PostViewService = { 17 | showNoPostsSlider: function () { 18 | var scope = getScope(); 19 | // TODO review translation sanitization 20 | $translate(['post.there_are_no_posts', 'post.in_this_deployment']).then(function (noPostText) { 21 | scope.noPostText = noPostText; 22 | SliderService.openTemplate( 23 | '

{{noPostText["post.there_are_no_posts"]}}{{noPostText["post.in_this_deployment"]}}

' + 24 | '' + 25 | '', 26 | 'file', false, scope, false, false, true); 27 | }); 28 | 29 | } 30 | }; 31 | 32 | function getScope() { 33 | if (scope) { 34 | scope.$destroy(); 35 | } 36 | scope = $rootScope.$new(); 37 | return scope; 38 | } 39 | 40 | return Util.bindAllFunctionsToSelf(PostViewService); 41 | }]; 42 | -------------------------------------------------------------------------------- /legacy/app/data/services/message.js: -------------------------------------------------------------------------------- 1 | module.exports = [ 2 | '$resource', 3 | 'Util', 4 | function ( 5 | $resource, 6 | Util 7 | ) { 8 | 9 | var MessageEndpoint = $resource(Util.apiUrl('/messages/:id'), { 10 | id: '@id' 11 | }, { 12 | query: { 13 | method: 'GET', 14 | isArray: true, 15 | transformResponse: function (data /*, header*/) { 16 | return angular.fromJson(data); 17 | } 18 | }, 19 | get: { 20 | method: 'GET' 21 | }, 22 | allInThread: { 23 | method: 'GET', 24 | params: { 25 | contact: '@contact', 26 | offset: '@offset', 27 | limit: '@limit', 28 | order: 'asc', 29 | orderby: 'created' 30 | }, 31 | isArray: false, 32 | transformResponse: function (data /*, header*/) { 33 | return angular.fromJson(data); 34 | } 35 | }, 36 | save: { 37 | method: 'POST' 38 | } 39 | }); 40 | 41 | return MessageEndpoint; 42 | }]; 43 | -------------------------------------------------------------------------------- /legacy/app/index.html: -------------------------------------------------------------------------------- 1 |
6 | 7 | Skip to content 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 |
18 | -------------------------------------------------------------------------------- /legacy/app/map/directives/overflow-toggle.js: -------------------------------------------------------------------------------- 1 | module.exports = OverflowToggleDirective; 2 | 3 | OverflowToggleDirective.$inject = ['$parse']; 4 | function OverflowToggleDirective($parse) { 5 | return { 6 | restrict: 'A', 7 | link: OverflowToggleController 8 | }; 9 | 10 | function OverflowToggleController($scope, $element, $attrs) { 11 | var toggle = $element[0].querySelector('.form-field-toggle'); 12 | var hasOverflow = angular.bind({}, $parse($attrs.hasOverflow), $scope); 13 | 14 | $scope.$watch(hasOverflow, function (hasOverflow) { 15 | $element.toggleClass('has-overflow', hasOverflow); 16 | }); 17 | 18 | angular.element(toggle).on('click', function ($event) { 19 | $event.preventDefault(); 20 | hasOverflow() ? $element.toggleClass('show-overflow') : ''; 21 | }); 22 | } 23 | } 24 | 25 | -------------------------------------------------------------------------------- /legacy/app/map/mode-context/filter-by-survey-dropdown.directive.js: -------------------------------------------------------------------------------- 1 | module.exports = FilterBySurveryDropdownDirective; 2 | 3 | FilterBySurveryDropdownDirective.$inject = []; 4 | function FilterBySurveryDropdownDirective() { 5 | return { 6 | restrict: 'A', 7 | replace: true, 8 | controller: FilterBySurveryDropdownController 9 | }; 10 | } 11 | 12 | FilterBySurveryDropdownController.$inject = ['$scope', '$rootScope']; 13 | function FilterBySurveryDropdownController($scope, $rootScope) { 14 | 15 | $scope.filtersMenuOpen = false; 16 | 17 | activate(); 18 | 19 | function activate() { 20 | $rootScope.$on('filters:open:dropdown', function () { 21 | externalOpenDropDown(); 22 | }); 23 | } 24 | 25 | function externalOpenDropDown() { 26 | $scope.filtersMenuOpen = true; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /legacy/app/map/mode-context/mode-context.directive.js: -------------------------------------------------------------------------------- 1 | module.exports = ModeContext; 2 | 3 | ModeContext.$inject = []; 4 | 5 | function ModeContext() { 6 | return { 7 | restrict: 'E', 8 | scope: { 9 | filters: '=' 10 | }, 11 | controller: ModeContextController, 12 | template: require('./mode-context.html') 13 | }; 14 | } 15 | 16 | ModeContextController.$inject = [ 17 | '$scope' 18 | ]; 19 | function ModeContextController( 20 | $scope 21 | ) { 22 | 23 | activate(); 24 | 25 | function activate() { 26 | 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /legacy/app/map/mode-context/mode-context.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |

4 | 5 |
6 | 7 | 13 | 14 |
15 |

16 | 17 | 18 | 19 |
20 |
21 | -------------------------------------------------------------------------------- /legacy/app/map/post-card/collection-toggle/collection-toggle-link.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Add to collection 6 | 7 | -------------------------------------------------------------------------------- /legacy/app/map/post-card/collection-toggle/collection-toggle-link.js: -------------------------------------------------------------------------------- 1 | module.exports = [ 2 | '$rootScope', 3 | 'CollectionsService', 4 | function ( 5 | $rootScope, 6 | CollectionsService 7 | ) { 8 | return { 9 | restrict: 'E', 10 | replace: true, 11 | scope: { 12 | post: '=' 13 | }, 14 | link: function ($scope, $element, $attrs, ngModel) { 15 | $scope.toggleCollection = function () { 16 | // Collection toggle expects an array of posts 17 | CollectionsService.showAddToCollection([$scope.post]); 18 | }; 19 | }, 20 | template: require('./collection-toggle-link.html') 21 | }; 22 | }]; 23 | -------------------------------------------------------------------------------- /legacy/app/map/post-card/post-preview-media.html: -------------------------------------------------------------------------------- 1 |
2 | {{ media.caption }} 3 | 4 |
5 | 6 | -------------------------------------------------------------------------------- /legacy/app/map/post-toolbar/add-post/add-post-button.html: -------------------------------------------------------------------------------- 1 |
2 | 11 |
12 | -------------------------------------------------------------------------------- /legacy/app/map/post-toolbar/add-post/add-post-survey-list.directive.js: -------------------------------------------------------------------------------- 1 | module.exports = AddPostSurveyListDirective; 2 | 3 | AddPostSurveyListDirective.$inject = []; 4 | 5 | function AddPostSurveyListDirective() { 6 | return { 7 | restrict: 'E', 8 | scope: true, 9 | controller: AddPostSurveyListController, 10 | template: require('./add-post-survey-list.html') 11 | }; 12 | } 13 | 14 | AddPostSurveyListController.$inject = [ 15 | '$scope', 16 | '$location', 17 | 'TranslationService' 18 | ]; 19 | 20 | function AddPostSurveyListController( 21 | $scope, 22 | $location, 23 | TranslationService 24 | ) { 25 | 26 | $scope.handleClick = handleClick; 27 | TranslationService.getLanguage().then(language=>{ 28 | $scope.userLanguage = language; 29 | }); 30 | 31 | function handleClick(form) { 32 | $scope.closeMainsheet(); 33 | $location.path('posts/create/' + form.id); 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /legacy/app/map/post-toolbar/add-post/add-post-survey-list.html: -------------------------------------------------------------------------------- 1 | 10 | -------------------------------------------------------------------------------- /legacy/app/map/post-toolbar/filters/filter-date.directive.js: -------------------------------------------------------------------------------- 1 | module.exports = DateSelectDirective; 2 | 3 | DateSelectDirective.$inject = []; 4 | function DateSelectDirective() { 5 | return { 6 | restrict: 'E', 7 | scope: { 8 | dateBeforeModel: '=', 9 | dateAfterModel: '=' 10 | }, 11 | controller: DateSelectController, 12 | template: require('./filter-date.html') 13 | }; 14 | } 15 | 16 | DateSelectController.$inject = ['$scope', '$rootScope', 'Flatpickr']; 17 | function DateSelectController($scope, $rootScope, Flatpickr) { 18 | let pickers = Flatpickr('.flatpickr', {}); 19 | 20 | function pauseTrap() { 21 | $rootScope.$broadcast('event:pauseTrap', true); 22 | } 23 | 24 | function unPauseTrap() { 25 | $rootScope.$broadcast('event:pauseTrap', false); 26 | } 27 | 28 | // There are multiple pickers because of start/end-date in filters 29 | pickers.forEach((picker) => { 30 | if (picker.config) { 31 | if (picker.config.onOpen) { 32 | picker.config.onOpen.push(pauseTrap); 33 | } 34 | if (picker.config.onClose) { 35 | picker.config.onClose.push(unPauseTrap); 36 | } 37 | } 38 | }); 39 | } 40 | -------------------------------------------------------------------------------- /legacy/app/map/post-toolbar/filters/filter-form.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 |
5 | 8 |
9 |
10 | 15 |
16 |
17 | 20 |
21 |
22 | -------------------------------------------------------------------------------- /legacy/app/map/post-toolbar/filters/filter-has-location.directive.js: -------------------------------------------------------------------------------- 1 | 2 | module.exports = FilterHasLocationDirective; 3 | 4 | FilterHasLocationDirective.$inject = []; 5 | 6 | function FilterHasLocationDirective() { 7 | return { 8 | restrict: 'E', 9 | replace: true, 10 | scope: { 11 | hasLocation: '=' 12 | }, 13 | require: 'ngModel', 14 | link: FilterHasLocationLink, 15 | template: require('./filter-has-location.html') 16 | }; 17 | } 18 | 19 | function FilterHasLocationLink($scope, $element, $attrs, ngModel) { 20 | activate(); 21 | function activate() { 22 | $scope.$watch('hasLocation', saveToView, true); 23 | } 24 | 25 | function saveToView(hasLocation) { 26 | ngModel.$setViewValue(angular.copy(hasLocation)); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /legacy/app/map/post-toolbar/filters/filter-has-location.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | 5 | 12 |
13 |
14 | 15 | 22 |
23 |
24 | 25 | 32 |
33 |
34 | -------------------------------------------------------------------------------- /legacy/app/map/post-toolbar/filters/filter-location.html: -------------------------------------------------------------------------------- 1 |
2 | Location 3 | 4 |
5 |
6 | 7 | 8 | 9 | 10 |
11 |
12 | 13 |
14 | 21 |
22 | 23 |
24 | 25 | -------------------------------------------------------------------------------- /legacy/app/map/post-toolbar/filters/filter-post-order-asc-desc.html: -------------------------------------------------------------------------------- 1 |
2 | 6 |
7 | -------------------------------------------------------------------------------- /legacy/app/map/post-toolbar/filters/filter-post-sorting-options.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | 10 |
11 |
12 |
13 | -------------------------------------------------------------------------------- /legacy/app/map/post-toolbar/filters/filter-saved-search.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | 13 |
14 | 15 |
16 |
17 | 18 | 26 |
27 | -------------------------------------------------------------------------------- /legacy/app/map/post-toolbar/filters/filter-status.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 |
5 | 6 | 23 |
24 |
25 | -------------------------------------------------------------------------------- /legacy/app/map/post-toolbar/filters/filter-unlocked-on-top.directive.js: -------------------------------------------------------------------------------- 1 | module.exports = FilterUnlockedOnTopDirective; 2 | 3 | FilterUnlockedOnTopDirective.$inject = [ 4 | '_' 5 | ]; 6 | function FilterUnlockedOnTopDirective(_) { 7 | return { 8 | restrict: 'E', 9 | require: 'ngModel', 10 | template: require('./filter-unlocked-on-top.html'), 11 | scope: {}, 12 | link: FilterUnlockedOnTopDirectiveLink 13 | }; 14 | function FilterUnlockedOnTopDirectiveLink($scope, $element, $attrs, ngModel) { 15 | $scope.unlockedOnTop = { 16 | value: 'true', 17 | labelTranslateKey: 'global_filter.sort.unlockedOnTop.filter_type_tag' 18 | }; 19 | 20 | function activate() { 21 | ngModel.$render = renderModelValue; 22 | $scope.$watch('unlockedOnTop', saveToView, true); 23 | } 24 | 25 | function renderModelValue() { 26 | $scope.unlockedOnTop = { 27 | value: ngModel.$viewValue, 28 | labelTranslateKey: 'global_filter.sort.unlockedOnTop.filter_type_tag' 29 | }; 30 | } 31 | activate(); 32 | function saveToView(unlockedOnTop) { 33 | ngModel.$setViewValue(angular.copy(unlockedOnTop ? unlockedOnTop.value.toString() : '')); 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /legacy/app/map/post-toolbar/filters/filter-unlocked-on-top.html: -------------------------------------------------------------------------------- 1 |
2 | 9 |
-------------------------------------------------------------------------------- /legacy/app/map/post-toolbar/share/post-export.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /legacy/app/map/post-toolbar/share/post-share.html: -------------------------------------------------------------------------------- 1 | 14 | -------------------------------------------------------------------------------- /legacy/app/map/post-toolbar/share/share-menu-modal.directive.js: -------------------------------------------------------------------------------- 1 | module.exports = ShareMenuDirective; 2 | 3 | ShareMenuDirective.$inject = []; 4 | function ShareMenuDirective() { 5 | return { 6 | restrict: 'E', 7 | scope: { 8 | surveyId: '=', 9 | postId: '=', 10 | filters: '=' 11 | }, 12 | replace: true, 13 | controller: ShareMenuController, 14 | template: require('./share-menu-modal.html') 15 | }; 16 | } 17 | 18 | ShareMenuController.$inject = [ 19 | '$scope', 20 | '$window' 21 | ]; 22 | function ShareMenuController( 23 | $scope, 24 | $window 25 | ) { 26 | } 27 | -------------------------------------------------------------------------------- /legacy/app/map/post-toolbar/share/share-menu-modal.html: -------------------------------------------------------------------------------- 1 | 4 | -------------------------------------------------------------------------------- /legacy/app/map/post-toolbar/sort-and-filter-counter.directive.js: -------------------------------------------------------------------------------- 1 | module.exports = SortAndFilterCounterDirective; 2 | 3 | SortAndFilterCounterDirective.$inject = ['PostFilters']; 4 | function SortAndFilterCounterDirective(PostFilters) { 5 | return { 6 | restrict: 'E', 7 | scope: {}, 8 | link: SortAndFilterCounterDirectiveLink, 9 | template: require('./sort-and-filter-counter.html') 10 | }; 11 | 12 | function SortAndFilterCounterDirectiveLink($scope, $element, $attrs, ngModel) { 13 | $scope.$watch(function () { 14 | return PostFilters.countFilters(); 15 | }, handleFiltersUpdate, true); 16 | 17 | function handleFiltersUpdate() { 18 | $scope.filtersCount = PostFilters.countFilters(); 19 | } 20 | } 21 | 22 | } 23 | 24 | -------------------------------------------------------------------------------- /legacy/app/map/post-toolbar/sort-and-filter-counter.html: -------------------------------------------------------------------------------- 1 | 2 | {{filtersCount}} 3 | app.sort_filter 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /legacy/app/map/post-view-map.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 |
5 | 6 |
7 |
8 |
9 |
10 |
11 |
12 | -------------------------------------------------------------------------------- /legacy/app/map/post-view-noui.controller.js: -------------------------------------------------------------------------------- 1 | module.exports = PostViewNouiController; 2 | 3 | PostViewNouiController.$inject = ['$scope', '$rootScope', '$translate', '$transition$', 'PostFilters']; 4 | function PostViewNouiController($scope, $rootScope, $translate, $transition$, PostFilters) { 5 | $rootScope.setLayout('layout-embed'); 6 | $scope.filters = PostFilters.getFilters(); 7 | $scope.$emit('event:allposts:show'); 8 | } 9 | -------------------------------------------------------------------------------- /legacy/app/map/post-view-noui.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 |
-------------------------------------------------------------------------------- /legacy/app/map/services/view-helper.js: -------------------------------------------------------------------------------- 1 | module.exports = [ 2 | '$translate', 3 | function ( 4 | $translate 5 | ) { 6 | var allViews = [ 7 | { 8 | name: 'map', 9 | display_name: $translate.instant('views.map') 10 | }, 11 | { 12 | name: 'data', 13 | display_name: $translate.instant('views.data') 14 | } 15 | ]; 16 | 17 | function views() { 18 | return allViews; 19 | } 20 | 21 | return { 22 | views: views 23 | }; 24 | }]; 25 | -------------------------------------------------------------------------------- /legacy/app/mode-bar/mode-bar.module.js: -------------------------------------------------------------------------------- 1 | angular.module('ushahidi.modebar', []) 2 | 3 | .directive('modeBar', require('./mode-bar.directive.js')) 4 | .directive('ushLogo', require('./ush-logo.directive.js')) 5 | 6 | .run([ 7 | '$templateCache', 8 | function ($templateCache) { 9 | $templateCache.put( 10 | 'mode-bar/ushahidi-logo.html', 11 | require('./ushahidi-logo.html') 12 | ); 13 | } 14 | ]); 15 | -------------------------------------------------------------------------------- /legacy/app/mode-bar/support-links.html: -------------------------------------------------------------------------------- 1 | 4 | 5 | 17 | 18 | -------------------------------------------------------------------------------- /legacy/app/mode-bar/ush-logo.directive.js: -------------------------------------------------------------------------------- 1 | module.exports = UshLogoDirective; 2 | 3 | UshLogoDirective.$inject = []; 4 | function UshLogoDirective() { 5 | return { 6 | restrict: 'E', 7 | controller: UshLogoController, 8 | replace: true, 9 | template: require('./ush-logo.html') 10 | }; 11 | } 12 | 13 | UshLogoController.$inject = []; 14 | function UshLogoController() { 15 | } 16 | -------------------------------------------------------------------------------- /legacy/app/mode-bar/ush-logo.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /legacy/app/settings/categories/category-translation-editor.directive.js: -------------------------------------------------------------------------------- 1 | module.exports = CategoryTranslationEditor; 2 | 3 | CategoryTranslationEditor.$inject = []; 4 | function CategoryTranslationEditor() { 5 | return { 6 | restrict: 'E', 7 | scope: { 8 | activeLanguage: '=', 9 | category:'=', 10 | defaultLanguage:'=' 11 | }, 12 | controller: CategoryTranslationEditorController, 13 | template: require('./category-translation-editor.html') 14 | }; 15 | } 16 | 17 | CategoryTranslationEditorController.$inject = []; 18 | function CategoryTranslationEditorController() { 19 | } 20 | -------------------------------------------------------------------------------- /legacy/app/settings/data-import/data-after-import.controller.js: -------------------------------------------------------------------------------- 1 | module.exports = [ 2 | '$scope', 3 | '$rootScope', 4 | '$location', 5 | '$translate', 6 | '$q', 7 | '_', 8 | function ( 9 | $scope, 10 | $rootScope, 11 | $location, 12 | $translate, 13 | $q, 14 | _ 15 | ) { 16 | 17 | // Redirect to home if not authorized 18 | if ($rootScope.hasManageSettingsPermission() === false) { 19 | return $location.path('/'); 20 | } 21 | 22 | // Change layout class 23 | $rootScope.setLayout('layout-c'); 24 | // Change mode 25 | $scope.$emit('event:mode:change', 'settings'); 26 | }]; 27 | -------------------------------------------------------------------------------- /legacy/app/settings/data-import/data-after-import.directive.js: -------------------------------------------------------------------------------- 1 | module.exports = [ 2 | '$rootScope', 3 | '$translate', 4 | '$location', 5 | function ( 6 | $rootScope, 7 | $translate, 8 | $location 9 | ) { 10 | return { 11 | restrict: 'A', 12 | link: function ($scope, $element, $attrs) { 13 | $scope.importComplete = false; 14 | 15 | $rootScope.$on('event:import:complete', function (event, args) { 16 | $scope.collectionId = args.collectionId; 17 | $scope.filename = args.filename; 18 | $scope.importComplete = true; 19 | }); 20 | } 21 | }; 22 | }]; 23 | -------------------------------------------------------------------------------- /legacy/app/settings/data-import/data-import.controller.js: -------------------------------------------------------------------------------- 1 | module.exports = [ 2 | '$scope', 3 | '$rootScope', 4 | '$location', 5 | '$translate', 6 | 'FormEndpoint', 7 | '_', 8 | function ( 9 | $scope, 10 | $rootScope, 11 | $location, 12 | $translate, 13 | FormEndpoint, 14 | _ 15 | ) { 16 | // Redirect to home if not authorized 17 | if ($rootScope.hasManageSettingsPermission() === false) { 18 | return $location.path('/'); 19 | } 20 | 21 | // Change layout class 22 | $rootScope.setLayout('layout-c'); 23 | // Change mode 24 | $scope.$emit('event:mode:change', 'settings'); 25 | 26 | $scope.fileContainer = { 27 | file: null 28 | }; 29 | 30 | FormEndpoint.queryFresh().$promise.then(function (response) { 31 | $scope.forms = response; 32 | }); 33 | } 34 | ]; 35 | -------------------------------------------------------------------------------- /legacy/app/settings/datasources/gmail-auth.directive.js: -------------------------------------------------------------------------------- 1 | module.exports = GmailAuthDirective; 2 | 3 | GmailAuthDirective.$inject = []; 4 | function GmailAuthDirective() { 5 | return { 6 | restrict: 'E', 7 | scope: true, 8 | controller: GmailAuthController, 9 | template: require('./gmail-auth.html') 10 | }; 11 | } 12 | GmailAuthController.$inject = [ 13 | '$scope' 14 | ]; 15 | function GmailAuthController( 16 | $scope 17 | ) { 18 | $scope.processing = false; 19 | $scope.code = ''; 20 | 21 | $scope.submit = submit; 22 | $scope.cancel = cancel; 23 | 24 | $scope.processing = false; 25 | 26 | function submit() { 27 | $scope.processing = true; 28 | $scope.$parent.authorizeGmailProvider($scope.code, $scope.date) 29 | .finally(function () { 30 | $scope.processing = false; 31 | $scope.$parent.closeModal(); 32 | }) 33 | } 34 | 35 | function cancel() { 36 | $scope.$parent.closeModal(); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /legacy/app/settings/directives/color-picker.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Ushahidi Angular Color Picker directive 3 | * Drop in directive for color picking 4 | */ 5 | 6 | module.exports = [ 7 | function () { 8 | var controller = [ 9 | '$scope', 10 | '$translate', 11 | function ( 12 | $scope, 13 | $translate 14 | ) { 15 | // Set default color 16 | $scope.color = '#eee'; 17 | // Update local color when inbound color is changed 18 | $scope.$watch('colorContainer.color', function () { 19 | if ($scope.colorContainer.color) { 20 | $scope.color = $scope.colorContainer.color.replace('#', ''); 21 | } 22 | }); 23 | 24 | $scope.setColor = function (color) { 25 | $scope.colorContainer.color = color.indexOf('#') > -1 ? color : '#' + color; 26 | }; 27 | } 28 | ]; 29 | return { 30 | restrict: 'E', 31 | replace: true, 32 | template: require('./color-picker.html'), 33 | scope: { 34 | colorContainer: '=' 35 | }, 36 | controller: controller 37 | }; 38 | } 39 | ]; 40 | -------------------------------------------------------------------------------- /legacy/app/settings/directives/filter-system/filter-role.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | 12 |
13 |
14 | -------------------------------------------------------------------------------- /legacy/app/settings/directives/filter-system/filter-role.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Ushahidi Angular Filter System role directive 3 | * Drop in directive responsible for role selection 4 | * for filtering 5 | */ 6 | 7 | module.exports = [ 8 | function ( 9 | ) { 10 | var controller = [ 11 | '$scope', 12 | '$rootScope', 13 | '$translate', 14 | 'RoleEndpoint', 15 | function ( 16 | $scope, 17 | $rootScope, 18 | $translate, 19 | RoleEndpoint 20 | ) { 21 | RoleEndpoint.query().$promise.then(function (roles) { 22 | $scope.roles = roles; 23 | }); 24 | }]; 25 | return { 26 | restrict: 'E', 27 | replace: true, 28 | template: require('./filter-role.html'), 29 | scope: { 30 | model: '=' 31 | }, 32 | controller: controller 33 | }; 34 | }]; 35 | -------------------------------------------------------------------------------- /legacy/app/settings/directives/loading-dots.directive.js: -------------------------------------------------------------------------------- 1 | module.exports = LoadingDotsDirective; 2 | 3 | LoadingDotsDirective.$inject = []; 4 | 5 | function LoadingDotsDirective() { 6 | return { 7 | restrict: 'E', 8 | scope: { 9 | buttonClass: '@', 10 | label: '=', 11 | disabled: '=' 12 | }, 13 | controller: LoadingDotsController, 14 | template: require('./loading-dots.html') 15 | }; 16 | } 17 | LoadingDotsController.$inject = ['$scope']; 18 | 19 | function LoadingDotsController($scope) { 20 | } 21 | -------------------------------------------------------------------------------- /legacy/app/settings/directives/loading-dots.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 |
6 | -------------------------------------------------------------------------------- /legacy/app/settings/donation/donation.controller.js: -------------------------------------------------------------------------------- 1 | module.exports = [ 2 | '$scope', 3 | '$rootScope', 4 | '$location', 5 | '$translate', 6 | '_', 7 | function ($scope, $rootScope, $location, $translate, _) { 8 | // Redirect to home if not authorized 9 | if ($rootScope.hasManageSettingsPermission() === false) { 10 | return $location.path('/'); 11 | } 12 | 13 | // Change layout class 14 | $rootScope.setLayout('layout-c'); 15 | // Change mode 16 | $scope.$emit('event:mode:change', 'settings'); 17 | } 18 | ]; 19 | -------------------------------------------------------------------------------- /legacy/app/settings/roles/roles.controller.js: -------------------------------------------------------------------------------- 1 | module.exports = [ 2 | '$scope', 3 | '$translate', 4 | '$rootScope', 5 | '$location', 6 | function ( 7 | $scope, 8 | $translate, 9 | $rootScope, 10 | $location 11 | ) { 12 | 13 | // Redirect to home if not authorized 14 | if ($rootScope.hasManageSettingsPermission() === false) { 15 | return $location.path('/'); 16 | } 17 | 18 | $translate('tool.manage_roles').then(function (title) { 19 | $scope.title = title; 20 | $scope.$emit('setPageTitle', title); 21 | }); 22 | // Change mode 23 | $scope.$emit('event:mode:change', 'settings'); 24 | 25 | }]; 26 | -------------------------------------------------------------------------------- /legacy/app/settings/roles/roles.directive.js: -------------------------------------------------------------------------------- 1 | module.exports = [ 2 | '$translate', 3 | '$rootScope', 4 | '$location', 5 | 'RoleEndpoint', 6 | '_', 7 | 'Features', 8 | function ( 9 | $translate, 10 | $rootScope, 11 | $location, 12 | RoleEndpoint, 13 | _, 14 | Features 15 | ) { 16 | return { 17 | restrict: 'A', 18 | link: function ($scope, $element, $attrs) { 19 | $rootScope.setLayout('layout-a'); 20 | $scope.refreshView = function () { 21 | RoleEndpoint.queryFresh().$promise.then(function (roles) { 22 | $scope.roles = roles; 23 | }); 24 | }; 25 | 26 | $scope.refreshView(); 27 | Features.loadFeatures().then(function () { 28 | $scope.rolesEnabled = Features.isFeatureEnabled('roles'); 29 | }); 30 | } 31 | }; 32 | }]; 33 | -------------------------------------------------------------------------------- /legacy/app/settings/services/accessibility.service.js: -------------------------------------------------------------------------------- 1 | module.exports = AccessibilityService; 2 | function AccessibilityService() { 3 | return { 4 | setFocus 5 | }; 6 | function setFocus(id) { 7 | return document.getElementById(id).focus(); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /legacy/app/settings/services/endpoints/apikey.js: -------------------------------------------------------------------------------- 1 | module.exports = [ 2 | '$resource', 3 | '$rootScope', 4 | 'Util', 5 | function ( 6 | $resource, 7 | $rootScope, 8 | Util 9 | ) { 10 | 11 | var ApiKeyEndpoint = $resource(Util.apiUrl('/apikeys/:id'), { 12 | id: '@id' 13 | }, { 14 | query: { 15 | method: 'GET', 16 | isArray: true, 17 | transformResponse: function (data /*, header*/) { 18 | return Util.transformResponse(data).results; 19 | } 20 | }, 21 | get: { 22 | method: 'GET' 23 | }, 24 | update: { 25 | method: 'PUT' 26 | } 27 | }); 28 | 29 | return ApiKeyEndpoint; 30 | 31 | }]; 32 | -------------------------------------------------------------------------------- /legacy/app/settings/services/endpoints/country-code-endpoint.js: -------------------------------------------------------------------------------- 1 | module.exports = [ 2 | '$resource', 3 | 'Util', 4 | 'CacheFactory', 5 | function ( 6 | $resource, 7 | Util, 8 | CacheFactory 9 | ) { 10 | var cache; 11 | if (!(cache = CacheFactory.get('countryCodes'))) { 12 | cache = CacheFactory.createCache('countryCodes'); 13 | } 14 | cache.removeExpired(); 15 | 16 | var CountryCodeEndpoint = $resource(Util.apiUrl('/country-codes/'), { 17 | }, { 18 | query: { 19 | method: 'GET', 20 | isArray: true, 21 | cache: cache, 22 | transformResponse: function (data) { 23 | return Util.transformResponse(data).results; 24 | } 25 | } 26 | }); 27 | 28 | return CountryCodeEndpoint; 29 | }]; 30 | -------------------------------------------------------------------------------- /legacy/app/settings/services/endpoints/form-contact.js: -------------------------------------------------------------------------------- 1 | module.exports = [ 2 | '$resource', 3 | 'Util', 4 | 'CacheFactory', 5 | function ( 6 | $resource, 7 | Util, 8 | CacheFactory 9 | ) { 10 | var cache; 11 | 12 | if (!(cache = CacheFactory.get('formContactCache'))) { 13 | cache = CacheFactory.createCache('formContactCache'); 14 | } 15 | cache.removeExpired(); 16 | 17 | var FormContactEndpoint = $resource(Util.apiUrl('/forms/:formId/contacts/'), { 18 | formId: '@formId' 19 | }, { 20 | query: { 21 | method: 'GET', 22 | isArray: true, 23 | cache: cache 24 | }, 25 | get: { 26 | method: 'GET', 27 | cache: cache 28 | }, 29 | update: { 30 | method: 'PUT' 31 | } 32 | }); 33 | return FormContactEndpoint; 34 | }]; 35 | -------------------------------------------------------------------------------- /legacy/app/settings/services/endpoints/hxl-license-endpoint.js: -------------------------------------------------------------------------------- 1 | module.exports = [ 2 | '$resource', 3 | 'Util', 4 | function ( 5 | $resource, 6 | Util 7 | ) { 8 | 9 | var HxlLicenseEndpoint = $resource(Util.apiUrl('/hxl/licenses'), { 10 | id: '@id' 11 | }, { 12 | get: { 13 | method: 'GET' 14 | }, 15 | update: { 16 | method: 'PUT' 17 | }, 18 | deleteEntity: { 19 | method: 'DELETE' 20 | } 21 | }); 22 | 23 | return HxlLicenseEndpoint; 24 | 25 | }]; 26 | -------------------------------------------------------------------------------- /legacy/app/settings/services/endpoints/hxl-metadata-endpoint.js: -------------------------------------------------------------------------------- 1 | module.exports = [ 2 | '$resource', 3 | 'Util', 4 | function ( 5 | $resource, 6 | Util 7 | ) { 8 | 9 | var HxlMetadataEndpoint = $resource(Util.apiUrl('/hxl/metadata'), { 10 | id: '@id' 11 | }, { 12 | get: { 13 | method: 'GET' 14 | }, 15 | update: { 16 | method: 'PUT' 17 | }, 18 | deleteEntity: { 19 | method: 'DELETE' 20 | } 21 | }); 22 | 23 | return HxlMetadataEndpoint; 24 | 25 | }]; 26 | -------------------------------------------------------------------------------- /legacy/app/settings/services/endpoints/hxl-organisations-endpoint.js: -------------------------------------------------------------------------------- 1 | module.exports = [ 2 | '$resource', 3 | 'Util', 4 | function ( 5 | $resource, 6 | Util 7 | ) { 8 | 9 | var HxlOrganisationsEndpoint = $resource(Util.apiUrl('/hxl/organisations'), { 10 | id: '@id' 11 | }, { 12 | get: { 13 | method: 'GET' 14 | }, 15 | update: { 16 | method: 'PUT' 17 | }, 18 | deleteEntity: { 19 | method: 'DELETE' 20 | } 21 | }); 22 | 23 | return HxlOrganisationsEndpoint; 24 | 25 | }]; 26 | -------------------------------------------------------------------------------- /legacy/app/settings/services/endpoints/permission.js: -------------------------------------------------------------------------------- 1 | module.exports = [ 2 | '$resource', 3 | 'Util', 4 | 'CacheFactory', 5 | function ( 6 | $resource, 7 | Util, 8 | CacheFactory 9 | ) { 10 | var cache; 11 | 12 | if (!(cache = CacheFactory.get('permissionCache'))) { 13 | cache = CacheFactory.createCache('permissionCache'); 14 | } 15 | cache.removeExpired(); 16 | 17 | var PermissionEndpoint = $resource(Util.apiUrl('/permissions/:id'), { 18 | id: '@id' 19 | }, { 20 | query: { 21 | method: 'GET', 22 | transpermissionResponse: function (data /*, header*/) { 23 | return Util.transformResponse(data).results; 24 | } 25 | }, 26 | get: { 27 | method: 'GET', 28 | cache: cache 29 | } 30 | }); 31 | 32 | PermissionEndpoint.getFresh = function (params) { 33 | cache.remove(Util.apiUrl('/permissions/' + params.id)); 34 | return PermissionEndpoint.get(params); 35 | }; 36 | 37 | PermissionEndpoint.invalidateCache = function () { 38 | return cache.removeAll(); 39 | }; 40 | 41 | PermissionEndpoint.queryFresh = function () { 42 | cache.removeAll(); 43 | return PermissionEndpoint.query(); 44 | }; 45 | 46 | return PermissionEndpoint; 47 | 48 | }]; 49 | -------------------------------------------------------------------------------- /legacy/app/settings/settings.controller.js: -------------------------------------------------------------------------------- 1 | module.exports = [ 2 | '$scope', 3 | '$translate', 4 | '$location', 5 | '$rootScope', 6 | function ( 7 | $scope, 8 | $translate, 9 | $location, 10 | $rootScope 11 | ) { 12 | 13 | // Redirect to home if not authorized 14 | if ($rootScope.hasManageSettingsPermission() === false) { 15 | return $location.path('/'); 16 | } 17 | 18 | $translate('tool.settings').then(function (title) { 19 | $scope.title = title; 20 | $scope.$emit('setPageTitle', title); 21 | }); 22 | // Change mode 23 | $scope.$emit('event:mode:change', 'settings'); 24 | }]; 25 | -------------------------------------------------------------------------------- /legacy/app/settings/settings.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /legacy/app/settings/site/settings-general.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /legacy/app/settings/site/site.controller.js: -------------------------------------------------------------------------------- 1 | module.exports = [ 2 | '$scope', 3 | '$rootScope', 4 | '$location', 5 | '$translate', 6 | function ( 7 | $scope, 8 | $rootScope, 9 | $location, 10 | $translate 11 | ) { 12 | 13 | // Redirect to home if not authorized 14 | if ($rootScope.hasManageSettingsPermission() === false) { 15 | return $location.path('/'); 16 | } 17 | 18 | $rootScope.setLayout('layout-a'); 19 | $translate('tool.site_settings').then(function (title) { 20 | $scope.title = title; 21 | $rootScope.$emit('setPageTitle', title); 22 | }); 23 | // Change mode 24 | $scope.$emit('event:mode:change', 'settings'); 25 | 26 | }]; 27 | -------------------------------------------------------------------------------- /legacy/app/settings/surveys/attribute-create.html: -------------------------------------------------------------------------------- 1 | 10 | -------------------------------------------------------------------------------- /legacy/app/settings/surveys/edit.controller.js: -------------------------------------------------------------------------------- 1 | module.exports = [ 2 | '$scope', 3 | '$rootScope', 4 | '$transition$', 5 | function ( 6 | $scope, 7 | $rootScope, 8 | $transition$ 9 | ) { 10 | $scope.surveyId = $transition$.params().id; 11 | $scope.actionType = $transition$.params().action; 12 | }]; 13 | -------------------------------------------------------------------------------- /legacy/app/settings/surveys/survey-edit.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /legacy/app/settings/surveys/survey-success.html: -------------------------------------------------------------------------------- 1 |

2 | {{successText}} 3 |

4 | 5 | Add to survey 6 | 9 | -------------------------------------------------------------------------------- /legacy/app/settings/surveys/survey-translation-editor.directive.js: -------------------------------------------------------------------------------- 1 | module.exports = SurveyTranslationEditor; 2 | 3 | SurveyTranslationEditor.$inject = []; 4 | function SurveyTranslationEditor() { 5 | return { 6 | restrict: 'E', 7 | scope: { 8 | activeLanguage: '=', 9 | survey:'=', 10 | defaultLanguage:'=' 11 | }, 12 | controller: SurveyTranslationEditorController, 13 | template: require('./survey-translation-editor.html') 14 | }; 15 | } 16 | 17 | SurveyTranslationEditorController.$inject = ['$rootScope', '$scope', 'ModalService','_']; 18 | function SurveyTranslationEditorController($rootScope, $scope, ModalService, _) { 19 | $scope.openField = openField; 20 | $scope.form = {}; 21 | $rootScope.$on('event:surveys:translationMissing', function () { 22 | $scope.form.translation.$setDirty(); 23 | }); 24 | 25 | function openField(field, task) { 26 | $scope.activeTask = task; 27 | if (!field.translations[$scope.activeLanguage]) { 28 | field.translations[$scope.activeLanguage] = {} 29 | } 30 | $scope.translateField = field; 31 | ModalService.openTemplate('', 'translations.translate_field', '', $scope, true, true); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /legacy/app/settings/surveys/survey.notify.service.js: -------------------------------------------------------------------------------- 1 | module.exports = SurveyNotify; 2 | 3 | var scope; 4 | 5 | SurveyNotify.$inject = ['_', '$q', '$rootScope', '$translate', 'SliderService']; 6 | function SurveyNotify(_, $q, $rootScope, $translate, SliderService) { 7 | return { 8 | success: success 9 | }; 10 | 11 | function success(successText, translateValues, values) { 12 | var scope = getScope(); 13 | 14 | function showSlider(successText) { 15 | values.successText = successText; 16 | scope = _.extend(scope, values); 17 | 18 | SliderService.openTemplate(require('./survey-success.html'), 'thumb-up', 'confirmation', scope, false, false); 19 | } 20 | 21 | $translate(successText, translateValues).then(showSlider, showSlider); 22 | } 23 | 24 | function getScope() { 25 | if (scope) { 26 | scope.$destroy(); 27 | } 28 | scope = $rootScope.$new(); 29 | return scope; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /legacy/app/settings/surveys/task-create.directive.js: -------------------------------------------------------------------------------- 1 | module.exports = [ 2 | '$rootScope', 3 | 'ModalService', 4 | function ( 5 | $rootScope, 6 | ModalService 7 | ) { 8 | return { 9 | restrict: 'E', 10 | template: require('./task-create.html'), 11 | link: function ($scope, $element, $attrs) { 12 | 13 | // Init an empty saved search 14 | $scope.newTask = { 15 | required : false, 16 | fields: [], 17 | type: 'task', 18 | show_when_published: false, 19 | task_is_internal_only: true 20 | }; 21 | 22 | $scope.closeModal = function () { 23 | ModalService.close(); 24 | }; 25 | } 26 | }; 27 | }]; 28 | -------------------------------------------------------------------------------- /legacy/app/settings/users/filter-users.directive.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Ushahidi Angular Filter System User directive 3 | * Drop in directive for managing filters for users 4 | */ 5 | 6 | module.exports = [ 7 | function ( 8 | ) { 9 | var controller = [ 10 | '$scope', 11 | '$rootScope', 12 | '$translate', 13 | '$timeout', 14 | '_', 15 | function ( 16 | $scope, 17 | $rootScope, 18 | $translate, 19 | $timeout, 20 | _ 21 | ) { 22 | $scope.filtersMenuOpen = false; 23 | $scope.cancel = function () { 24 | // Reset filters 25 | $scope.usersFiltersForm.$rollbackViewValue(); 26 | // and close dropdown 27 | $scope.filtersMenuOpen = false; 28 | }; 29 | 30 | $scope.applyFilters = function () { 31 | // ngFormController automatically commits changes to the model ($scope.filters) 32 | // Just close the dropdown 33 | $scope.filtersMenuOpen = false; 34 | }; 35 | }]; 36 | return { 37 | restrict: 'E', 38 | replace: true, 39 | template: require('./filter-users.html'), 40 | scope: { 41 | filters: '=' 42 | }, 43 | controller: controller 44 | }; 45 | }]; 46 | -------------------------------------------------------------------------------- /legacy/app/settings/webhooks/webhooks.controller.js: -------------------------------------------------------------------------------- 1 | module.exports = [ 2 | '$scope', 3 | '$translate', 4 | '$rootScope', 5 | '$location', 6 | function ( 7 | $scope, 8 | $translate, 9 | $rootScope, 10 | $location 11 | ) { 12 | 13 | // Redirect to home if not authorized 14 | if ($rootScope.hasManageSettingsPermission() === false) { 15 | return $location.path('/'); 16 | } 17 | 18 | $translate('tool.manage_webhooks').then(function (title) { 19 | $scope.title = title; 20 | $scope.$emit('setPageTitle', title); 21 | }); 22 | // Change mode 23 | $scope.$emit('event:mode:change', 'settings'); 24 | 25 | }]; 26 | -------------------------------------------------------------------------------- /legacy/app/settings/webhooks/webhooks.directive.js: -------------------------------------------------------------------------------- 1 | module.exports = [ 2 | '$translate', 3 | '$rootScope', 4 | '$location', 5 | 'WebhookEndpoint', 6 | '_', 7 | 'Features', 8 | function ( 9 | $translate, 10 | $rootScope, 11 | $location, 12 | WebhookEndpoint, 13 | _, 14 | Features 15 | ) { 16 | return { 17 | restrict: 'A', 18 | link: function ($scope, $element, $attrs) { 19 | $rootScope.setLayout('layout-a'); 20 | 21 | $scope.refreshView = function () { 22 | WebhookEndpoint.queryFresh().$promise.then(function (webhooks) { 23 | $scope.webhooks = webhooks; 24 | }); 25 | }; 26 | 27 | $scope.refreshView(); 28 | Features.loadFeatures().then(function () { 29 | $scope.webhooksEnabled = Features.isFeatureEnabled('webhooks'); 30 | }); 31 | } 32 | }; 33 | }]; 34 | -------------------------------------------------------------------------------- /legacy/app/test-bootstrap.js: -------------------------------------------------------------------------------- 1 | require('./app'); 2 | window.ushahidi.bootstrapConfig = require('../mocked_backend/api/v3/config.json').results; 3 | // Just bootstrap the app immediately 4 | angular.bootstrap(document, ['app'], { 5 | strictDi: true 6 | }); 7 | -------------------------------------------------------------------------------- /legacy/mocked_backend/api/v3/config/features.json: -------------------------------------------------------------------------------- 1 | 2 | { 3 | "id": "features", 4 | "url": "http://localhost:8081/api/v2/config/features", 5 | "views": { 6 | "map": true, 7 | "list": true, 8 | "chart": true, 9 | "timeline": true, 10 | "activity": true 11 | }, 12 | "data-providers": { 13 | "smssync": true, 14 | "twitter": true, 15 | "frontlinesms": true, 16 | "email": true, 17 | "twilio": true, 18 | "nexmo": true 19 | }, 20 | "limits": { 21 | "posts": true, 22 | "forms": true, 23 | "admin_users": true 24 | }, 25 | "private": { 26 | "enabled": true 27 | }, 28 | "roles": { 29 | "enabled": true 30 | }, 31 | "webhooks": { 32 | "enabled": true 33 | }, 34 | "data-import": { 35 | "enabled": true 36 | }, 37 | "targeted-surveys": { 38 | "enabled": true 39 | }, 40 | "csv-speedup": { 41 | "enabled": true 42 | }, 43 | "user-settings": { 44 | "enabled": true 45 | }, 46 | "anonymise-reporters": { 47 | "enabled": true 48 | }, 49 | "hxl": { 50 | "enabled": true 51 | }, 52 | "allowed_privileges": [ 53 | "read", 54 | "search" 55 | ] 56 | } 57 | -------------------------------------------------------------------------------- /legacy/mocked_backend/api/v3/config/map.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "map", 3 | "url":"http://localhost:8081/api/v2/config/map", 4 | "clustering": false, 5 | "cluster_radius": 50, 6 | "location_precision":2, 7 | "default_view": { 8 | "lat": -1.3048035, 9 | "lon": 36.8473969, 10 | "zoom": 2, 11 | "baselayer": "MapQuest", 12 | "fit_map_boundaries": true, 13 | "icon": "map-marker", 14 | "color": "blue" 15 | }, 16 | "allowed_privileges": [ 17 | "read", 18 | "search" 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /legacy/mocked_backend/api/v3/config/site.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "site", 3 | "name": "Ushahidi Mock", 4 | "description": "Ushahidi testing deployment", 5 | "email": "someone@somewhere.somehow", 6 | "timezone": "UTC", 7 | "language": "en-US", 8 | "date_format": "n/j/Y", 9 | "client_url": false, 10 | "first_login": true, 11 | "tier": "free", 12 | "private": false, 13 | "allowed_methods": { 14 | "get": true, 15 | "post": true, 16 | "put": true, 17 | "delete": true 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /legacy/mocked_backend/api/v3/forms/1.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 1, 3 | "url": "http://192.168.33.110/api/v3/forms/1", 4 | "parent_id": null, 5 | "name": "Test Form", 6 | "description": "Testing form", 7 | "type": "report", 8 | "disabled": false, 9 | "created": "1970-01-01T00:00:00+00:00", 10 | "updated": "2015-11-30T15:09:53+00:00", 11 | "allowed_privileges": [ 12 | "read", 13 | "create", 14 | "update", 15 | "delete", 16 | "search" 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /legacy/mocked_backend/api/v3/forms/3.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 3, 3 | "url": "http://192.168.33.110/api/v3/forms/3", 4 | "parent_id": null, 5 | "name": "new test title", 6 | "description": "new test description", 7 | "type": "report", 8 | "disabled": false, 9 | "created": "1970-01-01T00:00:00+00:00", 10 | "updated": "2015-11-30T15:09:53+00:00", 11 | "allowed_privileges": [ 12 | "read", 13 | "create", 14 | "update", 15 | "delete", 16 | "search" 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /legacy/mocked_backend/api/v3/posts/999.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "9999", 3 | "url": "http://localhost:8081/api/v2/posts/9999", 4 | "parent": null, 5 | "user": null, 6 | "title": "Post without a type and form id (could be a message)", 7 | "slug": null, 8 | "content": "Some description", 9 | "author_email": null, 10 | "author_realname": null, 11 | "status": "published", 12 | "created": "1970-01-01T00:00:00+00:00", 13 | "updated": null, 14 | "locale": "en_us", 15 | "values": { 16 | "last_location_point": [ 17 | { 18 | "id": "3", 19 | "value": { 20 | "lon": 10.123, 21 | "lat": 26.213 22 | } 23 | } 24 | ] 25 | }, 26 | "tags": [ 27 | 28 | ], 29 | "allowed_methods": { 30 | "get": true, 31 | "post": true, 32 | "put": true, 33 | "delete": true 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /legacy/mocked_backend/api/v3/stages/4.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 4, 3 | "url": "http://192.168.33.110/api/v3/form_stages/1", 4 | "form_id": 1, 5 | "label": "4th step", 6 | "priority": 99, 7 | "icon": null, 8 | "required": false, 9 | "allowed_privileges": [ 10 | "read", 11 | "create", 12 | "update", 13 | "delete", 14 | "search" 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /legacy/mocked_backend/api/v3/users/me.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 2, 3 | "url": "http://ushahidi-backend/api/v2/users/2", 4 | "email": "admin@ush.com", 5 | "realname": "Admin Joe", 6 | "logins": 0, 7 | "failed_attempts": 0, 8 | "last_login": null, 9 | "last_attempt": null, 10 | "created": "1970-01-01T00:00:00+00:00", 11 | "updated": "2014-12-13T19:17:57+00:00", 12 | "role": "admin", 13 | "allowed_methods": [ 14 | "get", 15 | "post", 16 | "put" 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /legacy/sass/overrides/_dropdown.scss: -------------------------------------------------------------------------------- 1 | .dropdown { 2 | .dropdown-animate { 3 | display: block !important; 4 | opacity: 1 !important; 5 | transition: opacity 0.15s; 6 | } 7 | 8 | .dropdown-animate-flex { 9 | display: flex !important; 10 | opacity: 1 !important; 11 | transition: opacity 0.15s ease-in; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /legacy/sass/overrides/_filters.scss: -------------------------------------------------------------------------------- 1 | .filter-controls { 2 | padding-top: 10px; 3 | padding-bottom: 10px; 4 | text-align: right; 5 | 6 | a.clear-filters { 7 | display: inline-block; 8 | padding: 10px 15px; 9 | 10 | text-transform: none; 11 | font-weight: normal; 12 | letter-spacing: normal; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /legacy/sass/overrides/_intercom.scss: -------------------------------------------------------------------------------- 1 | 2 | .layout-a { 3 | .intercom-launcher-frame, .intercom-lightweight-app-launcher { 4 | right: 13px !important; 5 | @media (max-width: 1150px) { 6 | bottom: 120px !important; 7 | } 8 | } 9 | } 10 | .layout-d { 11 | .intercom-launcher-frame, .intercom-lightweight-app-launcher { 12 | right: 13px !important; 13 | bottom: 80px !important; 14 | @media (max-width: 1023px) { 15 | bottom: 120px !important; 16 | } 17 | } 18 | } 19 | 20 | .intercom-messenger-frame { 21 | right: 100px !important; 22 | } 23 | -------------------------------------------------------------------------------- /legacy/sass/overrides/_modal.scss: -------------------------------------------------------------------------------- 1 | modal { 2 | div.modal { 3 | display: block; 4 | } 5 | 6 | div.modal-detached { 7 | position: absolute; 8 | bottom: 0; right: 0; 9 | width: 0; height: 0; 10 | visibility: hidden; 11 | pointer-events: none; 12 | } 13 | } 14 | 15 | 16 | -------------------------------------------------------------------------------- /legacy/sass/vendor.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Combined vendor stylesheets 3 | */ 4 | 5 | // the 'gulp rename' task is a workaround that duplicates the .css file and 6 | // renames it to .scss, allowing us to essentially import vendor .css. 7 | // 8 | // these files are imported via the 'node-modules include path' in gulpfile.js 9 | // 10 | @import "~leaflet/dist/leaflet"; 11 | @import "~leaflet.markercluster/dist/MarkerCluster"; 12 | @import "~leaflet.markercluster/dist/MarkerCluster.Default"; 13 | @import "~leaflet.locatecontrol/src/L.Control.Locate"; 14 | @import '~@toast-ui/editor/dist/toastui-editor-viewer.css'; // editor's ui 15 | @import '~@toast-ui/editor/dist/toastui-editor.css'; // editor's content 16 | @import '~flatpickr/dist/flatpickr.min.css'; 17 | 18 | 19 | // Custom overrides 20 | @import "overrides/leaflet"; 21 | @import "overrides/filters"; 22 | @import "overrides/modal"; 23 | @import "overrides/intercom"; 24 | @import "overrides/tui-markdown"; 25 | -------------------------------------------------------------------------------- /legacy/test/pre_test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #placeholder -------------------------------------------------------------------------------- /legacy/test/test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -ev 3 | 4 | if [ "${TEST_SUITE}" = "lint" ]; then 5 | npm run eslint 6 | fi 7 | 8 | if [ "${TEST_SUITE}" = "unit" ]; then 9 | NODE_ENV=test gulp test 10 | fi 11 | -------------------------------------------------------------------------------- /legacy/test/unit/common/directives/embed-only.directive.spec.js: -------------------------------------------------------------------------------- 1 | describe('embed only directive', function () { 2 | 3 | var $rootScope, 4 | $compile, 5 | $scope, 6 | $window, 7 | element; 8 | 9 | beforeEach(function () { 10 | fixture.setBase('mocked_backend/api/v3'); 11 | 12 | var testApp = makeTestApp(); 13 | 14 | testApp.directive('embedOnly', require('app/common/directives/embed-only.directive')); 15 | 16 | angular.mock.module('testApp'); 17 | }); 18 | 19 | beforeEach(inject(function (_$rootScope_, _$compile_, _Notify_, _GlobalFilter_, _$window_) { 20 | $rootScope = _$rootScope_; 21 | $compile = _$compile_; 22 | $window = _$window_; 23 | $scope = _$rootScope_.$new(); 24 | $rootScope.globalLayout = 'layout-a'; 25 | $window.self = 'frame'; 26 | $rootScope.setLayout = function () {}; 27 | spyOn($rootScope, 'setLayout').and.callThrough(); 28 | })); 29 | 30 | it('should set the layout', function () { 31 | element = '
'; 32 | element = $compile(element)($scope); 33 | $scope.$digest(); 34 | 35 | }); 36 | }); 37 | -------------------------------------------------------------------------------- /legacy/test/unit/common/directives/file-upload.directive.spec.js: -------------------------------------------------------------------------------- 1 | describe('file upload directive', function () { 2 | 3 | var $rootScope, 4 | $compile, 5 | $scope, 6 | $window, 7 | element; 8 | 9 | beforeEach(function () { 10 | fixture.setBase('mocked_backend/api/v3'); 11 | 12 | var testApp = makeTestApp(); 13 | 14 | testApp.directive('fileUpload', require('app/common/directives/file-upload.directive')); 15 | 16 | angular.mock.module('testApp'); 17 | }); 18 | 19 | beforeEach(inject(function (_$rootScope_, _$compile_, _$window_) { 20 | $rootScope = _$rootScope_; 21 | $compile = _$compile_; 22 | $window = _$window_; 23 | $scope = _$rootScope_.$new(); 24 | $rootScope.globalLayout = 'layout-a'; 25 | $window.self = 'frame'; 26 | $rootScope.setLayout = function () {}; 27 | spyOn($rootScope, 'setLayout').and.callThrough(); 28 | })); 29 | 30 | it('should set the layout', function () { 31 | element = ''; 32 | element = $compile(element)($scope); 33 | $scope.$digest(); 34 | 35 | }); 36 | }); 37 | -------------------------------------------------------------------------------- /legacy/test/unit/common/global/event-handlers-spec.js: -------------------------------------------------------------------------------- 1 | describe('global event handlers', function () { 2 | 3 | var mockedSessionData, 4 | mockedAuthenticationData 5 | ; 6 | 7 | beforeEach(function () { 8 | 9 | var testApp = makeTestApp(), 10 | mockedSessionService = 11 | { 12 | getSessionData: function () { 13 | return mockedSessionData; 14 | }, 15 | getSessionDataEntry: function (key) { 16 | return mockedSessionData[key]; 17 | }, 18 | setSessionDataEntry: function (key, value) { 19 | mockedSessionData[key] = value; 20 | } 21 | }, 22 | mockedAuthenticationService = 23 | { 24 | getLoginStatus: function () { 25 | return mockedAuthenticationData.loginStatus; 26 | }, 27 | logout : function () { 28 | // Just a stub 29 | } 30 | }; 31 | 32 | testApp.service('Session', function () { 33 | return mockedSessionService; 34 | }) 35 | .service('Authentication', function () { 36 | return mockedAuthenticationService; 37 | }) 38 | .run(require('app/common/global/event-handlers.js')); 39 | 40 | 41 | }); 42 | }); 43 | -------------------------------------------------------------------------------- /legacy/test/unit/common/services/features.js: -------------------------------------------------------------------------------- 1 | describe('Features', function () { 2 | 3 | var Features, $rootScope; 4 | 5 | beforeEach(function () { 6 | makeTestApp() 7 | .service('Features', require('app/common/services/features.js')); 8 | 9 | 10 | angular.mock.module('testApp'); 11 | }); 12 | 13 | beforeEach(angular.mock.inject(function (_$rootScope_, _Features_) { 14 | $rootScope = _$rootScope_; 15 | Features = _Features_; 16 | Features.loadFeatures(); 17 | })); 18 | 19 | it('should check if feature is enabled', function () { 20 | expect(Features.isFeatureEnabled('test')).toBe(true); 21 | }); 22 | 23 | it('should check if a view is enabled', function () { 24 | expect(Features.isViewEnabled('test')).toBe(true); 25 | }); 26 | 27 | it('should get a limit for a given feature', function () { 28 | expect(Features.getLimit('test')).toEqual(1); 29 | }); 30 | 31 | it('should reload features', function () { 32 | Features.features = undefined; 33 | Features.loadFeatures(); 34 | 35 | expect(Features.features.limits.test).toEqual(1); 36 | }); 37 | }); 38 | -------------------------------------------------------------------------------- /legacy/test/unit/common/services/view-helper-spec.js: -------------------------------------------------------------------------------- 1 | describe('view helper', function () { 2 | 3 | var ViewHelper; 4 | 5 | beforeEach(function () { 6 | makeTestApp() 7 | .service('ViewHelper', require('app/map/services/view-helper.js')) 8 | .service('ConfigEndpoint', function () { 9 | return { 10 | get : function () {} 11 | }; 12 | }) 13 | .factory('BootstrapConfig', function () { 14 | return { map: {}, site: {}, features: {} }; 15 | }); 16 | 17 | angular.mock.module('testApp'); 18 | }); 19 | 20 | beforeEach(angular.mock.inject(function (_ViewHelper_) { 21 | ViewHelper = _ViewHelper_; 22 | })); 23 | 24 | it('should return view and display name for map and list', function () { 25 | var views = ViewHelper.views(); 26 | expect(_.pluck(views, 'name')).toEqual(['map', 'data']); 27 | expect(_.pluck(views, 'display_name')).toEqual(['views.map', 'views.data']); 28 | }); 29 | }); 30 | -------------------------------------------------------------------------------- /legacy/test/unit/main/post/detail/post-media-value.directive.spec.js: -------------------------------------------------------------------------------- 1 | describe('post media value directive', function () { 2 | 3 | var $rootScope, 4 | $scope, 5 | isolateScope, 6 | MediaEndpoint, 7 | element; 8 | 9 | beforeEach(function () { 10 | fixture.setBase('mocked_backend/api/v3'); 11 | 12 | 13 | var testApp = makeTestApp(); 14 | 15 | testApp.directive('postMediaValue', require('app/data/post-detail/post-media-value.directive')) 16 | .value('$filter', function () { 17 | return function () {}; 18 | }); 19 | 20 | angular.mock.module('testApp'); 21 | }); 22 | 23 | 24 | 25 | beforeEach(angular.mock.inject(function (_$rootScope_, $compile) { 26 | $rootScope = _$rootScope_; 27 | $scope = _$rootScope_.$new(); 28 | 29 | element = ''; 30 | element = $compile(element)($scope); 31 | $rootScope.$digest(); 32 | isolateScope = element.isolateScope(); 33 | })); 34 | 35 | it('should load media properties', angular.mock.inject(function (_MediaEndpoint_) { 36 | MediaEndpoint = _MediaEndpoint_; 37 | 38 | expect(isolateScope.media.caption).toEqual('test caption'); 39 | expect(isolateScope.media.original_file_url).toEqual('http://localhost/test.png'); 40 | })); 41 | }); 42 | -------------------------------------------------------------------------------- /legacy/test/unit/main/post/modify/post-create.controller.spec.js: -------------------------------------------------------------------------------- 1 | describe('Post create controller', function () { 2 | var $scope, $controller; 3 | 4 | beforeEach(function () { 5 | fixture.setBase('mocked_backend/api/v3'); 6 | 7 | makeTestApp() 8 | .value('PostEntity', function () { 9 | return fixture.load('posts/120.json'); 10 | }) 11 | .controller('postCreateController', require('app/data/post-create/post-create.controller.js')) 12 | .service('$transition$', function () { 13 | return { 14 | 'params': function () { 15 | return { 16 | 'id': 1 17 | }; 18 | } 19 | }; 20 | }); 21 | 22 | angular.mock.module('testApp'); 23 | }); 24 | 25 | beforeEach(angular.mock.inject(function (_$rootScope_, _$controller_) { 26 | $scope = _$rootScope_.$new(); 27 | $controller = _$controller_; 28 | 29 | })); 30 | 31 | beforeEach(function () { 32 | $controller('postCreateController', { 33 | $scope: $scope 34 | }); 35 | }); 36 | 37 | it('should load and set options', function () { 38 | expect($scope.post.allowed_privileges[0]).toEqual('read'); 39 | expect($scope.post.form.id).toEqual(1); 40 | }); 41 | }); 42 | -------------------------------------------------------------------------------- /legacy/test/unit/main/post/views/post-card.directive.spec.js: -------------------------------------------------------------------------------- 1 | describe('post card directive', function () { 2 | 3 | var $rootScope, 4 | $scope, 5 | isolateScope, 6 | GlobalFilter, 7 | Notify, 8 | element; 9 | 10 | beforeEach(function () { 11 | fixture.setBase('mocked_backend/api/v3'); 12 | 13 | 14 | var testApp = makeTestApp(); 15 | 16 | testApp.directive('postCard', require('app/map/post-card/post-card.directive')) 17 | .value('$filter', function () { 18 | return function () {}; 19 | }); 20 | 21 | angular.mock.module('testApp'); 22 | }); 23 | 24 | 25 | 26 | beforeEach(angular.mock.inject(function (_$rootScope_, $compile, _Notify_, _GlobalFilter_) { 27 | $rootScope = _$rootScope_; 28 | $scope = _$rootScope_.$new(); 29 | 30 | GlobalFilter = _GlobalFilter_; 31 | Notify = _Notify_; 32 | 33 | $scope.post = fixture.load('posts/120.json'); 34 | 35 | element = ''; 36 | element = $compile(element)($scope); 37 | $scope.$digest(); 38 | isolateScope = element.children().scope(); 39 | })); 40 | 41 | describe('test directive functions', function () { 42 | }); 43 | }); 44 | -------------------------------------------------------------------------------- /legacy/test/unit/mock/controllers/navigation.controller.mock.js: -------------------------------------------------------------------------------- 1 | module.exports = [function () { 2 | this.site = { 3 | name: 'Mock Site' 4 | }; 5 | }]; 6 | -------------------------------------------------------------------------------- /legacy/test/unit/mock/factories/socket-factory.mock.js: -------------------------------------------------------------------------------- 1 | module.exports = [function () { 2 | return { 3 | init: function () { 4 | return; 5 | }, 6 | on: function () { 7 | return; 8 | }, 9 | emnit: function () { 10 | return; 11 | } 12 | }; 13 | }]; 14 | -------------------------------------------------------------------------------- /legacy/test/unit/mock/services/accessibility.service.js: -------------------------------------------------------------------------------- 1 | module.exports = AccessibilityService; 2 | function AccessibilityService() { 3 | return { 4 | setFocus 5 | }; 6 | function setFocus(id) {} 7 | } 8 | -------------------------------------------------------------------------------- /legacy/test/unit/mock/services/authentication.js: -------------------------------------------------------------------------------- 1 | module.exports = [function () { 2 | var mockedAuthenticationData = { 3 | loginStatus: false 4 | }; 5 | return { 6 | setAuthenticationData: function (authenticationData) { 7 | mockedAuthenticationData = authenticationData; 8 | }, 9 | getLoginStatus: function () { 10 | return mockedAuthenticationData.loginStatus; 11 | }, 12 | logout : function () { 13 | // Just a stub 14 | }, 15 | openLogin : function () { 16 | 17 | } 18 | }; 19 | }]; 20 | -------------------------------------------------------------------------------- /legacy/test/unit/mock/services/country-code-endpoint.js: -------------------------------------------------------------------------------- 1 | module.exports = [function () { 2 | return { 3 | query: function () { 4 | return {$promise: { 5 | then: function (successCallback, failCallback) { 6 | successCallback({'results': [{ 7 | id: 1, 8 | country_name: 'testCountry', 9 | dial_code: '+100', 10 | country_code: 'TC' 11 | }]}); 12 | } 13 | }}; 14 | } 15 | }; 16 | }]; 17 | -------------------------------------------------------------------------------- /legacy/test/unit/mock/services/data-export.js: -------------------------------------------------------------------------------- 1 | module.exports = [function () { 2 | return { 3 | startExport: function () {}, 4 | loadExportJob: function () {}, 5 | loadExportJobs: function () { 6 | return { 7 | then: function () {} 8 | }; 9 | } 10 | }; 11 | }]; 12 | -------------------------------------------------------------------------------- /legacy/test/unit/mock/services/data-import.js: -------------------------------------------------------------------------------- 1 | module.exports = [function () { 2 | return { 3 | update: function () { 4 | return {$promise: { 5 | then: function (successCallback, failCallback) { 6 | successCallback({ 7 | name: 'test data-importer', 8 | id: 1 9 | }); 10 | } 11 | }}; 12 | }, 13 | delete: function () { 14 | return {$promise: { 15 | then: function (successCallback) { 16 | successCallback(); 17 | } 18 | }}; 19 | }, 20 | import: function (dataImporter) { 21 | return {$promise: { 22 | then: function (successCallback, failCallback) { 23 | dataImporter.id === 'pass' ? successCallback({id: 1}) : failCallback('error'); 24 | } 25 | }}; 26 | }, 27 | upload: function (formData) { 28 | return { 29 | then: function (successCallback, failCallback) { 30 | successCallback({id: 1}); 31 | } 32 | }; 33 | } 34 | }; 35 | }]; 36 | -------------------------------------------------------------------------------- /legacy/test/unit/mock/services/data-import.service.js: -------------------------------------------------------------------------------- 1 | module.exports = [function () { 2 | return { 3 | startImport: function () {}, 4 | loadImportJob: function () {}, 5 | loadImportJobs: function () { 6 | return { 7 | then: function () {} 8 | }; 9 | }, 10 | processImportJobs: function () {}, 11 | setImportJobs: function () {}, 12 | getImportJobs: function () {} 13 | }; 14 | }]; 15 | 16 | 17 | -------------------------------------------------------------------------------- /legacy/test/unit/mock/services/data-retriever.js: -------------------------------------------------------------------------------- 1 | module.exports = [function () { 2 | return { 3 | setImportData: function (message) { 4 | return {}; 5 | }, 6 | getImportData: function (message) { 7 | return {}; 8 | }, 9 | dataMapperInitialData: function (message) { 10 | return {}; 11 | } 12 | }; 13 | }]; 14 | -------------------------------------------------------------------------------- /legacy/test/unit/mock/services/form-contact.js: -------------------------------------------------------------------------------- 1 | module.exports = [function () { 2 | return { 3 | query: function () { 4 | return {$promise: { 5 | then: function (successCallback, failCallback) { 6 | successCallback([{ 7 | contact: 'test@ushahidi.com', 8 | id: 1 9 | }]); 10 | } 11 | }}; 12 | }, 13 | get: function () { 14 | return {$promise: { 15 | then: function (successCallback) { 16 | successCallback({ 17 | contact: 'test@ushahidi.com', 18 | id: 1 19 | }); 20 | } 21 | }}; 22 | }, 23 | update: function (contact) { 24 | return function (successCallback, failCallback) { 25 | contact.id === 'pass' ? successCallback({id: 1}) : failCallback('error'); 26 | }; 27 | }, 28 | save: function (contact) { 29 | return function (successCallback, failCallback) { 30 | contact.formId === '1' ? successCallback({id: 1}) : failCallback('error'); 31 | }; 32 | } 33 | }; 34 | }]; 35 | -------------------------------------------------------------------------------- /legacy/test/unit/mock/services/form-stats-endpoint.js: -------------------------------------------------------------------------------- 1 | module.exports = [function () { 2 | return { 3 | query: function () { 4 | return {$promise: { 5 | then: function (successCallback, failCallback) { 6 | successCallback({ 7 | total_responses: 9, 8 | total_recipients: 5 9 | }); 10 | } 11 | }}; 12 | } 13 | }; 14 | }]; 15 | -------------------------------------------------------------------------------- /legacy/test/unit/mock/services/global-filters.js: -------------------------------------------------------------------------------- 1 | module.exports = [function () { 2 | return { 3 | tags: [], 4 | form: [], 5 | set: [], 6 | current_stage: [], 7 | getPostQuery: function () { 8 | return { 9 | q: 'dummy' 10 | }; 11 | }, 12 | options: { 13 | tags: {}, 14 | collections: {}, 15 | forms: {} 16 | }, 17 | loadInitialData: function () {}, 18 | getDefaults: function () {}, 19 | setSelected: function () {}, 20 | clearSelected: function () {} 21 | }; 22 | }]; 23 | -------------------------------------------------------------------------------- /legacy/test/unit/mock/services/hxl-export.js: -------------------------------------------------------------------------------- 1 | module.exports = [function () { 2 | return { 3 | getFormsWithTags: function () { 4 | return {$promise: { 5 | then: function (successCallback, failCallback) { 6 | successCallback([{ 7 | name: 'test form', 8 | id: 1, 9 | attributes: [ 10 | { 11 | name: 'test form attributes', 12 | id: 1, 13 | form_stage_id: 1, 14 | priority: 1, 15 | key: 'test_attr1', 16 | type: 'input', 17 | required: false, 18 | tags: [] 19 | } 20 | ] 21 | }]); 22 | } 23 | }}; 24 | } 25 | }; 26 | }]; 27 | -------------------------------------------------------------------------------- /legacy/test/unit/mock/services/importnotify.js: -------------------------------------------------------------------------------- 1 | module.exports = [function () { 2 | return { 3 | importComplete: function (message) { 4 | return { 5 | then: function (successCallback) { 6 | successCallback(); 7 | } 8 | }; 9 | }, 10 | getScope: function () { 11 | return { 12 | then: function (successCallback) { 13 | successCallback(); 14 | } 15 | }; 16 | } 17 | }; 18 | }]; 19 | -------------------------------------------------------------------------------- /legacy/test/unit/mock/services/languages.js: -------------------------------------------------------------------------------- 1 | module.exports = [ 2 | function () { 3 | return { 4 | getLanguages: function() { 5 | return [{ 6 | 'rtl': false, 7 | 'pluralequation': 'language.pluralequation', 8 | 'code': 'en', 9 | 'name': 'English', 10 | 'nplurals': 2 11 | }] 12 | } 13 | } 14 | }]; 15 | -------------------------------------------------------------------------------- /legacy/test/unit/mock/services/loadingProgress.service.js: -------------------------------------------------------------------------------- 1 | module.exports = [function () { 2 | return { 3 | watchTransitions: function () {}, 4 | getLoadingState: function () { 5 | return true; 6 | }, 7 | getSavingState: function () { 8 | return true; 9 | }, 10 | setLoadingState: function () {}, 11 | setSavingState: function () {} 12 | }; 13 | }]; 14 | -------------------------------------------------------------------------------- /legacy/test/unit/mock/services/media-edit-service.js: -------------------------------------------------------------------------------- 1 | module.exports = [function () { 2 | return { 3 | saveMedia: function (media, post) { 4 | return { 5 | then: function (successCallback, failCallback) { 6 | successCallback( 7 | {'results': [{ 8 | id: 1 9 | }] 10 | }); 11 | } 12 | }; 13 | }, 14 | deleteMedia: function () { 15 | return true; 16 | }, 17 | update: function () { 18 | return true; 19 | }, 20 | uploadFile: function (dataImporter) { 21 | return true; 22 | } 23 | }; 24 | }]; 25 | -------------------------------------------------------------------------------- /legacy/test/unit/mock/services/media.js: -------------------------------------------------------------------------------- 1 | module.exports = [function () { 2 | return { 3 | query: function () { 4 | return {$promise: { 5 | then: function (successCallback, failCallback) { 6 | successCallback({'results': [{ 7 | original_file_url: 'http://localhost/test.png', 8 | caption: 'test caption' 9 | }]}); 10 | } 11 | }}; 12 | }, 13 | get: function () { 14 | return {$promise: { 15 | then: function (successCallback) { 16 | successCallback({ 17 | original_file_url: 'http://localhost/test.png', 18 | caption: 'test caption' 19 | }); 20 | } 21 | }}; 22 | }, 23 | delete: function () { 24 | return {$promise: { 25 | then: function (successCallback) { 26 | successCallback(); 27 | } 28 | }}; 29 | } 30 | }; 31 | }]; 32 | -------------------------------------------------------------------------------- /legacy/test/unit/mock/services/modal.service.js: -------------------------------------------------------------------------------- 1 | module.exports = [function () { 2 | return { 3 | openTemplate: function () {}, 4 | openUrl: function () {}, 5 | close: function () {} 6 | }; 7 | }]; 8 | -------------------------------------------------------------------------------- /legacy/test/unit/mock/services/post-actions-service.js: -------------------------------------------------------------------------------- 1 | module.exports = [function () { 2 | return { 3 | delete: function (post) { 4 | return { 5 | then: function () {} 6 | }; 7 | }, 8 | getStatuses: function () { 9 | return ['published', 'draft', 'archived']; 10 | } 11 | }; 12 | }]; 13 | -------------------------------------------------------------------------------- /legacy/test/unit/mock/services/post-edit-service.js: -------------------------------------------------------------------------------- 1 | module.exports = [function () { 2 | return { 3 | cleanPostValues: function (post) { 4 | return post; 5 | }, 6 | cleanTagValues: function (post) { 7 | return post; 8 | }, 9 | validatePost: function () { 10 | return true; 11 | }, 12 | validateVideoUrl: function (url) { 13 | if (url === 'https://www.youtube.com/video/1234') { 14 | return ['https://www.youtube.com/embed/1234', 'https:', 'www.', 'youtube.com', 'be.com', 'embed/', '1234', undefined] 15 | } else { 16 | return null; 17 | } 18 | }, 19 | canSavePost: function () { 20 | return true; 21 | }, 22 | isFirstStage: function (dataImporter) { 23 | return true; 24 | }, 25 | isStageValid: function (formData) { 26 | return true; 27 | } 28 | }; 29 | }]; 30 | -------------------------------------------------------------------------------- /legacy/test/unit/mock/services/post-lock-endpoint.js: -------------------------------------------------------------------------------- 1 | module.exports = [function () { 2 | return { 3 | getLock: function () { 4 | return {$promise: { 5 | then: function (successCallback) { 6 | successCallback(); 7 | } 8 | }}; 9 | }, 10 | unlockByPost: function () { 11 | return {$promise: { 12 | then: function (successCallback) { 13 | successCallback(); 14 | } 15 | }}; 16 | }, 17 | unlock: function () { 18 | return {$promise: { 19 | then: function (successCallback) { 20 | successCallback(); 21 | }, 22 | finally: function (successCallback) { 23 | successCallback(); 24 | } 25 | }}; 26 | }, 27 | options: function () { 28 | return {$promise: { 29 | then: function (successCallback) { 30 | successCallback(); 31 | } 32 | }}; 33 | } 34 | }; 35 | }]; 36 | -------------------------------------------------------------------------------- /legacy/test/unit/mock/services/post-lock.service.js: -------------------------------------------------------------------------------- 1 | module.exports = [function () { 2 | return { 3 | createSocketListener: function () { 4 | return {$promise: { 5 | then: function (successCallback) { 6 | successCallback(); 7 | } 8 | }}; 9 | }, 10 | unlockByPost: function () { 11 | return {$promise: { 12 | then: function (successCallback) { 13 | successCallback(); 14 | } 15 | }}; 16 | }, 17 | unlock: function () { 18 | return {$promise: { 19 | then: function (successCallback) { 20 | successCallback(); 21 | } 22 | }}; 23 | }, 24 | getLock: function () { 25 | return {$promise: { 26 | then: function (successCallback) { 27 | successCallback(); 28 | } 29 | }}; 30 | }, 31 | isPostLockedForCurrentUser: function () { 32 | return {$promise: { 33 | then: function (successCallback) { 34 | successCallback(); 35 | } 36 | }}; 37 | } 38 | }; 39 | }]; 40 | -------------------------------------------------------------------------------- /legacy/test/unit/mock/services/post-metadata-service.js: -------------------------------------------------------------------------------- 1 | module.exports = [function () { 2 | return { 3 | formatSource: function (source) { }, 4 | loadUser: function () { }, 5 | loadContact: function () { }, 6 | validateUser: function () { } 7 | }; 8 | }]; 9 | -------------------------------------------------------------------------------- /legacy/test/unit/mock/services/post-survey-service.js: -------------------------------------------------------------------------------- 1 | module.exports = [function () { 2 | return { 3 | allowedSurveys: function () { 4 | return []; 5 | }, 6 | canCreatePostInSurvey : function () {} 7 | }; 8 | }]; 9 | -------------------------------------------------------------------------------- /legacy/test/unit/mock/services/post-view-service.js: -------------------------------------------------------------------------------- 1 | module.exports = [function () { 2 | return { 3 | showNoPostsSlider: function () { } 4 | }; 5 | }]; 6 | -------------------------------------------------------------------------------- /legacy/test/unit/mock/services/sdk/UtilsSdk.js: -------------------------------------------------------------------------------- 1 | module.exports = [ 2 | 'Util', 3 | function ( 4 | Util 5 | ) { 6 | const url = Util.url(''); 7 | const getLanguages = function() { 8 | return { then: function () { 9 | return [{'code':'ach','name':'Acoli'},{'code':'ady','name':'Adyghe'},{'code':'af','name':'Afrikaans'}]; 10 | } 11 | } 12 | } 13 | return {getLanguages}; 14 | } 15 | ]; 16 | -------------------------------------------------------------------------------- /legacy/test/unit/mock/services/session.js: -------------------------------------------------------------------------------- 1 | module.exports = [function () { 2 | var mockedSessionData = {}; 3 | return { 4 | setSessionData: function (sessionData) { 5 | mockedSessionData = sessionData; 6 | }, 7 | getSessionData: function () { 8 | return mockedSessionData; 9 | }, 10 | getSessionDataEntry: function (key) { 11 | return mockedSessionData[key]; 12 | }, 13 | setSessionDataEntry: function (key, value) { 14 | mockedSessionData[key] = value; 15 | }, 16 | setSessionDataEntries: function (entries) { 17 | mockedSessionData = angular.extend({}, mockedSessionData, entries); 18 | } 19 | }; 20 | }]; 21 | -------------------------------------------------------------------------------- /legacy/test/unit/mock/services/survey-notify.js: -------------------------------------------------------------------------------- 1 | module.exports = [function () { 2 | return { 3 | success: function (message) { 4 | return { 5 | then: function (successCallback) { 6 | successCallback(); 7 | } 8 | }; 9 | } 10 | }; 11 | }]; 12 | -------------------------------------------------------------------------------- /legacy/test/unit/mock/services/third_party/leaflet.js: -------------------------------------------------------------------------------- 1 | module.exports = [function () { 2 | return { 3 | geoJson : function () { 4 | 5 | }, 6 | markerClusterGroup : function () { 7 | 8 | } 9 | }; 10 | }]; 11 | -------------------------------------------------------------------------------- /legacy/test/unit/mock/services/third_party/transitions.js: -------------------------------------------------------------------------------- 1 | module.exports = [function () { 2 | return { 3 | onSuccess: function () { 4 | return function () {}; 5 | } 6 | }; 7 | 8 | }]; 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /legacy/test/unit/mock/services/translation-service.js: -------------------------------------------------------------------------------- 1 | module.exports = ['$q', 2 | function ($q) { 3 | return { 4 | translate: function (language) {}, 5 | setStartLanguage: function () {}, 6 | getLanguage: function () { 7 | return $q(function (resolve, reject) { 8 | resolve('en'); 9 | }); 10 | }, 11 | setLanguage: function () {} 12 | }; 13 | }]; 14 | -------------------------------------------------------------------------------- /legacy/test/unit/settings/data-import/data-import-controller-spec.js: -------------------------------------------------------------------------------- 1 | describe('setting data import controller', function () { 2 | 3 | var $rootScope, 4 | $scope, 5 | Notify, 6 | $controller; 7 | 8 | beforeEach(function () { 9 | 10 | var testApp = makeTestApp(); 11 | 12 | testApp.controller('settingDataImportController', require('app/settings/data-import/data-import.controller.js')); 13 | 14 | angular.mock.module('testApp'); 15 | }); 16 | 17 | beforeEach(angular.mock.inject(function (_$rootScope_, _$controller_, _Notify_) { 18 | $rootScope = _$rootScope_; 19 | $controller = _$controller_; 20 | Notify = _Notify_; 21 | $scope = _$rootScope_.$new(); 22 | 23 | $rootScope.hasManageSettingsPermission = function () { 24 | return true; 25 | }; 26 | })); 27 | 28 | 29 | beforeEach(function () { 30 | $rootScope.setLayout = function () {}; 31 | $controller('settingDataImportController', { 32 | $scope: $scope, 33 | $rootScope: $rootScope 34 | }); 35 | 36 | $rootScope.setLayout = function () {}; 37 | 38 | $rootScope.$digest(); 39 | $rootScope.$apply(); 40 | }); 41 | 42 | it('should retrieve forms and set them', function () { 43 | expect($scope.forms[0].name).toEqual('test form'); 44 | }); 45 | 46 | }); 47 | -------------------------------------------------------------------------------- /legacy/test/unit/settings/roles/roles-controller-spec.js: -------------------------------------------------------------------------------- 1 | describe('setting roles controller', function () { 2 | 3 | var $rootScope, 4 | $scope, 5 | $q, 6 | Notify, 7 | $controller; 8 | 9 | beforeEach(function () { 10 | 11 | var testApp = makeTestApp(); 12 | 13 | testApp.controller('settingRolesController', require('app/settings/roles/roles.controller.js')); 14 | 15 | angular.mock.module('testApp'); 16 | }); 17 | 18 | beforeEach(angular.mock.inject(function (_$q_, _$rootScope_, _$controller_, _Notify_) { 19 | $rootScope = _$rootScope_; 20 | $q = _$q_; 21 | $controller = _$controller_; 22 | Notify = _Notify_; 23 | $scope = _$rootScope_.$new(); 24 | 25 | $rootScope.hasManageSettingsPermission = function () { 26 | return true; 27 | }; 28 | })); 29 | 30 | 31 | beforeEach(function () { 32 | spyOn($rootScope, '$emit').and.callThrough(); 33 | 34 | $controller('settingRolesController', { 35 | $scope: $scope, 36 | $rootScope: $rootScope 37 | }); 38 | 39 | $rootScope.$digest(); 40 | $rootScope.$apply(); 41 | 42 | }); 43 | 44 | }); 45 | -------------------------------------------------------------------------------- /legacy/test/unit/settings/roles/setting-roles-directive-spec.js: -------------------------------------------------------------------------------- 1 | describe('setting roles directive', function () { 2 | 3 | var $rootScope, 4 | $scope, 5 | Notify, 6 | element; 7 | 8 | beforeEach(function () { 9 | fixture.setBase('mocked_backend/api/v3'); 10 | 11 | 12 | var testApp = makeTestApp(); 13 | 14 | testApp.directive('roles', require('app/settings/roles/roles.directive')) 15 | .value('$filter', function () { 16 | return function () {}; 17 | }) 18 | .value('PostEntity', {}); 19 | 20 | angular.mock.module('testApp'); 21 | }); 22 | 23 | 24 | 25 | beforeEach(angular.mock.inject(function (_$rootScope_, $compile, _Notify_) { 26 | $rootScope = _$rootScope_; 27 | $scope = _$rootScope_.$new(); 28 | $rootScope.setLayout = function () {}; 29 | Notify = _Notify_; 30 | 31 | element = '
'; 32 | element = $compile(element)($scope); 33 | $scope.$digest(); 34 | })); 35 | 36 | it('shuld refresh the view', function () { 37 | $scope.refreshView(); 38 | expect($scope.roles.length).toEqual(2); 39 | }); 40 | 41 | }); 42 | -------------------------------------------------------------------------------- /legacy/test/unit/settings/site/setting-editor-directive-spec.js: -------------------------------------------------------------------------------- 1 | describe('setting editor directive', function () { 2 | 3 | var $rootScope, 4 | $scope, 5 | Notify, 6 | element; 7 | 8 | beforeEach(function () { 9 | fixture.setBase('mocked_backend/api/v3'); 10 | 11 | 12 | var testApp = makeTestApp(); 13 | 14 | testApp.directive('settingEditor', require('app/settings/site/editor.directive')) 15 | .value('$filter', function () { 16 | return function () {}; 17 | }) 18 | .value('PostEntity', {}); 19 | 20 | angular.mock.module('testApp'); 21 | }); 22 | 23 | 24 | 25 | beforeEach(angular.mock.inject(function (_$rootScope_, $compile, _Notify_) { 26 | $rootScope = _$rootScope_; 27 | $scope = _$rootScope_.$new(); 28 | 29 | Notify = _Notify_; 30 | 31 | element = ''; 32 | element = $compile(element)($scope); 33 | $scope.$digest(); 34 | })); 35 | 36 | }); 37 | -------------------------------------------------------------------------------- /legacy/webpack.dev.config.js: -------------------------------------------------------------------------------- 1 | var config = require('./webpack.config'); 2 | 3 | config.mode = 'development'; 4 | 5 | config.devtool = 'sourcemap' 6 | 7 | config.devServer = { 8 | headers: { 9 | 'Access-Control-Allow-Origin': '*' 10 | }, 11 | stats: 'errors-only' 12 | } 13 | 14 | // this is modules imported using require inside the code (for example dayjs), 15 | // needed for proxy in dev-environment 16 | config.output.chunkFilename = 'legacy-modules/[name].js' 17 | 18 | module.exports = config; 19 | -------------------------------------------------------------------------------- /legacy/webpack.dist.config.js: -------------------------------------------------------------------------------- 1 | var config = require('./webpack.config'); 2 | config.mode = 'production'; 3 | config.stats = 'none'; 4 | config.output.filename = '[name].[chunkhash].js'; 5 | 6 | module.exports = config; 7 | -------------------------------------------------------------------------------- /legacy/webpack.test.config.js: -------------------------------------------------------------------------------- 1 | var path = require('path'); 2 | var config = require('./webpack.config'); 3 | 4 | config.devtool = 'inline-source-map'; 5 | config.plugins = []; 6 | 7 | // Add root to resolve for easier refs within tests 8 | config.resolve = { 9 | modules : [ 10 | path.resolve('./'), 11 | 'node_modules' 12 | ] 13 | }; 14 | config.output = {}; 15 | config.mode = 'development'; 16 | 17 | 18 | module.exports = config; 19 | -------------------------------------------------------------------------------- /root/.eslintignore: -------------------------------------------------------------------------------- 1 | dist/* -------------------------------------------------------------------------------- /root/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["important-stuff", "plugin:prettier/recommended"], 3 | "parser": "@babel/eslint-parser" 4 | } 5 | -------------------------------------------------------------------------------- /root/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | *.pid.lock 13 | 14 | # Directory for instrumented libs generated by jscoverage/JSCover 15 | lib-cov 16 | 17 | # Coverage directory used by tools like istanbul 18 | coverage 19 | 20 | # nyc test coverage 21 | .nyc_output 22 | 23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 24 | .grunt 25 | 26 | # Bower dependency directory (https://bower.io/) 27 | bower_components 28 | 29 | # node-waf configuration 30 | .lock-wscript 31 | 32 | # Compiled binary addons (https://nodejs.org/api/addons.html) 33 | build/Release 34 | 35 | # Dependency directories 36 | node_modules/ 37 | jspm_packages/ 38 | 39 | # TypeScript v1 declaration files 40 | typings/ 41 | 42 | # Optional npm cache directory 43 | .npm 44 | 45 | # Optional eslint cache 46 | .eslintcache 47 | 48 | # Optional REPL history 49 | .node_repl_history 50 | 51 | # Output of 'npm pack' 52 | *.tgz 53 | 54 | # Yarn Integrity file 55 | .yarn-integrity 56 | 57 | # dotenv environment variables file 58 | .env 59 | 60 | # next.js build output 61 | .next 62 | dist 63 | 64 | # Editor directories and files 65 | .idea 66 | .vscode 67 | *.suo 68 | *.ntvs* 69 | *.njsproj 70 | *.sln 71 | *.sw? 72 | .DS_Store 73 | -------------------------------------------------------------------------------- /root/.prettierignore: -------------------------------------------------------------------------------- 1 | .gitignore 2 | .prettierignore 3 | yarn.lock 4 | yarn-error.log 5 | package-lock.json 6 | LICENSE 7 | *.ejs 8 | dist 9 | coverage 10 | pnpm-lock.yaml -------------------------------------------------------------------------------- /root/babel.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["@babel/preset-env"], 3 | "plugins": [ 4 | [ 5 | "@babel/plugin-transform-runtime", 6 | { 7 | "useESModules": true, 8 | "regenerator": false 9 | } 10 | ] 11 | ], 12 | "env": { 13 | "test": { 14 | "presets": [ 15 | [ 16 | "@babel/preset-env", 17 | { 18 | "targets": "current node" 19 | } 20 | ] 21 | ] 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /root/src/config.js: -------------------------------------------------------------------------------- 1 | // Configure your Ushahidi deployment 2 | // 3 | // Uncomment lines below to configure your deployment 4 | // window.ushahidi = { 5 | // backendUrl : "https://ushahidi-platform-api-release.herokuapp.com", 6 | // mapboxApiKey: "", 7 | // sources: ['sms', 'twitter', 'web', 'email', 'whatsapp', 'ussd'] // remove sources you don't want from the sources array list 8 | // }; 9 | window.ushahidi = {}; 10 | -------------------------------------------------------------------------------- /root/src/importmap.json: -------------------------------------------------------------------------------- 1 | { 2 | "imports": { 3 | "@ushahidi/root-config": "/ushahidi-root-config.js", 4 | "@ushahidi/legacy-app": "/ushahidi-legacy-app.js", 5 | "@ushahidi/utilities": "/ushahidi-utilities.js", 6 | "@ushahidi/api": "/ushahidi-api.js", 7 | "@ushahidi/legacy-settings": "/ushahidi-settings.js", 8 | "@ushahidi/legacy-data": "/ushahidi-data.js", 9 | "@ushahidi/legacy-activity": "/ushahidi-activity.js" 10 | 11 | } 12 | } -------------------------------------------------------------------------------- /root/src/loading.scss: -------------------------------------------------------------------------------- 1 | #bootstrap-loading { 2 | position: absolute; 3 | top: 50%; 4 | right: 0; 5 | left: 0; 6 | text-align: center; 7 | margin-top: -16px; 8 | 9 | .loading { 10 | .line { 11 | border-radius: 15px; 12 | background-color: #ffc334; 13 | display: inline-block; 14 | height: 15px; 15 | width: 15px; 16 | margin: 5px; 17 | 18 | &:nth-last-child(1) {animation: loadingBounce .6s .1s linear infinite;} 19 | 20 | &:nth-last-child(2) {animation: loadingBounce .6s .2s linear infinite;} 21 | 22 | &:nth-last-child(3) {animation: loadingBounce .6s .3s linear infinite;} 23 | } 24 | } 25 | } 26 | 27 | @keyframes loadingBounce { 28 | 0 {transform: translate(0,0);} 29 | 50% {transform: translate(0,15px);} 30 | 100% {transform: translate(0,0);} 31 | } 32 | 33 | .hidden { 34 | display: none !important; 35 | } 36 | 37 | #bootstrap-error { 38 | .alert { 39 | &.error { 40 | background-color: #fac4cb; 41 | border-left: 2px solid #b00f23; 42 | display: inline-block; 43 | font-style: italic; 44 | line-height: 1.4; 45 | padding: 8px 16px; 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /root/src/microfrontend-layout.html: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 10 | 16 | 17 |
18 | 19 |
20 |
21 |
22 |
23 |
24 |
25 | 34 | 35 | 36 |
37 | 38 | 39 | 40 | 41 |
42 |
43 | -------------------------------------------------------------------------------- /server/nginx-site.conf: -------------------------------------------------------------------------------- 1 | server { 2 | listen 80 default; ## listen for ipv4; this line is default and implied 3 | listen [::]:80 default ipv6only=on; ## listen for ipv6 4 | 5 | charset UTF-8; 6 | root /var/www/; 7 | index index.html; 8 | 9 | server_name ushahidi-client; 10 | 11 | add_header X-XSS-Protection "1; mode=block"; 12 | 13 | location / { 14 | try_files $uri $uri/ @missing; 15 | } 16 | 17 | # Rewrite 404s back to index.html for pushState support 18 | # All routing is handled by Angular. 19 | location @missing { 20 | rewrite ^ /index.html last; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /server/rewrite.htaccess: -------------------------------------------------------------------------------- 1 | RewriteEngine on 2 | RewriteCond %{REQUEST_FILENAME} !-f 3 | RewriteRule ^.*$ /index.html [PT,L] 4 | 5 | Header set X-XSS-Protection "1; mode=block" 6 | -------------------------------------------------------------------------------- /server/scripts/generateImportMap.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const file = './build/importmap.json'; 3 | const buildFolder = './build'; 4 | let importmap; 5 | 6 | const matchNames = function () { 7 | fs.readdir(buildFolder, 'utf8', (err, files) => { 8 | files = files.filter(file => file.includes('ushahidi') && file.split('.').pop() === 'js'); 9 | // loop through hashed files in the build directory 10 | files.forEach(file => { 11 | // match with entries in the importmap 12 | Object.keys(importmap.imports).forEach(value => { 13 | let filename = importmap.imports[value].substring(1); 14 | filename = filename.slice(0, -3); 15 | if(file.includes(filename)) { 16 | importmap.imports[value] = "/" + file; 17 | } 18 | }); 19 | }); 20 | fs.writeFileSync(file, JSON.stringify(importmap)); 21 | }); 22 | } 23 | 24 | try { 25 | importmap = fs.readFileSync(file, 'utf8') 26 | importmap = JSON.parse(importmap) 27 | matchNames() 28 | } catch (err) { 29 | console.error(err) 30 | } -------------------------------------------------------------------------------- /server/scripts/ready.js: -------------------------------------------------------------------------------- 1 | const address = require('address'); 2 | const colors = require('colors'); 3 | const PROXY_PORT = process.env.PORT || 3000; 4 | console.log(""); 5 | console.log("*****************"); 6 | console.log(""); 7 | console.log("All clients have loaded.".green); 8 | console.log(""); 9 | console.log("Ushahidi client is ready to be viewed at", `http://${address.ip()}:${PROXY_PORT}`.blue); 10 | console.log(""); 11 | console.log("*****************"); 12 | console.log(""); 13 | -------------------------------------------------------------------------------- /server/scripts/start.js: -------------------------------------------------------------------------------- 1 | const address = require('address'); 2 | const colors = require('colors'); 3 | 4 | console.log(""); 5 | console.log("*****************"); 6 | console.log(""); 7 | console.log("Wait for all clients to load.".red); 8 | console.log(""); 9 | console.log("*****************"); 10 | console.log(""); 11 | -------------------------------------------------------------------------------- /single.stage.Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ushahidi/node-ci:node-10-gulp-4 2 | 3 | ARG HTTP_PORT=8080 4 | 5 | RUN apt-get update && \ 6 | apt-get install --no-install-recommends -y nginx python python-pip python-setuptools python-yaml && \ 7 | pip install 'jinja2-cli[yaml]==0.6.0' && \ 8 | apt-get clean && \ 9 | rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* 10 | 11 | RUN mkdir -p /var/app 12 | WORKDIR /var/app 13 | COPY package.json . 14 | RUN npm-install-silent.sh 15 | 16 | COPY . ./ 17 | RUN gulp build 18 | 19 | WORKDIR /usr/share/nginx/html 20 | RUN rsync -a --delete-after /var/app/server/www/ ./ 21 | COPY app/config.js.j2 ./config.js.j2 22 | COPY app/config.json.j2 ./config.json.j2 23 | COPY docker/nginx.default.conf /etc/nginx/sites-enabled/default 24 | COPY docker/nginx.run.sh /nginx.run.sh 25 | RUN sed -i 's/$HTTP_PORT/'$HTTP_PORT'/' /etc/nginx/sites-enabled/default && \ 26 | chgrp -R 0 . /var/lib/nginx /run && \ 27 | chmod -R g+rwX . /var/lib/nginx /run && \ 28 | ln -sf /dev/stdout /var/log/nginx/access.log && \ 29 | ln -sf /dev/stderr /var/log/nginx/error.log 30 | 31 | ENV HTTP_PORT=$HTTP_PORT 32 | EXPOSE $HTTP_PORT 33 | 34 | ENTRYPOINT [ "/bin/sh", "/nginx.run.sh" ] 35 | CMD [ "/usr/sbin/nginx", "-g", "daemon off;" ] 36 | -------------------------------------------------------------------------------- /utilities/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["important-stuff", "plugin:prettier/recommended"], 3 | "parser": "@babel/eslint-parser" 4 | } 5 | -------------------------------------------------------------------------------- /utilities/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | *.pid.lock 13 | 14 | # Directory for instrumented libs generated by jscoverage/JSCover 15 | lib-cov 16 | 17 | # Coverage directory used by tools like istanbul 18 | coverage 19 | 20 | # nyc test coverage 21 | .nyc_output 22 | 23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 24 | .grunt 25 | 26 | # Bower dependency directory (https://bower.io/) 27 | bower_components 28 | 29 | # node-waf configuration 30 | .lock-wscript 31 | 32 | # Compiled binary addons (https://nodejs.org/api/addons.html) 33 | build/Release 34 | 35 | # Dependency directories 36 | node_modules/ 37 | jspm_packages/ 38 | 39 | # TypeScript v1 declaration files 40 | typings/ 41 | 42 | # Optional npm cache directory 43 | .npm 44 | 45 | # Optional eslint cache 46 | .eslintcache 47 | 48 | # Optional REPL history 49 | .node_repl_history 50 | 51 | # Output of 'npm pack' 52 | *.tgz 53 | 54 | # Yarn Integrity file 55 | .yarn-integrity 56 | 57 | # dotenv environment variables file 58 | .env 59 | 60 | # next.js build output 61 | .next 62 | dist 63 | 64 | # Editor directories and files 65 | .idea 66 | .vscode 67 | *.suo 68 | *.ntvs* 69 | *.njsproj 70 | *.sln 71 | *.sw? 72 | .DS_Store 73 | -------------------------------------------------------------------------------- /utilities/.prettierignore: -------------------------------------------------------------------------------- 1 | .gitignore 2 | .prettierignore 3 | yarn.lock 4 | yarn-error.log 5 | package-lock.json 6 | dist 7 | coverage 8 | pnpm-lock.yaml -------------------------------------------------------------------------------- /utilities/babel.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["@babel/preset-env"], 3 | "plugins": [ 4 | [ 5 | "@babel/plugin-transform-runtime", 6 | { 7 | "useESModules": true, 8 | "regenerator": false 9 | } 10 | ] 11 | ], 12 | "env": { 13 | "test": { 14 | "presets": [ 15 | [ 16 | "@babel/preset-env", 17 | { 18 | "targets": "current node" 19 | } 20 | ] 21 | ] 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /utilities/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | transform: { 3 | "^.+\\.(j|t)sx?$": "babel-jest", 4 | }, 5 | moduleNameMapper: { 6 | "\\.(css)$": "identity-obj-proxy", 7 | }, 8 | }; 9 | -------------------------------------------------------------------------------- /utilities/src/ushahidi-utilities.js: -------------------------------------------------------------------------------- 1 | import { getConfig } from "@ushahidi/api"; 2 | 3 | export const getPageMetadata = function () { 4 | return getConfig("site").then((config) => { 5 | return { 6 | title: config.name || "USHAHIDI", 7 | description: config.description || "", 8 | appleId: getAppleId(), 9 | }; 10 | }); 11 | }; 12 | 13 | export const setBootstrapConfig = function () { 14 | if (window.ushahidi && window.ushahidi.backendUrl && !window.ushahidi.bootstrapConfig) { 15 | getConfig() 16 | .then(response => { 17 | return response.json(); 18 | }) 19 | .then(config => { 20 | // setting config 21 | window.ushahidi.bootstrapConfig = config; 22 | }) 23 | .catch(err => { 24 | window.ushahidi.bootstrapConfig = {}; 25 | }); 26 | } 27 | } 28 | 29 | const getAppleId = function () { 30 | if (window.ushahidi && window.ushahidi.appStoreId) { 31 | return window.ushahidi.appStoreId; 32 | } 33 | return; 34 | }; 35 | -------------------------------------------------------------------------------- /utilities/webpack.config.js: -------------------------------------------------------------------------------- 1 | const { merge } = require("webpack-merge"); 2 | const webpack = require("webpack"); 3 | const singleSpaDefaults = require("webpack-config-single-spa"); 4 | 5 | module.exports = (webpackConfigEnv, argv) => { 6 | const defaultConfig = singleSpaDefaults({ 7 | orgName: "ushahidi", 8 | projectName: "utilities", 9 | webpackConfigEnv, 10 | argv 11 | }); 12 | 13 | let filename = defaultConfig.mode === 'development' ? 'ushahidi-utilities.js' : 'ushahidi-utilities.[chunkhash].js'; 14 | return merge(defaultConfig, { 15 | output: { 16 | filename, 17 | clean: true 18 | }, 19 | plugins: [ 20 | new webpack.DefinePlugin({ 21 | BACKEND_URL: JSON.stringify( 22 | process.env.BACKEND_URL || "http://backend.url.undefined" 23 | ), 24 | }), 25 | ], 26 | }); 27 | }; 28 | --------------------------------------------------------------------------------