├── .env
├── .gitignore
├── .travis.yml
├── LICENSE
├── README.md
├── azuredeploy.json
├── azuredeploy.parameters.json
├── docker-compose.yml
├── project-fortis-backup
├── .dockerignore
├── backup-cassandra-keyspace.sh
├── docker
│ ├── Dockerfile
│ ├── run-backup.sh
│ └── run-cqlsh.sh
└── travis
│ ├── ci.sh
│ └── publish.sh
├── project-fortis-interfaces
├── .dockerignore
├── .eslintrc
├── .gitignore
├── docker
│ ├── Dockerfile
│ └── run-react.sh
├── package-lock.json
├── package.json
├── public
│ ├── images
│ │ ├── OCHA_Logo.png
│ │ ├── intl_alert.png
│ │ ├── stroer_logo.png
│ │ └── umea_white.svg
│ └── index.html
├── src
│ ├── actions
│ │ ├── Admin
│ │ │ └── index.js
│ │ ├── Dashboard
│ │ │ └── index.js
│ │ ├── Facts
│ │ │ └── index.js
│ │ ├── constants.js
│ │ └── shared.js
│ ├── components
│ │ ├── Admin
│ │ │ ├── Admin.js
│ │ │ ├── AdminSettings.js
│ │ │ ├── AdminWatchlist.js
│ │ │ ├── BlacklistEditor.js
│ │ │ ├── CustomEventsEditor.js
│ │ │ ├── DataGrid.js
│ │ │ ├── SiteExportButton.js
│ │ │ ├── Streams
│ │ │ │ ├── CreateStream.js
│ │ │ │ ├── StreamConstants.js
│ │ │ │ ├── StreamEditor.js
│ │ │ │ ├── StreamParamsButtonFormatter.js
│ │ │ │ └── StreamStatusButtonFormatter.js
│ │ │ ├── TrustedSources.js
│ │ │ ├── UserRoles.js
│ │ │ └── shared.js
│ │ ├── Facts
│ │ │ ├── FactsList.js
│ │ │ └── ListView.js
│ │ ├── Footer.js
│ │ ├── Graphics
│ │ │ ├── DoughnutChart.js
│ │ │ ├── GraphCard.js
│ │ │ ├── NoData.js
│ │ │ ├── Sentiment.js
│ │ │ ├── Timeline.js
│ │ │ └── WordCloud.js
│ │ ├── Header
│ │ │ ├── Header.js
│ │ │ └── index.js
│ │ ├── Insights
│ │ │ ├── ActiveFiltersView.js
│ │ │ ├── ActivityFeed.js
│ │ │ ├── CategoryPicker.js
│ │ │ ├── CsvExporter.js
│ │ │ ├── Dashboard.js
│ │ │ ├── DataSelector.js
│ │ │ ├── DrawerActionsIconButton.js
│ │ │ ├── FortisEvent.js
│ │ │ ├── HeatmapToggle.js
│ │ │ ├── LanguagePicker.js
│ │ │ ├── Layouts
│ │ │ │ └── index.js
│ │ │ ├── MapBoundingReset.js
│ │ │ ├── Maps
│ │ │ │ ├── HeatMap.js
│ │ │ │ ├── MarkerCluster.js
│ │ │ │ ├── MarkerClusterGroup.js
│ │ │ │ ├── TileLayer.js
│ │ │ │ └── style.scss
│ │ │ ├── PopularLocationsChart.js
│ │ │ ├── PopularSourcesChart.js
│ │ │ ├── PopularTermsChart.js
│ │ │ ├── SentimentTreeview.js
│ │ │ ├── ShareButton.js
│ │ │ ├── Subheader.js
│ │ │ ├── TermFilter.js
│ │ │ ├── TimeSeriesGraph.js
│ │ │ ├── TopicCloud.js
│ │ │ ├── TranslateButton.js
│ │ │ ├── TreeFilter.js
│ │ │ ├── TypeaheadSearch.js
│ │ │ └── shared.js
│ │ └── dialogs
│ │ │ ├── DialogBox.js
│ │ │ ├── EventDetails.js
│ │ │ ├── Highlighter.js
│ │ │ └── MapViewPort.js
│ ├── config.js
│ ├── images
│ │ ├── MSFT_logo_png.png
│ │ ├── OCHA_Logo.png
│ │ ├── layers-2x.png
│ │ ├── layers.png
│ │ ├── marker-icon-2x.png
│ │ ├── marker-icon-red.png
│ │ ├── marker-icon.png
│ │ ├── marker-shadow.png
│ │ ├── nav_bg2.svg
│ │ ├── partner_catalyst_icon.ico
│ │ ├── partner_catalyst_icon.png
│ │ ├── partner_catalyst_logo.png
│ │ ├── select.png
│ │ └── umea_white.svg
│ ├── index.js
│ ├── routes
│ │ ├── AdminPage.js
│ │ ├── AppPage.js
│ │ ├── DashboardPage.js
│ │ ├── FactsPage.js
│ │ ├── NotFoundPage.js
│ │ ├── UnsupportedBrowserPage.js
│ │ └── routes.js
│ ├── services
│ │ ├── Admin
│ │ │ └── index.js
│ │ ├── Dashboard
│ │ │ └── index.js
│ │ ├── Facts
│ │ │ └── index.js
│ │ ├── featureService.js
│ │ ├── graphql
│ │ │ ├── fragments
│ │ │ │ ├── Admin
│ │ │ │ │ └── index.js
│ │ │ │ ├── Dashboard
│ │ │ │ │ └── index.js
│ │ │ │ └── Facts
│ │ │ │ │ └── index.js
│ │ │ ├── mutations
│ │ │ │ └── Admin
│ │ │ │ │ └── index.js
│ │ │ └── queries
│ │ │ │ ├── Admin
│ │ │ │ └── index.js
│ │ │ │ ├── Dashboard
│ │ │ │ └── index.js
│ │ │ │ └── Facts
│ │ │ │ └── index.js
│ │ └── shared.js
│ ├── stores
│ │ ├── AdminStore.js
│ │ └── DataStore.js
│ ├── styles
│ │ ├── Admin
│ │ │ └── Admin.css
│ │ ├── Facts
│ │ │ └── Facts.css
│ │ ├── Footer.css
│ │ ├── Global.css
│ │ ├── Graphics
│ │ │ ├── GraphCard.css
│ │ │ ├── colors.js
│ │ │ └── styles.js
│ │ ├── Header.css
│ │ └── Insights
│ │ │ ├── ActiveFiltersView.css
│ │ │ ├── ActivityFeed.css
│ │ │ ├── ActivityFeed.js
│ │ │ ├── Dashboard.css
│ │ │ ├── DataSelector.css
│ │ │ ├── DialogBox.css
│ │ │ ├── HeatMap.css
│ │ │ ├── SentimentTreeView.css
│ │ │ ├── SentimentTreeview.js
│ │ │ └── TypeaheadSearch.css
│ └── utils
│ │ ├── Fact.js
│ │ ├── HtmlSanitizer.js
│ │ └── Utils.js
└── travis
│ └── ci.sh
├── project-fortis-pipeline
├── .gitignore
├── docs
│ ├── aad-setup.md
│ ├── admin-settings.md
│ ├── azure-deploy-parameters.md
│ ├── background.md
│ ├── development-faq.md
│ ├── development-setup.md
│ └── production-setup.md
├── fortis-deploy.sh
├── localdeploy
│ ├── parameters.json
│ ├── parse-output.py
│ ├── seed-data
│ │ ├── seed-data-no-events.tar.gz
│ │ ├── seed-data-twitter-clewolff.tar.gz
│ │ ├── seed-data-twitter-steph.tar.gz
│ │ ├── seed-data-twitter.tar.gz
│ │ └── seed-data.tar.gz
│ ├── setup-development-azure-resources.sh
│ └── template.json
├── ops
│ ├── charts
│ │ ├── cassandra
│ │ │ ├── .helmignore
│ │ │ ├── Chart.yaml
│ │ │ ├── templates
│ │ │ │ ├── _helpers.tpl
│ │ │ │ ├── statefulset.yaml
│ │ │ │ └── svc.yaml
│ │ │ └── values.yaml
│ │ └── spark
│ │ │ ├── .helmignore
│ │ │ ├── Chart.yaml
│ │ │ ├── templates
│ │ │ ├── NOTES.txt
│ │ │ ├── _helpers.tpl
│ │ │ ├── secret.yaml
│ │ │ ├── spark-master-deployment.yaml
│ │ │ ├── spark-master-service.yaml
│ │ │ ├── spark-worker-statefulset.yaml
│ │ │ └── spark-zeppelin-deployment.yaml
│ │ │ └── values.yaml
│ ├── config
│ │ └── defaultTopics
│ │ │ ├── climate.json
│ │ │ ├── health.json
│ │ │ └── humanitarian.json
│ ├── create-cluster.sh
│ ├── create-tags.sh
│ ├── install-cassandra.sh
│ ├── install-featureservice.sh
│ ├── install-fortis-backup.sh
│ ├── install-fortis-interfaces.sh
│ ├── install-fortis-services.sh
│ ├── install-spark.sh
│ └── storage-ddls
│ │ ├── cassandra-setup.cql
│ │ └── settings-setup.cql
└── travis
│ └── ci.sh
├── project-fortis-services
├── .dockerignore
├── .eslintignore
├── .eslintrc
├── .gitattributes
├── .gitignore
├── config.js
├── docker
│ ├── Dockerfile
│ ├── run-cqlsh.sh
│ └── run-node.sh
├── package-lock.json
├── package.json
├── server.js
├── src
│ ├── auth.js
│ ├── clients
│ │ ├── appinsights
│ │ │ ├── AppInsightsClient.js
│ │ │ ├── AppInsightsConstants.js
│ │ │ └── LoggingClient.js
│ │ ├── cassandra
│ │ │ └── CassandraConnector.js
│ │ ├── eventhub
│ │ │ └── EventHubSender.js
│ │ ├── locations
│ │ │ └── FeatureServiceClient.js
│ │ ├── storage
│ │ │ └── BlobStorageClient.js
│ │ ├── streaming
│ │ │ ├── ServiceBusClient.js
│ │ │ └── StreamingController.js
│ │ └── translator
│ │ │ └── MsftTranslator.js
│ ├── resolvers
│ │ ├── Edges
│ │ │ ├── index.js
│ │ │ └── queries.js
│ │ ├── Messages
│ │ │ ├── index.js
│ │ │ ├── mutations.js
│ │ │ └── queries.js
│ │ ├── Settings
│ │ │ ├── index.js
│ │ │ ├── mutations.js
│ │ │ ├── queries.js
│ │ │ └── shared.js
│ │ ├── Tiles
│ │ │ ├── index.js
│ │ │ └── queries.js
│ │ └── shared.js
│ ├── routes
│ │ └── healthcheck.js
│ ├── schemas
│ │ ├── EdgesSchema.js
│ │ ├── MessageSchema.js
│ │ ├── SettingsSchema.js
│ │ └── TilesSchema.js
│ ├── scripts
│ │ ├── addusers.js
│ │ ├── createsite.js
│ │ └── ingestsetting.js
│ └── utils
│ │ ├── collections.js
│ │ └── request.js
└── travis
│ ├── ci.sh
│ └── publish.sh
└── project-fortis-spark
├── .dockerignore
├── .gitignore
├── build.sbt
├── docker
├── Dockerfile
├── run-cqlsh.sh
└── run-spark.sh
├── lib
├── spark-streaming-twitter_2.11-2.2.0-SNAPSHOT.jar
├── tritonus_remaining-0.3.6.jar
└── tritonus_share-0.3.6.jar
├── project
├── build.properties
└── plugins.sbt
├── src
├── main
│ ├── resources
│ │ └── ApplicationInsights.xml
│ └── scala
│ │ └── com
│ │ └── microsoft
│ │ └── partnercatalyst
│ │ └── fortis
│ │ └── spark
│ │ ├── CassandraTest.scala
│ │ ├── Constants.scala
│ │ ├── FortisSettings.scala
│ │ ├── Pipeline.scala
│ │ ├── ProjectFortis.scala
│ │ ├── StreamsChangeListener.scala
│ │ ├── analyzer
│ │ ├── AnalysisDefaults.scala
│ │ ├── Analyzer.scala
│ │ ├── BingAnalyzer.scala
│ │ ├── CustomEventAnalyzer.scala
│ │ ├── ExtendedFortisEvent.scala
│ │ ├── FacebookCommentAnalyzer.scala
│ │ ├── FacebookPostAnalyzer.scala
│ │ ├── HTMLAnalyzer.scala
│ │ ├── InstagramAnalyzer.scala
│ │ ├── RSSAnalyzer.scala
│ │ ├── RadioAnalyzer.scala
│ │ ├── RedditAnalyzer.scala
│ │ ├── TadawebAnalyzer.scala
│ │ └── TwitterAnalyzer.scala
│ │ ├── dba
│ │ ├── CassandraConfigurationManager.scala
│ │ ├── CassandraSchema.scala
│ │ └── ConfigurationManager.scala
│ │ ├── dto
│ │ ├── BlacklistedItem.scala
│ │ ├── ComputedTile.scala
│ │ ├── ComputedTrend.scala
│ │ ├── FortisEvent.scala
│ │ ├── Geofence.scala
│ │ └── SiteSettings.scala
│ │ ├── logging
│ │ ├── AppInsightsTelemetry.scala
│ │ ├── FortisTelemetry.scala
│ │ └── Timer.scala
│ │ ├── serialization
│ │ └── KryoRegistrator.scala
│ │ ├── sinks
│ │ └── cassandra
│ │ │ ├── CassandraConfig.scala
│ │ │ ├── CassandraEventSchema.scala
│ │ │ ├── CassandraEventsSink.scala
│ │ │ ├── CassandraExtensions.scala
│ │ │ ├── FortisConnectionFactory.scala
│ │ │ ├── Period.scala
│ │ │ ├── aggregators
│ │ │ ├── ConjunctiveTopicsOffineAggregator.scala
│ │ │ └── TileAggregator.scala
│ │ │ └── dto
│ │ │ ├── AggregationRecord.scala
│ │ │ ├── FortisRecords.scala
│ │ │ └── UserDefinedTypes.scala
│ │ ├── sources
│ │ ├── StreamProviderFactory.scala
│ │ ├── streamfactories
│ │ │ ├── BingPageStreamFactory.scala
│ │ │ ├── EventHubStreamFactory.scala
│ │ │ ├── FacebookCommentStreamFactory.scala
│ │ │ ├── FacebookPageStreamFactory.scala
│ │ │ ├── HTMLStreamFactory.scala
│ │ │ ├── InstagramLocationStreamFactory.scala
│ │ │ ├── InstagramTagStreamFactory.scala
│ │ │ ├── ParameterExtensions.scala
│ │ │ ├── RSSStreamFactory.scala
│ │ │ ├── RadioStreamFactory.scala
│ │ │ ├── RedditStreamFactory.scala
│ │ │ ├── StreamFactoryBase.scala
│ │ │ └── TwitterStreamFactory.scala
│ │ ├── streamprovider
│ │ │ ├── ConnectorConfig.scala
│ │ │ ├── StreamFactory.scala
│ │ │ ├── StreamProvider.scala
│ │ │ └── StreamProviderException.scala
│ │ └── streamwrappers
│ │ │ ├── customevents
│ │ │ ├── CustomEvent.scala
│ │ │ └── CustomEventsAdapter.scala
│ │ │ ├── radio
│ │ │ ├── RadioInputDStream.scala
│ │ │ ├── RadioStreamUtils.scala
│ │ │ ├── RadioTranscription.scala
│ │ │ └── TranscriptionReceiver.scala
│ │ │ └── tadaweb
│ │ │ ├── TadawebAdapter.scala
│ │ │ └── TadawebEvent.scala
│ │ ├── transformcontext
│ │ ├── Delta.scala
│ │ ├── TransformContext.scala
│ │ ├── TransformContextMessages.scala
│ │ └── TransformContextProvider.scala
│ │ └── transforms
│ │ ├── ZipModelsProvider.scala
│ │ ├── entities
│ │ └── EntityRecognizer.scala
│ │ ├── gender
│ │ └── GenderDetector.scala
│ │ ├── image
│ │ ├── ImageAnalyzer.scala
│ │ └── dto
│ │ │ └── Json.scala
│ │ ├── language
│ │ ├── CognitiveServicesLanguageDetector.scala
│ │ ├── LanguageDetector.scala
│ │ ├── LocalLanguageDetector.scala
│ │ ├── TextNormalizer.scala
│ │ └── dto
│ │ │ └── Json.scala
│ │ ├── locations
│ │ ├── LocationsExtractor.scala
│ │ ├── LocationsExtractorFactory.scala
│ │ ├── LuceneLocationsExtractor.scala
│ │ ├── PlaceRecognizer.scala
│ │ ├── StringUtils.scala
│ │ ├── Tile.scala
│ │ ├── client
│ │ │ └── FeatureServiceClient.scala
│ │ └── dto
│ │ │ └── Json.scala
│ │ ├── nlp
│ │ ├── OpeNER.scala
│ │ └── Tokenizer.scala
│ │ ├── people
│ │ └── PeopleRecognizer.scala
│ │ ├── sentiment
│ │ ├── CognitiveServicesSentimentDetector.scala
│ │ ├── SentimentDetector.scala
│ │ ├── WordListSentimentDetector.scala
│ │ └── dto
│ │ │ └── Json.scala
│ │ ├── summary
│ │ └── KeywordSummarizer.scala
│ │ └── topic
│ │ ├── Blacklist.scala
│ │ ├── KeyphraseExtractor.scala
│ │ ├── KeywordExtractor.scala
│ │ ├── LuceneKeyphraseExtractor.scala
│ │ └── LuceneKeywordExtractor.scala
└── test
│ └── scala
│ └── com
│ └── microsoft
│ └── partnercatalyst
│ └── fortis
│ └── spark
│ ├── SparkSpec.scala
│ ├── StreamsChangeListenerTestSpec.scala
│ ├── dto
│ └── FortisEventSpec.scala
│ ├── sinks
│ └── cassandra
│ │ ├── CassandraConjunctiveTopicsTestSpec.scala
│ │ ├── CassandraConjunctiveTopicsTestSpecRdd.scala
│ │ ├── CassandraExtensionsTests.scala
│ │ ├── CassandraIntegrationTestSpec.scala
│ │ └── PeriodSpec.scala
│ ├── sources
│ └── streamfactories
│ │ └── TwitterStreamFactorySpec.scala
│ └── transforms
│ ├── image
│ └── ImageAnalyzerSpec.scala
│ ├── language
│ ├── CognitiveServicesLanguageDetectorSpec.scala
│ └── LocalLanguageDetectorSpec.scala
│ ├── locations
│ ├── LocationsExtractorSpec.scala
│ ├── PlaceRecognizerIntegrationSpec.scala
│ ├── StringUtilsSpec.scala
│ ├── TileUtilsSpec.scala
│ └── client
│ │ └── FeatureServiceClientSpec.scala
│ ├── nlp
│ └── TokenizerSpec.scala
│ ├── sentiment
│ ├── CognitiveServicesSentimentDetectorSpec.scala
│ ├── SentimentDetectorSpec.scala
│ ├── WordListSentimentDetectorIntegrationSpec.scala
│ └── WordListSentimentDetectorSpec.scala
│ ├── summary
│ └── KeywordSummarizerSpec.scala
│ └── topic
│ ├── BlacklistSpec.scala
│ ├── KeywordExtractorSpec.scala
│ └── LuceneKeyphraseExtractorSpec.scala
├── travis
├── ci.sh
└── publish.sh
└── version.sbt
/.env:
--------------------------------------------------------------------------------
1 | BUILD_TAG=latest
2 | PROJECT_FORTIS_SPARK_CONTEXT_UI_PORT=7777
3 | PROJECT_FORTIS_SPARK_MASTER_UI_PORT=7778
4 | PROJECT_FORTIS_SPARK_WORKER_UI_PORT=7779
5 | PROJECT_FORTIS_INTERFACES_PORT=8888
6 | PROJECT_FORTIS_SERVICES_PORT=8889
7 | FEATURE_SERVICE_PORT=9090
8 | CASSANDRA_SEED_DATA_URL=https://raw.githubusercontent.com/CatalystCode/project-fortis/master/project-fortis-pipeline/localdeploy/seed-data/seed-data-twitter.tar.gz
9 | AD_CLIENT_ID=bf1ceec7-cfc7-49c5-9ed3-c6390b87dda5
10 | USERS=scicoria@microsoft.com,erisch@microsoft.com
11 | ADMINS=clewolff@microsoft.com,stmarker@microsoft.com,naros@microsoft.com,keha@microsoft.com
12 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .env-secrets
2 |
3 | .idea/
4 | .DS_Store
5 | *.orig
6 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | matrix:
2 | include:
3 |
4 | - language: bash
5 | script:
6 | - project-fortis-backup/travis/ci.sh
7 | services:
8 | - docker
9 | deploy:
10 | - provider: script
11 | script: project-fortis-backup/travis/publish.sh
12 | on:
13 | repo: CatalystCode/project-fortis
14 | tags: true
15 | env:
16 | NAME=project-fortis-backup
17 |
18 | - language: node_js
19 | node_js:
20 | - "6"
21 | cache:
22 | directories:
23 | project-fortis-interfaces/node_modules
24 | script:
25 | project-fortis-interfaces/travis/ci.sh
26 | env:
27 | NAME=project-fortis-interfaces
28 |
29 | - language: bash
30 | script:
31 | - project-fortis-pipeline/travis/ci.sh
32 | env:
33 | NAME=project-fortis-pipeline
34 |
35 | - language: node_js
36 | sudo: required
37 | node_js:
38 | - "9"
39 | cache:
40 | directories:
41 | project-fortis-services/node_modules
42 | script:
43 | project-fortis-services/travis/ci.sh
44 | services:
45 | - docker
46 | deploy:
47 | - provider: script
48 | script: project-fortis-services/travis/publish.sh
49 | on:
50 | repo: CatalystCode/project-fortis
51 | tags: true
52 | env:
53 | NAME=project-fortis-services
54 |
55 | - language: scala
56 | jdk: oraclejdk8
57 | scala: 2.11.7
58 | dist: trusty
59 | sudo: required
60 | script:
61 | - project-fortis-spark/travis/ci.sh
62 | deploy:
63 | - provider: script
64 | script: project-fortis-spark/travis/publish.sh
65 | on:
66 | repo: CatalystCode/project-fortis
67 | tags: true
68 | env:
69 | NAME=project-fortis-spark
70 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 Catalyst Code
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # project-fortis
2 |
3 | Project Fortis is a data ingestion, analysis and visualization pipeline. The
4 | Fortis pipeline collects social media conversations and postings from the public
5 | web and darknet data sources.
6 |
7 | - [Find out more about the project](project-fortis-pipeline/docs/background.md)
8 | - [Learn how to set up Fortis in Azure](project-fortis-pipeline/docs/production-setup.md)
9 | - [Onboarding guide for developers](project-fortis-pipeline/docs/development-setup.md)
10 |
--------------------------------------------------------------------------------
/azuredeploy.parameters.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#",
3 | "contentVersion": "1.0.0.0",
4 | "parameters": {
5 | "githubProjectParent": {
6 | "value": "CatalystCode"
7 | },
8 | "githubProjectRelease": {
9 | "value": "master"
10 | },
11 | "siteName": {
12 | "value": "enter-your-fortis-site-name"
13 | },
14 | "siteLocation": {
15 | "value": "East US"
16 | },
17 | "acsMasterCount": {
18 | "value": 1
19 | },
20 | "acsAgentCount": {
21 | "value": 6
22 | },
23 | "agentVMSize": {
24 | "value": "Standard_L4s"
25 | },
26 | "sparkWorkers": {
27 | "value": 6
28 | },
29 | "cassandraNodes": {
30 | "value": 5
31 | },
32 | "siteType": {
33 | "value": "none"
34 | },
35 | "sshPublicKey": {
36 | "value": "CHANGE ME"
37 | },
38 | "mapboxAccessToken": {
39 | "value": "CHANGE ME"
40 | },
41 | "fortisSiteCloneUrl": {
42 | "value": ""
43 | },
44 | "servicePrincipalAppId": {
45 | "value": "CHANGE ME"
46 | },
47 | "servicePrincipalAppKey": {
48 | "value": "CHANGE ME"
49 | },
50 | "activeDirectoryClientId": {
51 | "value": ""
52 | },
53 | "fortisAdmins": {
54 | "value": ""
55 | },
56 | "fortisUsers": {
57 | "value": ""
58 | },
59 | "letsEncryptEmail": {
60 | "value": ""
61 | }
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/project-fortis-backup/.dockerignore:
--------------------------------------------------------------------------------
1 | travis/
2 |
--------------------------------------------------------------------------------
/project-fortis-backup/docker/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM ubuntu:xenial
2 |
3 | # install cassandra
4 | ENV CASSANDRA_HOME="/opt/cassandra"
5 | ARG CASSANDRA_VERSION="3.11.0"
6 | ARG CASSANDRA_ARTIFACT="apache-cassandra-${CASSANDRA_VERSION}"
7 | ARG CASSANDRA_URL="http://archive.apache.org/dist/cassandra/${CASSANDRA_VERSION}/${CASSANDRA_ARTIFACT}-bin.tar.gz"
8 | RUN apt-get update && \
9 | apt-get -qq install -y --no-install-recommends wget ca-certificates python && \
10 | wget -qO - ${CASSANDRA_URL} | tar -xzC /opt && \
11 | ln -s /opt/${CASSANDRA_ARTIFACT} ${CASSANDRA_HOME}
12 |
13 | RUN apt-get -qq update && \
14 | apt-get -qq install -y libssl-dev libffi-dev python-dev curl apt-transport-https && \
15 | echo "deb [arch=amd64] https://packages.microsoft.com/repos/azure-cli/ xenial main" | tee /etc/apt/sources.list.d/azure-cli.list && \
16 | curl -L https://packages.microsoft.com/keys/microsoft.asc | apt-key add - && \
17 | apt-get -qq update && \
18 | apt-get -qq install -y azure-cli
19 |
20 | # install app dependencies
21 | RUN apt-get -qq install -y cron gzip
22 |
23 | # install backup scripts
24 | ADD backup-cassandra-keyspace.sh /app/backup-cassandra-keyspace.sh
25 | ADD docker/run-cqlsh.sh /app/cqlsh
26 | ADD docker/run-backup.sh /app/backup
27 |
28 | CMD /app/backup
29 |
30 | # configuration for azure blob account where backups are stored
31 | ENV USER_FILES_BLOB_ACCOUNT_NAME=""
32 | ENV USER_FILES_BLOB_ACCOUNT_KEY=""
33 | ENV BACKUP_CONTAINER_NAME="backups"
34 | ENV BACKUP_DELETE_LOOKBACK="2 weeks ago"
35 | ENV BACKUP_INTERVAL="2h"
36 |
37 | # a one-node local cassandra is set up via docker-compose, if you wish to use a
38 | # larger cluster (e.g. hosted in Azure), just override this variable with the
39 | # hostname of your cluster
40 | ENV FORTIS_CASSANDRA_HOST="cassandra"
41 | ENV FORTIS_CASSANDRA_PORT="9042"
42 | ENV FORTIS_CASSANDRA_USERNAME="cassandra"
43 | ENV FORTIS_CASSANDRA_PASSWORD="cassandra"
44 |
--------------------------------------------------------------------------------
/project-fortis-backup/docker/run-backup.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | while :; do
4 | sleep "$BACKUP_INTERVAL"
5 | /app/backup-cassandra-keyspace.sh settings
6 | done
7 |
--------------------------------------------------------------------------------
/project-fortis-backup/docker/run-cqlsh.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | "$CASSANDRA_HOME/bin/cqlsh" \
4 | --request-timeout=3600 \
5 | --username="$FORTIS_CASSANDRA_USERNAME" \
6 | --password="$FORTIS_CASSANDRA_PASSWORD" \
7 | "$FORTIS_CASSANDRA_HOST" \
8 | "$FORTIS_CASSANDRA_PORT"
9 |
--------------------------------------------------------------------------------
/project-fortis-backup/travis/ci.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | set -e
4 |
5 | pushd "$(dirname "$0")/.."
6 |
7 | # shellcheck disable=SC2046
8 | shellcheck $(find . -name '*.sh')
9 |
10 | popd
11 |
--------------------------------------------------------------------------------
/project-fortis-backup/travis/publish.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | set -euo pipefail
4 |
5 | log() {
6 | echo "$@" >&2
7 | }
8 |
9 | check_preconditions() {
10 | if [ -z "${TRAVIS_TAG}" ]; then
11 | log "Build is not a tag, skipping publish"
12 | exit 0
13 | fi
14 | if [ -z "${DOCKER_USERNAME}" ] || [ -z "${DOCKER_PASSWORD}" ]; then
15 | log "Docker credentials not provided, unable to publish builds"
16 | exit 1
17 | fi
18 | }
19 |
20 | create_image() {
21 | touch .env-secrets
22 | BUILD_TAG="${TRAVIS_TAG}" docker-compose build project_fortis_backup
23 | }
24 |
25 | publish_image() {
26 | docker login --username="${DOCKER_USERNAME}" --password="${DOCKER_PASSWORD}"
27 | BUILD_TAG="${TRAVIS_TAG}" docker-compose push project_fortis_backup
28 | }
29 |
30 | pushd "$(dirname "$0")/../.."
31 |
32 | check_preconditions
33 | create_image
34 | publish_image
35 |
36 | popd
37 |
--------------------------------------------------------------------------------
/project-fortis-interfaces/.dockerignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | build/
3 | travis/
4 | README.md
5 | .gitignore
6 |
--------------------------------------------------------------------------------
/project-fortis-interfaces/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "react-app",
3 | "rules": {
4 | "jsx-a11y/alt-text": "off"
5 | }
6 | }
--------------------------------------------------------------------------------
/project-fortis-interfaces/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 |
5 | # Runtime data
6 | pids
7 | *.pid
8 | *.seed
9 |
10 | # Directory for instrumented libs generated by jscoverage/JSCover
11 | lib-cov
12 |
13 | # Coverage directory used by tools like istanbul
14 | coverage
15 |
16 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
17 | .grunt
18 |
19 | # node-waf configuration
20 | .lock-wscript
21 |
22 | # Compiled binary addons (http://nodejs.org/api/addons.html)
23 | build/Release
24 |
25 | # Dependency directory
26 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git
27 | node_modules
28 | node_modules_old
29 | bower_components
30 | dist
31 | build
32 | tmp
33 | *.pem
34 | *.config.json
35 |
36 | # Localhost config file
37 | .env
38 |
39 | # Editors
40 | .vscode/*
41 |
--------------------------------------------------------------------------------
/project-fortis-interfaces/docker/run-react.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | npm run devserver
4 |
--------------------------------------------------------------------------------
/project-fortis-interfaces/public/images/OCHA_Logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CatalystCode/project-fortis/e9843b080e33c2959b1021cb20247ba51a695a6a/project-fortis-interfaces/public/images/OCHA_Logo.png
--------------------------------------------------------------------------------
/project-fortis-interfaces/public/images/intl_alert.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CatalystCode/project-fortis/e9843b080e33c2959b1021cb20247ba51a695a6a/project-fortis-interfaces/public/images/intl_alert.png
--------------------------------------------------------------------------------
/project-fortis-interfaces/public/images/stroer_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CatalystCode/project-fortis/e9843b080e33c2959b1021cb20247ba51a695a6a/project-fortis-interfaces/public/images/stroer_logo.png
--------------------------------------------------------------------------------
/project-fortis-interfaces/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Fortis Dashboard
6 |
7 |
8 |
9 |
10 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/project-fortis-interfaces/src/actions/Facts/index.js:
--------------------------------------------------------------------------------
1 | import { SERVICES } from '../../services/Facts';
2 | import { ResponseHandler } from '../shared';
3 |
4 | const _methods = {
5 | loadFacts(pipelinekeys, mainTerm, fromDate, toDate, pageState, callback) {
6 | SERVICES.loadFacts(
7 | pipelinekeys, mainTerm, fromDate, toDate, pageState,
8 | (error, response, body) => ResponseHandler(error, response, body, callback));
9 | },
10 | };
11 |
12 | const methods = { FACTS: _methods };
13 |
14 | module.exports = {
15 | methods
16 | };
17 |
--------------------------------------------------------------------------------
/project-fortis-interfaces/src/actions/shared.js:
--------------------------------------------------------------------------------
1 | function ResponseHandler (error, response, body, callback) {
2 | if (!error && response.statusCode === 200 && body.data && !body.errors) {
3 | callback(undefined, body.data);
4 | } else {
5 | const code = response ? response.statusCode : 500;
6 | const message = `GraphQL call failed: ${formatGraphQlErrorDetails(body, error)}`;
7 | callback({ code, message }, undefined);
8 | }
9 | }
10 |
11 | function formatGraphQlErrorDetails(body, error) {
12 | if (!body) {
13 | return error;
14 | }
15 |
16 | if (!body.errors) {
17 | return body;
18 | }
19 |
20 | const errors = Array.from(new Set(body.errors.map(error => error.message)));
21 | errors.sort();
22 | return errors.join("; ");
23 | }
24 |
25 | const DataSources = (source, enabledStreams) => enabledStreams.has(source) ? enabledStreams.get(source).sourceValues : undefined;
26 |
27 | module.exports = {
28 | ResponseHandler,
29 | DataSources
30 | };
--------------------------------------------------------------------------------
/project-fortis-interfaces/src/components/Admin/shared.js:
--------------------------------------------------------------------------------
1 | const DEFAULT_COLUMN = {
2 | editable: false,
3 | filterable: false,
4 | resizable: true
5 | };
6 |
7 | function getColumns(columnValues) {
8 | return columnValues.map(value => Object.assign({}, DEFAULT_COLUMN, value));
9 | }
10 |
11 | module.exports = {
12 | getColumns
13 | };
--------------------------------------------------------------------------------
/project-fortis-interfaces/src/components/Footer.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import logo from '../images/MSFT_logo_png.png';
3 | import '../styles/Footer.css';
4 |
5 | class Footer extends Component {
6 | render() {
7 | return (
8 |
18 | );
19 | }
20 |
21 | }
22 |
23 | export default Footer;
24 |
--------------------------------------------------------------------------------
/project-fortis-interfaces/src/components/Graphics/GraphCard.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import {Card, CardHeader, CardTitle, CardActions, CardMedia} from 'material-ui/Card';
3 |
4 | import styles from '../../styles/Graphics/styles';
5 | import '../../styles/Graphics/GraphCard.css';
6 |
7 | export default class GraphCard extends Component {
8 | render() {
9 | return (
10 |
11 | {
12 | this.props.cardHeader ?
13 | : undefined
14 | }
15 |
16 | {this.props.children}
17 |
18 | {
19 | this.props.cardTitle ? : undefined
20 | }
21 | {
22 | this.props.cardActions ?
23 |
24 | {this.props.cardActions}
25 | : undefined
26 | }
27 |
28 | );
29 | }
30 | }
--------------------------------------------------------------------------------
/project-fortis-interfaces/src/components/Graphics/NoData.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import IconButton from 'material-ui/IconButton';
3 | import ActionHighlightOff from 'material-ui/svg-icons/action/highlight-off';
4 | import { fullWhite } from 'material-ui/styles/colors';
5 |
6 | export default class NoData extends React.Component {
7 | render() {
8 | return (
9 |
10 |
11 |
12 | );
13 | }
14 | };
15 |
--------------------------------------------------------------------------------
/project-fortis-interfaces/src/components/Graphics/Sentiment.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { getSentimentAttributes } from '../Insights/shared';
3 |
4 | export default class Sentiment extends React.Component {
5 | render() {
6 | const { value, showGraph } = this.props;
7 | const sentiment = getSentimentAttributes(value);
8 | const className = `material-icons sentimentIcon ${sentiment.style}`;
9 | const sentimentIcon = {sentiment.icon};
10 | const displayValue = parseFloat(value * 10).toFixed(0);
11 | const graphbarClassname = `sentimentGraphBar ${sentiment.style}`;
12 |
13 | if (!showGraph) {
14 | return {sentimentIcon}
;
15 | }
16 |
17 | return (
18 |
19 |
20 |
21 | { displayValue }
22 |
23 | {sentimentIcon}
24 |
25 |
26 | );
27 | }
28 | };
29 |
--------------------------------------------------------------------------------
/project-fortis-interfaces/src/components/Graphics/Timeline.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import numeralLibs from 'numeral';
3 | import { AreaChart, XAxis, CartesianGrid, Brush, YAxis, Tooltip, Legend, ResponsiveContainer } from 'recharts';
4 |
5 | const toNumericDisplay = (decimal, fixed = 0) => {
6 | return numeralLibs(decimal).format(decimal > 1000 ? '+0.0a' : '0a');
7 | };
8 |
9 | function highestCountFirst(item1, item2) {
10 | if (!item1 || !item1.value) return -1;
11 | if (!item2 || !item2.value) return 1;
12 | return item1.value < item2.value;
13 | }
14 |
15 | export default class Timeline extends Component {
16 | render() {
17 | return (
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 | {this.props.children}
28 |
29 |
30 |
31 |
32 | {this.props.children}
33 |
34 |
35 | );
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/project-fortis-interfaces/src/components/Graphics/WordCloud.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import { ResponsiveContainer } from 'recharts';
3 | import { TagCloud } from "react-tagcloud";
4 |
5 | const style = {
6 | display: 'table'
7 | };
8 |
9 | /**
10 | * Render the cloud using D3. Not stateless, because async rendering of d3-cloud
11 | */
12 | export default class WordCloud extends Component {
13 | constructor(props) {
14 | super(props);
15 | this.state = {
16 | cloudDimensions: []
17 | };
18 | }
19 |
20 | render() {
21 | const { words, minSize, maxSize, customRenderer, onClick } = this.props;
22 |
23 | return (
24 |
25 |
31 |
32 | );
33 | }
34 | }
--------------------------------------------------------------------------------
/project-fortis-interfaces/src/components/Header/index.js:
--------------------------------------------------------------------------------
1 | import Header from './Header';
2 |
3 | export default Header;
--------------------------------------------------------------------------------
/project-fortis-interfaces/src/components/Insights/CategoryPicker.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ContentFilterList from 'material-ui/svg-icons/content/filter-list';
3 | import { fullWhite } from 'material-ui/styles/colors';
4 | import DrawerActionsIconButton from './DrawerActionsIconButton';
5 |
6 | const CATEGORY_ALL = '';
7 |
8 | export default class CategoryPicker extends React.Component {
9 | formatCategory = (category) => category || 'all';
10 | formatText = (category) => `Reload with category '${this.formatCategory(category)}'`;
11 | formatLabel = (category) => `Category: ${this.formatCategory(category)}`;
12 | formatTooltip = (category) => `Current category: '${this.formatCategory(category)}'. Click to change category`;
13 |
14 | render() {
15 | const { category, allCategories, tooltipPosition, onChangeCategory } = this.props;
16 |
17 | return (
18 | }
26 | tooltipPosition={tooltipPosition}
27 | />
28 | );
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/project-fortis-interfaces/src/components/Insights/DrawerActionsIconButton.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Drawer from 'material-ui/Drawer';
3 | import IconButton from 'material-ui/IconButton';
4 | import MenuItem from 'material-ui/MenuItem';
5 |
6 | export default class DrawerActionsIconButton extends React.Component {
7 | constructor(props) {
8 | super(props);
9 | this.state = {
10 | open: false
11 | };
12 | }
13 |
14 | onClick = (value) => {
15 | this.props.onClick(value);
16 | this.setState({ open: false });
17 | }
18 |
19 | handleDrawerToggle = () => {
20 | this.setState({ open: !this.state.open });
21 | }
22 |
23 | handleDrawerChange = (open) => {
24 | this.setState({ open });
25 | }
26 |
27 | renderMenuItems() {
28 | return this.props.items.map((item) =>
29 |