├── data ├── db │ ├── __init__.py │ └── utils.py ├── intelligence │ ├── __init__.py │ ├── translate.sh │ └── translate.py ├── prod_generation │ ├── __init__.py │ ├── db_config.yaml │ ├── academic_titles.txt │ ├── utils.py │ ├── graph_tools.py │ ├── regenerate_prod_data.sh │ └── generate_public_dumps.py ├── db_config_data.yaml ├── db_config_update_source.yaml ├── run.sh ├── test.sh ├── requirements.txt ├── deploy.sh ├── update_rpvs.sh ├── update_KamIduEurofondy.sh ├── update_finstat.sh ├── geocoder_test.py ├── utils.py ├── kamidueurofondy.py ├── server.py ├── sources.json ├── clean_db.py └── test.py ├── kataster ├── db_config.yaml ├── run.sh ├── requirements.txt └── deploy.sh ├── obstaravania ├── notifications │ ├── templates │ │ ├── cache │ │ │ └── .gitkeep │ │ ├── compiled │ │ │ └── .gitkeep │ │ ├── template1.odt │ │ ├── footer.tpl │ │ └── header.tpl │ ├── resources │ │ ├── SKico.png │ │ ├── date.png │ │ ├── date2.png │ │ ├── place.png │ │ ├── deadline.png │ │ └── deadline2.png │ ├── .gitignore │ ├── composer.json │ ├── README.md │ └── sample_data │ │ ├── one.json │ │ └── one_new.json ├── db_config.yaml ├── db_config_old.yaml ├── pdfsender │ ├── .gitignore │ ├── libs │ │ ├── RetryableException.php │ │ └── zelenaposta │ │ │ ├── api2 │ │ │ ├── Request.php │ │ │ ├── SentClient.php │ │ │ └── UserClient.php │ │ │ ├── SentApiConfig.php │ │ │ ├── UserApiConfig.php │ │ │ └── ProductApiConfig.php │ ├── composer.json │ ├── README.md │ └── sendpdf.php ├── shards │ └── README ├── run.sh ├── requirements.txt ├── deploy.sh ├── skip_norms.txt ├── test.py ├── static │ └── obstaravania.js ├── db_old.py ├── stop_words.txt └── suspicious.py ├── verejne ├── db_config.yaml ├── run.sh ├── deploy.sh └── requirements.txt ├── prepojenia ├── db_config.yaml ├── run.sh ├── requirements.txt └── deploy.sh ├── client ├── .env.development ├── public │ ├── chv.png │ ├── nzk.png │ ├── tis.png │ ├── uvo.png │ ├── vl.png │ ├── SKico.png │ ├── favicon.ico │ ├── finstat.png │ ├── slovenko.png │ ├── favicon-32x32.png │ ├── politician_default.png │ ├── politician_default_s.png │ ├── manifest.json │ └── index.html ├── .flowconfig ├── src │ ├── components │ │ ├── Landing │ │ │ ├── icons │ │ │ │ ├── ihrisko.png │ │ │ │ ├── profily.png │ │ │ │ ├── prepojenia.png │ │ │ │ ├── public_data.png │ │ │ │ ├── obstaravania.png │ │ │ │ └── ihrisko.svg │ │ │ ├── Card.scss │ │ │ ├── Card.js │ │ │ └── Landing.scss │ │ ├── Public │ │ │ ├── Map │ │ │ │ ├── GoogleMap.scss │ │ │ │ ├── Marker │ │ │ │ │ ├── Marker.js │ │ │ │ │ └── Marker.scss │ │ │ │ ├── AddressDetail │ │ │ │ │ ├── ListRow.scss │ │ │ │ │ └── AddressDetail.scss │ │ │ │ └── ClusterMarker │ │ │ │ │ └── ClusterMarker.scss │ │ │ ├── EntitySearchResultItem │ │ │ │ ├── EntitySearchResultItem.scss │ │ │ │ └── EntitySearchResultItem.js │ │ │ ├── Public.scss │ │ │ ├── EntitySearch │ │ │ │ ├── EntitySearchModal.scss │ │ │ │ ├── EntitySearch.scss │ │ │ │ └── EntitySearch.js │ │ │ ├── Public.js │ │ │ ├── Sidebar │ │ │ │ └── Sidebar.scss │ │ │ └── EntitySearchAutocomplete │ │ │ │ └── EntitySearchAutocomplete.scss │ │ ├── shared │ │ │ ├── Info │ │ │ │ ├── InfoList.scss │ │ │ │ ├── Trend.scss │ │ │ │ ├── FinancesItem.scss │ │ │ │ ├── Item.scss │ │ │ │ ├── Trend.js │ │ │ │ ├── Relations.js │ │ │ │ ├── Item.js │ │ │ │ ├── InfoButton.scss │ │ │ │ ├── Eurofunds.js │ │ │ │ ├── Finances.js │ │ │ │ ├── Contracts.js │ │ │ │ ├── Notices.js │ │ │ │ ├── FinancesItem.js │ │ │ │ ├── Findata.js │ │ │ │ ├── RecursiveInfo.js │ │ │ │ ├── InfoButton.js │ │ │ │ ├── Info.scss │ │ │ │ └── RelationList.js │ │ │ ├── ExternalLink.js │ │ │ ├── CompanyDetails.js │ │ │ ├── CircleIcon.scss │ │ │ ├── AutoComplete │ │ │ │ └── AutoComplete.scss │ │ │ ├── withTracker.js │ │ │ ├── ToggleBox.scss │ │ │ ├── CircleIcon.js │ │ │ ├── Legend │ │ │ │ └── Legend.scss │ │ │ ├── ToggleBox.js │ │ │ └── utilities.js │ │ ├── App.scss │ │ ├── Connections │ │ │ ├── components │ │ │ │ ├── Statuses.scss │ │ │ │ ├── SubgraphInstructions.scss │ │ │ │ ├── InfoLoader.scss │ │ │ │ ├── Subgraph.scss │ │ │ │ ├── Results.scss │ │ │ │ ├── DummyResults.js │ │ │ │ ├── InfoLoader.js │ │ │ │ ├── graph │ │ │ │ │ └── gestures.js │ │ │ │ └── Statuses.js │ │ │ ├── Connections.scss │ │ │ ├── Connections.js │ │ │ └── dataWrappers │ │ │ │ ├── EntitySearchWrapper.js │ │ │ │ ├── EntityWrapper.js │ │ │ │ └── ConnectionWrapper.js │ │ ├── Search │ │ │ ├── Search.scss │ │ │ └── Search.js │ │ ├── Notices │ │ │ ├── NoticeDetail.scss │ │ │ ├── utilities.js │ │ │ ├── CompaniesTable.scss │ │ │ ├── Company.scss │ │ │ ├── NoticeSidebar.scss │ │ │ ├── Legend.js │ │ │ ├── NoticeItem.scss │ │ │ ├── NoticeSidebar.js │ │ │ ├── NoticeInformation.js │ │ │ ├── NoticeInformation.scss │ │ │ ├── LegendSymbols.scss │ │ │ ├── Bulletin.scss │ │ │ ├── LegendSymbols.js │ │ │ ├── Legend.scss │ │ │ ├── Bulletin.js │ │ │ ├── NoticeList.scss │ │ │ ├── CompaniesTable.js │ │ │ └── NoticeItem.js │ │ ├── Profile │ │ │ ├── components │ │ │ │ ├── DetailCadastralTable.scss │ │ │ │ ├── DetailCadastralLV.scss │ │ │ │ ├── DetailAssets.scss │ │ │ │ ├── MapContainer.scss │ │ │ │ ├── PoliticiansList.scss │ │ │ │ ├── Cardboard.scss │ │ │ │ ├── PoliticiansListWrapper.js │ │ │ │ ├── DetailCadastralLV.js │ │ │ │ ├── MapContainer.js │ │ │ │ ├── DetailAssets.js │ │ │ │ └── Politician.js │ │ │ ├── DetailPage.scss │ │ │ ├── Profile.scss │ │ │ └── utilities.js │ │ ├── Loading │ │ │ ├── Loading.scss │ │ │ └── Loading.js │ │ ├── Playground │ │ │ └── components │ │ │ │ ├── ColabDetail.js │ │ │ │ └── ColabList.js │ │ ├── GoogleMap │ │ │ └── GoogleMap.js │ │ ├── PlacesAutocomplete │ │ │ ├── PlacesAutocomplete.scss │ │ │ └── PlacesAutocomplete.js │ │ ├── Navigation.scss │ │ ├── variables.scss │ │ └── App.js │ ├── types │ │ ├── profileTypes.js │ │ ├── commonTypes.js │ │ └── reduxTypes.js │ ├── actions │ │ ├── colabActions.js │ │ ├── connectionsActions.js │ │ ├── profileActions.js │ │ └── sharedActions.js │ ├── customBootstrap.scss │ ├── dataProviders │ │ ├── dataProvidersUtils.js │ │ ├── colabDataProviders.js │ │ ├── noticesDataProviders.js │ │ └── publiclyDataProviders.js │ ├── rootReducer.js │ ├── configureStore.js │ ├── services │ │ └── map.js │ ├── slovakiaData │ │ └── region-centers.json │ ├── dataWrappers │ │ └── CompanyDetailWrapper.js │ ├── assets │ │ └── mapIcon.svg │ └── index.js ├── .stylelintrc ├── flow-typed │ └── npm │ │ ├── flow-bin_v0.x.x.js │ │ ├── node-sass-chokidar_vx.x.x.js │ │ ├── eslint-config-vacuumlabs_vx.x.x.js │ │ ├── prettier-eslint_vx.x.x.js │ │ ├── qs_v6.5.x.js │ │ ├── redux-thunk_vx.x.x.js │ │ └── redux-logger_vx.x.x.js ├── .eslintrc ├── .gitignore ├── check_flow.py └── README.md ├── .gitignore ├── static ├── favicon.ico └── favicon-32x32.png ├── .hgtags └── test_all.sh /data/db/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /data/intelligence/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /data/prod_generation/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /data/db_config_data.yaml: -------------------------------------------------------------------------------- 1 | user: data 2 | db: vd 3 | -------------------------------------------------------------------------------- /kataster/db_config.yaml: -------------------------------------------------------------------------------- 1 | user: kataster 2 | db: vd 3 | -------------------------------------------------------------------------------- /obstaravania/notifications/templates/cache/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /verejne/db_config.yaml: -------------------------------------------------------------------------------- 1 | user: verejne 2 | db: vd 3 | -------------------------------------------------------------------------------- /obstaravania/notifications/templates/compiled/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /prepojenia/db_config.yaml: -------------------------------------------------------------------------------- 1 | user: prepojenia 2 | db: vd 3 | -------------------------------------------------------------------------------- /obstaravania/db_config.yaml: -------------------------------------------------------------------------------- 1 | user: obstaravania 2 | db: vd 3 | -------------------------------------------------------------------------------- /data/db_config_update_source.yaml: -------------------------------------------------------------------------------- 1 | user: datautils 2 | db: vd 3 | -------------------------------------------------------------------------------- /data/prod_generation/db_config.yaml: -------------------------------------------------------------------------------- 1 | user: datautils 2 | db: vd 3 | -------------------------------------------------------------------------------- /obstaravania/db_config_old.yaml: -------------------------------------------------------------------------------- 1 | user: obstaravania 2 | db: verejne -------------------------------------------------------------------------------- /client/.env.development: -------------------------------------------------------------------------------- 1 | REACT_APP_API_URL=https://verejne.digital 2 | REACT_APP_BASENAME= -------------------------------------------------------------------------------- /data/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | . venv/bin/activate 4 | 5 | exec python ./server.py $@ 6 | -------------------------------------------------------------------------------- /prepojenia/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | . venv/bin/activate 4 | 5 | exec ./server.py $@ 6 | -------------------------------------------------------------------------------- /verejne/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | . venv/bin/activate 4 | 5 | exec python ./server.py $@ 6 | -------------------------------------------------------------------------------- /kataster/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | . venv/bin/activate 4 | 5 | exec python ./server.py $@ 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | **/package-lock.json 2 | .vscode 3 | **/venv 4 | *.pyc 5 | *.DS_Store 6 | ._* 7 | *~ 8 | -------------------------------------------------------------------------------- /obstaravania/pdfsender/.gitignore: -------------------------------------------------------------------------------- 1 | err 2 | out 3 | input 4 | *.xml 5 | .idea 6 | vendor 7 | *.pdf 8 | -------------------------------------------------------------------------------- /static/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verejnedigital/verejne.digital/HEAD/static/favicon.ico -------------------------------------------------------------------------------- /client/public/chv.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verejnedigital/verejne.digital/HEAD/client/public/chv.png -------------------------------------------------------------------------------- /client/public/nzk.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verejnedigital/verejne.digital/HEAD/client/public/nzk.png -------------------------------------------------------------------------------- /client/public/tis.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verejnedigital/verejne.digital/HEAD/client/public/tis.png -------------------------------------------------------------------------------- /client/public/uvo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verejnedigital/verejne.digital/HEAD/client/public/uvo.png -------------------------------------------------------------------------------- /client/public/vl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verejnedigital/verejne.digital/HEAD/client/public/vl.png -------------------------------------------------------------------------------- /prepojenia/requirements.txt: -------------------------------------------------------------------------------- 1 | argparse 2 | paste 3 | psycopg2 4 | PyYAML 5 | webapp2>=3.0.0b1 6 | webob 7 | -------------------------------------------------------------------------------- /client/public/SKico.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verejnedigital/verejne.digital/HEAD/client/public/SKico.png -------------------------------------------------------------------------------- /kataster/requirements.txt: -------------------------------------------------------------------------------- 1 | paste 2 | psycopg2 3 | PyYaml 4 | requests 5 | webapp2>=3.0.0b1 6 | webob 7 | tqdm 8 | -------------------------------------------------------------------------------- /client/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verejnedigital/verejne.digital/HEAD/client/public/favicon.ico -------------------------------------------------------------------------------- /client/public/finstat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verejnedigital/verejne.digital/HEAD/client/public/finstat.png -------------------------------------------------------------------------------- /client/public/slovenko.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verejnedigital/verejne.digital/HEAD/client/public/slovenko.png -------------------------------------------------------------------------------- /data/intelligence/translate.sh: -------------------------------------------------------------------------------- 1 | export GOOGLE_APPLICATION_CREDENTIALS=/tmp/service.json 2 | python translate.py 3 | -------------------------------------------------------------------------------- /static/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verejnedigital/verejne.digital/HEAD/static/favicon-32x32.png -------------------------------------------------------------------------------- /.hgtags: -------------------------------------------------------------------------------- 1 | cebf1fedb8cff7bd02d8f0165ccb0afcf5aa1921 kataster/canary 2 | cebf1fedb8cff7bd02d8f0165ccb0afcf5aa1921 kataster/prod 3 | -------------------------------------------------------------------------------- /client/public/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verejnedigital/verejne.digital/HEAD/client/public/favicon-32x32.png -------------------------------------------------------------------------------- /obstaravania/pdfsender/libs/RetryableException.php: -------------------------------------------------------------------------------- 1 | =3.0.0b1 7 | webob==1.8.6 8 | -------------------------------------------------------------------------------- /client/src/components/Landing/icons/prepojenia.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verejnedigital/verejne.digital/HEAD/client/src/components/Landing/icons/prepojenia.png -------------------------------------------------------------------------------- /client/src/components/Landing/icons/public_data.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verejnedigital/verejne.digital/HEAD/client/src/components/Landing/icons/public_data.png -------------------------------------------------------------------------------- /obstaravania/notifications/resources/deadline.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verejnedigital/verejne.digital/HEAD/obstaravania/notifications/resources/deadline.png -------------------------------------------------------------------------------- /obstaravania/notifications/resources/deadline2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verejnedigital/verejne.digital/HEAD/obstaravania/notifications/resources/deadline2.png -------------------------------------------------------------------------------- /obstaravania/notifications/templates/template1.odt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verejnedigital/verejne.digital/HEAD/obstaravania/notifications/templates/template1.odt -------------------------------------------------------------------------------- /client/.stylelintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "stylelint-config-standard", 3 | "rules": { 4 | "number-leading-zero": "never" 5 | }, 6 | "ignoreFiles": ["**/*.js"] 7 | } -------------------------------------------------------------------------------- /client/src/components/Landing/icons/obstaravania.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verejnedigital/verejne.digital/HEAD/client/src/components/Landing/icons/obstaravania.png -------------------------------------------------------------------------------- /client/src/components/Public/Map/GoogleMap.scss: -------------------------------------------------------------------------------- 1 | @import '../../variables.scss'; 2 | 3 | .google-map-wrapper { 4 | width: 100%; 5 | height: 100%; 6 | overflow: hidden; 7 | } 8 | -------------------------------------------------------------------------------- /obstaravania/notifications/.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | vendor 3 | *.pdf 4 | out/* 5 | templates/compiled/* 6 | !templates/compiled/.gitkeep 7 | templates/cache/* 8 | !templates/cache/.gitkeep 9 | -------------------------------------------------------------------------------- /client/src/components/shared/Info/InfoList.scss: -------------------------------------------------------------------------------- 1 | ul.infoList { 2 | padding: 0 12px; 3 | 4 | li { 5 | padding: 0 12px; 6 | } 7 | } 8 | 9 | .clickable { 10 | cursor: pointer; 11 | } 12 | -------------------------------------------------------------------------------- /client/src/components/Public/EntitySearchResultItem/EntitySearchResultItem.scss: -------------------------------------------------------------------------------- 1 | @import '../../variables.scss'; 2 | 3 | .location { 4 | height: 1rem; 5 | margin-left: .3rem; 6 | cursor: pointer; 7 | } 8 | -------------------------------------------------------------------------------- /client/src/components/Public/Public.scss: -------------------------------------------------------------------------------- 1 | .wrapper { 2 | overflow: hidden; 3 | height: 100%; 4 | } 5 | 6 | .entity-search-modal { 7 | .modal-body { 8 | min-height: 150px; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /obstaravania/requirements.txt: -------------------------------------------------------------------------------- 1 | argparse 2 | enum34 3 | gensim 4 | htmlmin 5 | jinja2 6 | numpy 7 | paste 8 | psycopg2 9 | python-dateutil 10 | PyYAML 11 | sqlalchemy 12 | webapp2>=3.0.0b1 13 | webob 14 | -------------------------------------------------------------------------------- /client/src/components/shared/Info/Trend.scss: -------------------------------------------------------------------------------- 1 | @import '../../variables.scss'; 2 | 3 | span.profit { 4 | color: $plus-value-color; 5 | } 6 | 7 | span.deficit { 8 | color: $minus-value-color; 9 | } 10 | -------------------------------------------------------------------------------- /client/src/components/shared/Info/FinancesItem.scss: -------------------------------------------------------------------------------- 1 | @import '../../variables.scss'; 2 | 3 | .finances-item { 4 | & + & { 5 | border-top: 1px dashed $border-color; 6 | padding-top: .5em; 7 | margin-top: .5em; 8 | } 9 | } -------------------------------------------------------------------------------- /client/src/types/profileTypes.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | export type ParsedAssetDeclarationsType = { 4 | unmovable_assets: Array, 5 | movable_assets: Array, 6 | income_assets: Array, 7 | source: string, 8 | } 9 | -------------------------------------------------------------------------------- /client/flow-typed/npm/flow-bin_v0.x.x.js: -------------------------------------------------------------------------------- 1 | // flow-typed signature: 6a5610678d4b01e13bbfbbc62bdaf583 2 | // flow-typed version: 3817bc6980/flow-bin_v0.x.x/flow_>=v0.25.x 3 | 4 | declare module 'flow-bin' { 5 | declare module.exports: string 6 | } 7 | -------------------------------------------------------------------------------- /client/src/components/shared/Info/Item.scss: -------------------------------------------------------------------------------- 1 | @import '../../variables.scss'; 2 | 3 | .info-item { 4 | padding: .5em 0; 5 | } 6 | 7 | .info-item-label { 8 | color: $secondary; 9 | font-weight: normal; 10 | margin-right: .5em; 11 | } 12 | -------------------------------------------------------------------------------- /client/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "vacuumlabs", 3 | "env": { 4 | "browser": true, 5 | "node": true, 6 | "jest": true 7 | }, 8 | "rules": { 9 | "no-duplicate-imports": 0, 10 | "import/no-duplicates": "error" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /client/src/actions/colabActions.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import type {Colab} from '../state' 3 | 4 | export const setColabs = (colabs: Colab[]) => ({ 5 | type: 'Set colabs', 6 | path: ['colabs'], 7 | payload: colabs, 8 | reducer: () => colabs, 9 | }) 10 | -------------------------------------------------------------------------------- /client/src/components/App.scss: -------------------------------------------------------------------------------- 1 | @import "./variables.scss"; 2 | 3 | html, 4 | body, 5 | #root, 6 | .application-container { 7 | height: 100%; 8 | } 9 | 10 | .screen-container { 11 | height: calc(100% - #{$navbar-height}); 12 | overflow: auto; 13 | } 14 | -------------------------------------------------------------------------------- /client/src/actions/connectionsActions.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | export const setAddNeighboursLimit = (limit: string | null) => ({ 4 | type: 'Set add neighbours limit', 5 | path: ['connections', 'addNeighboursLimit'], 6 | payload: limit, 7 | reducer: () => limit, 8 | }) 9 | -------------------------------------------------------------------------------- /client/src/components/Connections/components/Statuses.scss: -------------------------------------------------------------------------------- 1 | @import "../../variables.scss"; 2 | 3 | .statuses { 4 | margin-top: 2rem; 5 | font-size: 1rem; 6 | 7 | span { 8 | color: $secondary; 9 | } 10 | 11 | strong { 12 | color: $text; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /data/test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Execute `deploy.sh` first to install virtual environment in ./venv: 4 | # virtualenv-2.7 ./venv \ 5 | # && . venv/bin/activate \ 6 | # && pip install -r requirements.txt; 7 | 8 | . venv/bin/activate 9 | sudo -u data python test.py; 10 | deactivate; 11 | -------------------------------------------------------------------------------- /client/src/components/Search/Search.scss: -------------------------------------------------------------------------------- 1 | .search-autocomplete-wrapper { 2 | width: calc(100% - 34px); 3 | padding: 0; 4 | } 5 | 6 | .search-page-btn { 7 | width: 34px; 8 | height: calc(100% - 1px); 9 | svg { 10 | position: absolute; 11 | transform: translate(-50%, -50%); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /data/db/utils.py: -------------------------------------------------------------------------------- 1 | """Utility methods for package db.""" 2 | 3 | import yaml 4 | 5 | 6 | def yaml_load(path): 7 | with open(path, 'r', encoding='utf-8') as f: 8 | # data_yaml = yaml.load(f, Loader=yaml.FullLoader) 9 | data_yaml = yaml.load(f, Loader=yaml.FullLoader) 10 | return data_yaml 11 | -------------------------------------------------------------------------------- /data/requirements.txt: -------------------------------------------------------------------------------- 1 | paste==3.4.4 2 | psycopg2==2.8.6 3 | PyYaml==5.3.1 4 | requests==2.24.0 5 | webapp2>=3.0.0b1 6 | webob==1.8.6 7 | numpy==1.19.2 8 | scipy==1.5.2 9 | # smart-open==1.10.0 # solves bug in printing an warning message https://github.com/RaRe-Technologies/smart_open/issues/475 10 | smart-open==2.2.0 11 | -------------------------------------------------------------------------------- /client/src/components/Connections/components/SubgraphInstructions.scss: -------------------------------------------------------------------------------- 1 | @import '../../variables.scss'; 2 | 3 | .graph-instructions { 4 | .limit { 5 | cursor: pointer; 6 | } 7 | 8 | .limit-input { 9 | display: inline-block; 10 | padding: 0; 11 | width: 2rem; 12 | max-height: 1.3rem; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /client/src/components/Notices/NoticeDetail.scss: -------------------------------------------------------------------------------- 1 | @import '../variables.scss'; 2 | 3 | .notice-detail { 4 | padding-top: 40px; 5 | } 6 | 7 | .notice-detail-title { 8 | padding-left: 20px; 9 | margin-bottom: 30px; 10 | } 11 | 12 | .notice-detail-table { 13 | box-shadow: 0 4px 12px $shadow-color; 14 | margin-bottom: 30px; 15 | } 16 | -------------------------------------------------------------------------------- /client/src/components/Profile/components/DetailCadastralTable.scss: -------------------------------------------------------------------------------- 1 | .pagination-wrapper { 2 | display: flex; 3 | justify-content: center; 4 | align-items: center; 5 | } 6 | 7 | .scroll-container { 8 | margin: auto; 9 | max-height: 100%; 10 | overflow: auto; 11 | } 12 | 13 | .assets-cadastral { 14 | background: white; 15 | } 16 | -------------------------------------------------------------------------------- /client/src/components/Profile/components/DetailCadastralLV.scss: -------------------------------------------------------------------------------- 1 | @import '../../variables.scss'; 2 | 3 | article.profile { 4 | .key { 5 | color: grey; 6 | } 7 | 8 | .podiel { 9 | color: grey; 10 | padding-left: 10px; 11 | } 12 | 13 | .parcel:hover { 14 | background-color: $asset-hover-color; 15 | cursor: pointer; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /client/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "Verejne.digital", 3 | "name": "Verejne.digital", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | } 10 | ], 11 | "start_url": "./index.html", 12 | "display": "standalone", 13 | "theme_color": "#000000", 14 | "background_color": "#ffffff" 15 | } 16 | -------------------------------------------------------------------------------- /client/src/customBootstrap.scss: -------------------------------------------------------------------------------- 1 | // Your variable overrides 2 | $body-bg: #f1f4f5; 3 | $body-color: #333; 4 | $card-border-color: #cddae3; 5 | $card-border-width: 3px; 6 | $blue: #0062db; 7 | $font-size-base: .875rem; 8 | $h1-font-size: 24px; 9 | $link-color: $blue; 10 | $headings-font-weight: bold; 11 | 12 | // Bootstrap and its default variables 13 | @import "node_modules/bootstrap/scss/bootstrap"; 14 | -------------------------------------------------------------------------------- /client/src/components/Public/EntitySearch/EntitySearchModal.scss: -------------------------------------------------------------------------------- 1 | @import "../../variables.scss"; 2 | 3 | .modal-body { 4 | .publicly-modal-autocomplete-menu { 5 | width: calc(100% - 3px); 6 | max-height: calc(100vh - 150px); 7 | } 8 | .publicly-modal-autocomplete-input { 9 | width: 100%; 10 | } 11 | .publicly-modal-autocomplete-wrapper { 12 | width: calc(100% - 42px); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /client/src/components/Connections/components/InfoLoader.scss: -------------------------------------------------------------------------------- 1 | @import "../../variables.scss"; 2 | 3 | .info-loader-connection-line { 4 | height: 30px; 5 | width: 8px; 6 | background-color: $border-color; 7 | margin-left: 40px; 8 | } 9 | 10 | .info-loader:last-of-type > .container > .info-loader-connection-line { 11 | display: none; 12 | } 13 | 14 | .info-loader > .container { 15 | padding: 0; 16 | } 17 | 18 | -------------------------------------------------------------------------------- /client/src/components/shared/ExternalLink.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import * as React from 'react' 3 | import {FaExternalLinkAlt} from 'react-icons/fa' 4 | 5 | type Props = { 6 | url: string, 7 | children?: React.Node, 8 | } 9 | 10 | const ExternalLink = ({url, children}: Props) => ( 11 | 12 | {children} 13 | 14 | ) 15 | 16 | export default ExternalLink 17 | -------------------------------------------------------------------------------- /obstaravania/notifications/templates/footer.tpl: -------------------------------------------------------------------------------- 1 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /client/src/components/Connections/components/Subgraph.scss: -------------------------------------------------------------------------------- 1 | @import '../../variables.scss'; 2 | 3 | .subgraph { 4 | margin-bottom: 30px; 5 | 6 | .graph { 7 | display: block; 8 | margin-left: auto; 9 | margin-right: auto; 10 | margin-bottom: 0; 11 | padding: 10px; 12 | background-color: $component-background; 13 | border: 2px solid $border-color; 14 | border-radius: 2px; 15 | box-shadow: 0 4px 12px 0 $shadow-color; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /client/src/components/shared/CompanyDetails.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import React from 'react' 3 | import CompanyDetailWrapper from '../../dataWrappers/CompanyDetailWrapper' 4 | import type {CompanyDetailProps} from '../../dataWrappers/CompanyDetailWrapper' 5 | import Info from '../shared/Info/Info' 6 | 7 | const CompanyDetails = ({company, onClose}: CompanyDetailProps) => 8 | 9 | 10 | export default CompanyDetailWrapper(CompanyDetails) 11 | -------------------------------------------------------------------------------- /data/deploy.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # set bash strict mode - fail immediately if anything fails 4 | set -eu 5 | IFS=$'\n\t' 6 | 7 | echo "Removing old environment..." 8 | rm -rf ./venv 9 | 10 | echo "Creating new environment..." 11 | python -m venv venv 12 | echo "Activating new environment..." 13 | . venv/bin/activate 14 | echo "Installing requirements..." 15 | pip install --upgrade pip 16 | pip install wheel==0.35.1 17 | pip install Cython==0.29.21 18 | pip install -r requirements.txt 19 | -------------------------------------------------------------------------------- /client/src/types/commonTypes.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import type {Dispatch} from './reduxTypes' 3 | 4 | export type ObjectMap = {[string]: T} 5 | 6 | export type OnDataFunction = (ref: string, data: any, dispatch: Dispatch) => void 7 | 8 | // use with recompose.withState updater 9 | // https://github.com/acdlite/recompose/blob/master/docs/API.md#withstate 10 | export type StateUpdater = ( 11 | (prevValue: T) => T, 12 | callback?: Function 13 | ) => void | ((newValue: T, callback?: Function) => void) 14 | -------------------------------------------------------------------------------- /obstaravania/deploy.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # set bash strict mode - fail immediately if anything fails 4 | set -eu 5 | IFS=$'\n\t' 6 | 7 | echo "Removing old environment..." 8 | rm -rf ./venv 9 | 10 | echo "Creating new environment..." 11 | python -m venv venv 12 | echo "Activating new environment..." 13 | . venv/bin/activate 14 | echo "Installing requirements..." 15 | pip install --upgrade pip 16 | pip install wheel==0.35.1 17 | pip install Cython==0.29.21 18 | pip install -r requirements.txt 19 | -------------------------------------------------------------------------------- /obstaravania/notifications/templates/header.tpl: -------------------------------------------------------------------------------- 1 | 2 | 12 | 13 | 14 | 15 | 16 | 17 |
verejne.digital{$date}
18 | -------------------------------------------------------------------------------- /client/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | 6 | # testing 7 | /coverage 8 | 9 | # production 10 | /build 11 | 12 | # misc 13 | .DS_Store 14 | .env.local 15 | .env.development.local 16 | .env.test.local 17 | .env.production.local 18 | 19 | npm-debug.log* 20 | yarn-debug.log* 21 | yarn-error.log* 22 | 23 | # we're using sass, css files are built automatically 24 | src/**/*.css 25 | 26 | # flow coverage 27 | flow-coverage 28 | -------------------------------------------------------------------------------- /client/src/components/Profile/components/DetailAssets.scss: -------------------------------------------------------------------------------- 1 | @import '../../variables.scss'; 2 | 3 | article.profile { 4 | table.assets-declaration { 5 | border-bottom-style: double; 6 | width: 100%; 7 | background: white; 8 | 9 | .source { 10 | color: gray; 11 | font-weight: normal; 12 | padding-left: 20px; 13 | } 14 | 15 | .plot { 16 | max-width: 100%; 17 | } 18 | 19 | .asset:hover { 20 | background-color: $asset-hover-color; 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /obstaravania/pdfsender/libs/zelenaposta/api2/Request.php: -------------------------------------------------------------------------------- 1 | $value) { 12 | if (is_array($value)) { 13 | $value = static::createObjectFromArray($value); 14 | } 15 | $object->{$key} = $value; 16 | } 17 | return $object; 18 | } 19 | } -------------------------------------------------------------------------------- /client/src/components/shared/Info/Trend.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import React from 'react' 3 | import './Trend.css' 4 | 5 | type TrendProps = {| 6 | trend?: number, 7 | |} 8 | 9 | const Trend = ({trend}: TrendProps) => 10 | typeof trend === 'number' && ( 11 | 12 |  ( 13 | 0 ? 'profit' : 'deficit'}> 14 | {`${trend > 0 ? '+' : ''}${trend}%`} 15 | 16 | ) 17 | 18 | ) 19 | 20 | export default Trend 21 | -------------------------------------------------------------------------------- /client/src/components/Notices/utilities.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import {getWarningSymbol} from './LegendSymbols' 3 | 4 | import type {Notice} from '../../state' 5 | 6 | export function getWarning(item: Notice) { 7 | return item.estimated_value_amount && 8 | item.price_est_low && 9 | item.price_est_high && 10 | (item.estimated_value_amount < item.price_est_low || 11 | item.estimated_value_amount > item.price_est_high) 12 | ? getWarningSymbol(1, 'Vyhlásená cena nezodpovedá nášmu odhadu') 13 | : null 14 | } 15 | -------------------------------------------------------------------------------- /client/src/components/Public/Map/Marker/Marker.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import React from 'react' 3 | import classnames from 'classnames' 4 | import './Marker.css' 5 | 6 | import type {Node} from 'react' 7 | 8 | type MarkerProps = { 9 | className?: string, 10 | children?: Node, 11 | onClick?: () => void, 12 | } 13 | 14 | const Marker = ({className, children, onClick}: MarkerProps) => ( 15 |
16 | {children} 17 |
18 | ) 19 | 20 | export default Marker 21 | -------------------------------------------------------------------------------- /client/src/dataProviders/dataProvidersUtils.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import {receiveData} from '../actions/sharedActions' 3 | 4 | import type {Dispatch, Path} from '../types/reduxTypes' 5 | 6 | // helper to be used with data-provider 7 | export const dispatchReceivedData = ( 8 | path: Path, 9 | mappingFn: (Array | Object) => Object, 10 | ...mappingFnArgs: Array 11 | ) => (ref: string, data: Array | Object, dispatch: Dispatch) => { 12 | dispatch(receiveData(path, data, ref, mappingFn, ...mappingFnArgs)) 13 | } 14 | -------------------------------------------------------------------------------- /client/src/rootReducer.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import {forwardReducerTo} from './utils' 3 | import getInitialState from './state' 4 | 5 | import type {GenericAction} from './types/reduxTypes' 6 | import type {State} from './state' 7 | 8 | const rootReducer = (state: State = getInitialState(), action: GenericAction<*, *>) => { 9 | const {reducer, path, payload} = action 10 | // fallback for 3rd-party actions 11 | if (!reducer) return state 12 | return forwardReducerTo(reducer, path)(state, payload) 13 | } 14 | 15 | export default rootReducer 16 | -------------------------------------------------------------------------------- /client/src/components/Notices/CompaniesTable.scss: -------------------------------------------------------------------------------- 1 | @import '../variables.scss'; 2 | 3 | .companies-table { 4 | background-color: $component-background; 5 | padding: 0 0 0 20px; 6 | border-radius: 1px; 7 | margin-bottom: 0; 8 | } 9 | 10 | .companies-table-header tr th { 11 | color: $secondary; 12 | font-weight: normal; 13 | border-bottom: 1px solid $border-color; 14 | white-space: nowrap; 15 | background-color: $component-background; 16 | } 17 | 18 | .companies-table td { 19 | background-color: $component-background; 20 | } 21 | -------------------------------------------------------------------------------- /obstaravania/notifications/composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "verejne.digital/pdfcreator", 3 | "description": "tool to create PDF files with suggested offers from json", 4 | "type": "project", 5 | "require": { 6 | "php": ">=7", 7 | "tecnickcom/tcpdf": "^6.2", 8 | "smarty/smarty": "^3.1" 9 | }, 10 | "authors": [ 11 | { 12 | "name": "Martin Rejda", 13 | "email": "rejdi@ksp.sk" 14 | } 15 | ], 16 | "config": { 17 | "preferred-install": "dist" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /client/src/actions/profileActions.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import type {ObjectMap} from '../types/commonTypes' 3 | import type {PoliticiansSortKey, PoliticiansSortState} from '../state' 4 | 5 | export const setProfileSort = (section: string, sortKey: PoliticiansSortKey, reverse: boolean) => ({ 6 | type: 'Set addresses', 7 | path: ['profile', 'sorting'], 8 | payload: {sortKey, reverse}, 9 | reducer: (sortingState: ObjectMap, payload: PoliticiansSortState) => ({ 10 | ...sortingState, 11 | [section]: payload, 12 | }), 13 | }) 14 | -------------------------------------------------------------------------------- /data/prod_generation/academic_titles.txt: -------------------------------------------------------------------------------- 1 | akad 2 | arch 3 | ArtD 4 | BA 5 | BBA 6 | BBS 7 | Bc 8 | BcA 9 | BSBA 10 | BSc 11 | BTh 12 | CertHE 13 | CSc 14 | DBA 15 | DipHE 16 | DiM 17 | dipl 18 | DiS 19 | doc 20 | DPhil 21 | Dr 22 | DrSc 23 | DSc 24 | emer 25 | gen 26 | ICDr 27 | Ing 28 | Ing 29 | JUDr 30 | LLM 31 | mal 32 | MBA 33 | MDDr 34 | MIM 35 | mjr 36 | MgA 37 | Mgr 38 | MSc 39 | MSDr 40 | MUDr 41 | MVDr 42 | PaedDr 43 | PeaDr 44 | PharmDr 45 | Ph\.D 46 | PhD 47 | PhDr 48 | PhMr 49 | prof 50 | RNDr 51 | RSDr 52 | soch 53 | ThLic 54 | Th.D 55 | ThDr 56 | -------------------------------------------------------------------------------- /client/src/components/Public/Public.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import React from 'react' 3 | import Sidebar from './Sidebar/Sidebar' 4 | import EntitySearchModal from './EntitySearch/EntitySearchModal' 5 | import Map from './Map/Map' 6 | import Legend from '../shared/Legend/Legend' 7 | import './Public.css' 8 | 9 | const Public = () => ( 10 |
11 | 12 | 13 | 14 | 15 | 16 |
17 | ) 18 | 19 | export default Public 20 | -------------------------------------------------------------------------------- /client/src/components/shared/Info/Relations.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import React from 'react' 3 | import RelationList from './RelationList' 4 | 5 | import type {RelatedEntity} from '../../../state' 6 | import ToggleBox from '../ToggleBox' 7 | 8 | type RelationsProps = { 9 | data: Array, 10 | name: string, 11 | } 12 | 13 | const Relations = ({data, name}: RelationsProps) => ( 14 | 15 | 16 | 17 | ) 18 | 19 | export default Relations 20 | -------------------------------------------------------------------------------- /client/src/components/Notices/Company.scss: -------------------------------------------------------------------------------- 1 | @import '../variables.scss'; 2 | 3 | .company td { 4 | border-top: 1px solid $border-color; 5 | background-color: $component-background; 6 | } 7 | 8 | .nowrap-ellipsis { 9 | display: block; 10 | width: 100%; 11 | text-overflow: ellipsis; 12 | overflow: hidden; 13 | white-space: nowrap; 14 | } 15 | 16 | .company-title a { 17 | max-width: 20vw; 18 | } 19 | 20 | .company-link { 21 | color: $blue-color; 22 | cursor: pointer; 23 | 24 | &:hover { 25 | color: darken($blue-color, 10%); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /client/src/components/Public/Sidebar/Sidebar.scss: -------------------------------------------------------------------------------- 1 | @import "../../variables.scss"; 2 | 3 | .verejne-side-panel { 4 | position: fixed; 5 | top: $navbar-height + 40px; 6 | left: 40px; 7 | z-index: 1; 8 | 9 | .form-control { 10 | box-shadow: 0 4px 12px darken($shadow-color, 25%); 11 | border-radius: 2px; 12 | font-size: 1rem; 13 | padding: 1em 1.5em; 14 | } 15 | } 16 | 17 | .drawer { 18 | z-index: 900; 19 | } 20 | 21 | .drawer.drawer-left.drawer-open { 22 | z-index: 1030; 23 | } 24 | 25 | .drawer-content { 26 | padding: 1rem .5rem; 27 | } 28 | -------------------------------------------------------------------------------- /client/src/components/Notices/NoticeSidebar.scss: -------------------------------------------------------------------------------- 1 | @import "../variables.scss"; 2 | 3 | .notice-sidebar { 4 | margin: auto; 5 | text-align: center; 6 | } 7 | 8 | .notice-list-title { 9 | font-weight: 200; 10 | font-size: 3rem; 11 | padding-top: 1em; 12 | padding-bottom: 1em; 13 | text-align: center; 14 | } 15 | 16 | @media screen and (max-width: 576px) { 17 | .notice-list-title, 18 | .notice-list-text { 19 | text-align: center; 20 | } 21 | } 22 | @media screen and (max-width: 400px) { 23 | .notice-list-title { 24 | font-size: 2rem; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /client/src/components/Public/EntitySearchResultItem/EntitySearchResultItem.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import React from 'react' 3 | import './EntitySearchResultItem.css' 4 | import Info from '../../shared/Info/Info' 5 | import type {NewEntityDetail} from '../../../state' 6 | 7 | type EntitySearchResultItemProps = {| 8 | entity: NewEntityDetail, 9 | |} 10 | 11 | const EntitySearchResultItem = ({entity}: EntitySearchResultItemProps) => ( 12 |
13 | 14 |
15 | ) 16 | 17 | export default EntitySearchResultItem 18 | -------------------------------------------------------------------------------- /client/src/components/Connections/Connections.scss: -------------------------------------------------------------------------------- 1 | @import "../variables.scss"; 2 | 3 | .connections-sidebar { 4 | position: fixed; 5 | top: $navbar-height; 6 | bottom: 0; 7 | background-color: $component-background; 8 | display: flex; 9 | flex-direction: column; 10 | padding-bottom: 2rem; 11 | padding-top: 2rem; 12 | width: 400px; 13 | 14 | @media screen and (max-width: 767px) { 15 | position: static; 16 | width: 100%; 17 | align-items: center; 18 | } 19 | } 20 | 21 | .connections-main { 22 | margin-top: 15px; 23 | margin-bottom: 2rem; 24 | } 25 | -------------------------------------------------------------------------------- /client/src/components/Search/Search.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import React from 'react' 3 | import {Container} from 'reactstrap' 4 | import SearchAutocomplete from './SearchAutocomplete' 5 | import SearchResults from './SearchResults' 6 | 7 | import './Search.css' 8 | 9 | const Search = () => ( 10 | 11 | {/* $FlowFixMe Connected components are hard to type */} 12 | 13 | {/* $FlowFixMe Connected components are hard to type */} 14 | 15 | 16 | ) 17 | 18 | export default Search 19 | -------------------------------------------------------------------------------- /obstaravania/pdfsender/libs/zelenaposta/api2/SentClient.php: -------------------------------------------------------------------------------- 1 | call('sendMailings', $request); 23 | } 24 | } -------------------------------------------------------------------------------- /client/src/components/Public/Map/AddressDetail/ListRow.scss: -------------------------------------------------------------------------------- 1 | @import "../../../variables.scss"; 2 | 3 | .list-row { 4 | border: 0; 5 | margin-bottom: 0; 6 | 7 | &:first-child { 8 | border-radius: 0; 9 | } 10 | 11 | &:last-child { 12 | border-radius: 0; 13 | } 14 | 15 | & + & { 16 | border-top: 1px solid $border-color; 17 | } 18 | 19 | .info { 20 | cursor: default; 21 | } 22 | } 23 | 24 | .list-row-toggler { 25 | cursor: pointer; 26 | width: calc(100% - 3rem); 27 | display: inline-block; 28 | } 29 | 30 | .search-icon { 31 | cursor: pointer; 32 | color: $blue-color; 33 | } 34 | -------------------------------------------------------------------------------- /obstaravania/pdfsender/libs/zelenaposta/api2/UserClient.php: -------------------------------------------------------------------------------- 1 | call('getInfo', $request); 23 | } 24 | } -------------------------------------------------------------------------------- /client/src/components/Connections/components/Results.scss: -------------------------------------------------------------------------------- 1 | @import "../../variables.scss"; 2 | 3 | .showGraphButtonWrap { 4 | margin-bottom: 10px; 5 | width: 100%; 6 | position: relative; 7 | height: 40px; 8 | } 9 | 10 | .showGraphButton { 11 | cursor: pointer; 12 | z-index: 10; 13 | 14 | &.open { 15 | background: white; 16 | padding: .3rem; 17 | border: 1px solid $border-color; 18 | box-shadow: 0 4px 12px 0 $shadow-color; 19 | margin-bottom: 15px; 20 | } 21 | 22 | &.close { 23 | position: absolute; 24 | right: 15px; 25 | top: 5px; 26 | padding: 0 5px; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /client/src/components/Loading/Loading.scss: -------------------------------------------------------------------------------- 1 | .loading { 2 | display: flex; 3 | width: 100%; 4 | height: 100%; 5 | 6 | svg { 7 | margin: auto; 8 | } 9 | } 10 | 11 | .loadingsmall { 12 | width: 100%; 13 | height: 100%; 14 | 15 | svg { 16 | margin: auto; 17 | } 18 | } 19 | 20 | .loading-modal { 21 | margin: auto; 22 | 23 | svg { 24 | display: block; 25 | margin-left: auto; 26 | margin-right: auto; 27 | } 28 | } 29 | 30 | .loading-graph { 31 | margin-bottom: 20px; 32 | 33 | svg { 34 | display: block; 35 | margin-left: auto; 36 | margin-right: auto; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /client/src/components/Playground/components/ColabDetail.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import {ListGroupItemHeading, ListGroupItemText, ListGroupItem} from 'reactstrap' 3 | import type {Colab} from '../../../state' 4 | 5 | export type ColabDetailProps = { 6 | colab: Colab, 7 | } 8 | 9 | const ColabDetail = ({colab}: ColabDetailProps) => ( 10 | 11 | {colab.name} 12 | {colab.description} 13 | 14 | ) 15 | 16 | export default ColabDetail 17 | -------------------------------------------------------------------------------- /client/src/components/shared/CircleIcon.scss: -------------------------------------------------------------------------------- 1 | @import "../variables.scss"; 2 | 3 | .circle-icon { 4 | color: $blue-color; 5 | 6 | &.politician svg, &.politician.government svg, &.politician.politics svg { 7 | color: purple; 8 | background-color: purple; 9 | border-radius: 50%; 10 | } 11 | 12 | &.politics svg { 13 | color: $orange-color; 14 | } 15 | 16 | &.government svg{ 17 | background-color: $blue-color; 18 | border-radius: 50%; 19 | } 20 | 21 | &.politics.government svg{ 22 | color: $orange-color; 23 | background-color: $orange-color; 24 | border-radius: 50%; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /client/src/components/Notices/Legend.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import React from 'react' 3 | 4 | import {formatSimilarPercent, getWarningSymbol} from './LegendSymbols' 5 | import './Legend.css' 6 | import './LegendSymbols.css' 7 | 8 | const Legend = () => ( 9 |
10 |

Legenda:

11 |
12 |
{formatSimilarPercent(19)}
13 |
podobnosť s predchádzajúcim obstarávaním
14 |
{getWarningSymbol(1)}
15 |
podozrivé obstarávanie
16 |
17 |
18 | ) 19 | 20 | export default Legend 21 | -------------------------------------------------------------------------------- /client/src/components/Notices/NoticeItem.scss: -------------------------------------------------------------------------------- 1 | @import '../variables.scss'; 2 | 3 | .nowrap-ellipsis { 4 | display: block; 5 | width: 100%; 6 | text-overflow: ellipsis; 7 | overflow: hidden; 8 | white-space: nowrap; 9 | } 10 | 11 | .notice-item-title { 12 | white-space: nowrap; 13 | 14 | .warning-symbol { 15 | vertical-align: top; 16 | margin-right: 3px; 17 | } 18 | } 19 | 20 | .notice-item-title a { 21 | max-width: 50ch; 22 | display: inline-block; 23 | } 24 | 25 | .notice-item-link { 26 | color: $blue-color; 27 | cursor: pointer; 28 | 29 | &:hover { 30 | color: darken($blue-color, 10%); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /data/prod_generation/utils.py: -------------------------------------------------------------------------------- 1 | """Utility methods for production data generation.""" 2 | 3 | import six 4 | import yaml 5 | 6 | 7 | def longest_common_prefix(str1, str2): 8 | """Returns the longest common prefix length of two strings.""" 9 | limit = min(len(str1), len(str2)) 10 | for i in six.moves.range(limit): 11 | if str1[i] != str2[i]: 12 | return i 13 | return limit 14 | 15 | 16 | def yaml_load(path): 17 | """Returns content of YAML file at `path` as a Python object.""" 18 | with open(path, 'r', encoding='utf-8') as f: 19 | data_yaml = yaml.load(f, Loader=yaml.FullLoader) 20 | return data_yaml 21 | -------------------------------------------------------------------------------- /client/src/components/Connections/components/DummyResults.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import React from 'react' 3 | 4 | type Props = { 5 | text: string, 6 | } 7 | 8 | const DummyResults = ({text}: Props) => ( 9 |
10 |
11 |

{text}

12 |
13 |
14 | ) 15 | 16 | export const BeforeResults = () => 17 | DummyResults({text: 'Zadajte dvojicu pre začiatok vyhľadávania.'}) 18 | export const EmptyResults = () => 19 | DummyResults({text: 'Prepojenie neexistuje.'}) 20 | export const NoEntityResults = () => 21 | DummyResults({text: 'Daná osoba nebola nájdená'}) 22 | -------------------------------------------------------------------------------- /client/src/dataProviders/colabDataProviders.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import {setColabs} from '../actions/colabActions' 3 | import type {Colab} from '../state' 4 | import type {Dispatch} from '../types/reduxTypes' 5 | 6 | const dispatchColabs = () => (ref: string, data: Colab[], dispatch: Dispatch) => { 7 | dispatch(setColabs(data)) 8 | } 9 | 10 | export const colabsProvider = () => ({ 11 | ref: 'colabs', 12 | getData: [ 13 | fetch, 14 | `${process.env.REACT_APP_API_URL || ''}/api/d/colabs_info`, 15 | { 16 | accept: 'application/json', 17 | }, 18 | ], 19 | onData: [dispatchColabs], 20 | keepAliveFor: 60 * 60 * 1000, 21 | needed: true, 22 | }) 23 | -------------------------------------------------------------------------------- /client/src/components/Public/EntitySearchAutocomplete/EntitySearchAutocomplete.scss: -------------------------------------------------------------------------------- 1 | @import "../../variables.scss"; 2 | 3 | @media screen and (max-width: 575px) { 4 | .addon-button { 5 | width: 41px; 6 | margin-left: 1px; 7 | } 8 | } 9 | 10 | .publicly-autocomplete-input { 11 | width: $verejne-sidebar-width - 80px; 12 | height: auto; 13 | 14 | @media screen and (max-width: 575px) { 15 | width: 100%; 16 | } 17 | } 18 | .publicly-autocomplete-menu { 19 | max-height: calc(100vh - 160px); 20 | } 21 | 22 | .input-group.autocomplete-holder > div:first-child { 23 | @media screen and (max-width: 575px) { 24 | width: calc(100% - 82px); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /client/check_flow.py: -------------------------------------------------------------------------------- 1 | from os import walk, path 2 | from glob import glob 3 | 4 | README = ''' 5 | Recursively searching for *.js files inside 'src' folder and 6 | checking if the file is flowed ('// @flow' is on the first line) 7 | ''' 8 | DELIM, PATH = '---------------------------------------------------------------', 'src' 9 | 10 | print(README) 11 | print(DELIM) 12 | 13 | files = [y for x in walk(PATH) for y in glob(path.join(x[0], '*.js'))] 14 | for filename in files: 15 | with open(filename) as file: 16 | first_line = file.readline().strip() 17 | if first_line != '// @flow': 18 | print('Unflowed file: \t"%s"' % filename) 19 | 20 | print(DELIM) 21 | -------------------------------------------------------------------------------- /client/src/components/Public/Map/Marker/Marker.scss: -------------------------------------------------------------------------------- 1 | @import "../../../variables.scss"; 2 | 3 | .marker { 4 | position: absolute; 5 | width: $marker-width; 6 | height: $marker-height; 7 | left: -$marker-width / 2; 8 | top: -$marker-height / 2; 9 | text-align: center; 10 | cursor: pointer; 11 | 12 | &__text { 13 | font-size: .7rem !important; 14 | font-weight: bold; 15 | display: flex; 16 | justify-content: center; 17 | align-items: center; 18 | width: 100%; 19 | height: 100%; 20 | color: #fff !important; 21 | border-radius: 50%; 22 | } 23 | 24 | &:hover { 25 | transform: scale(1.2); 26 | transition: .2s ease; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /client/src/components/shared/Info/Item.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import React from 'react' 3 | import type {Node} from 'react' 4 | 5 | import ExternalLink from '../ExternalLink' 6 | import './Item.css' 7 | 8 | type ItemProps = {| 9 | children?: Node, 10 | label?: string, 11 | url?: string, 12 | linkText?: Node, 13 | |} 14 | 15 | const Item = ({children, label, url, linkText}: ItemProps) => ( 16 |
  • 17 | {label && {label}} 18 | {url && ( 19 | 20 | {linkText} 21 | 22 | )} 23 | {children} 24 |
  • 25 | ) 26 | 27 | export default Item 28 | -------------------------------------------------------------------------------- /client/src/components/Notices/NoticeSidebar.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import React, {Fragment} from 'react' 3 | 4 | import {Row, Col} from 'reactstrap' 5 | import './NoticeSidebar.css' 6 | 7 | const NoticeSidebar = () => ( 8 | 9 | 10 | 11 |

    Aktuálne obstarávania

    12 |

    13 | Našim cieľom je identifikovať a osloviť najvhodnejších uchádzačov, ktorí by sa mali 14 | zapojiť do verejných obstarávaní. Viac info 15 |

    16 | 17 |
    18 |
    19 | ) 20 | 21 | export default NoticeSidebar 22 | -------------------------------------------------------------------------------- /client/src/components/GoogleMap/GoogleMap.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import * as React from 'react' 3 | import GMap from 'google-map-react' 4 | import {GOOGLE_MAP_CONFIG, createMapOptions} from '../../constants' 5 | 6 | import type {MapOptions} from '../../state' 7 | 8 | type Props = {| 9 | zoom: number, 10 | center: [number, number], 11 | onChange: (options: MapOptions) => any, 12 | children: React.Node, 13 | |} 14 | 15 | const GoogleMap = ({zoom, center, onChange, children}: Props) => ( 16 | 23 | {children} 24 | 25 | ) 26 | 27 | export default GoogleMap 28 | -------------------------------------------------------------------------------- /client/src/components/Connections/Connections.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import React from 'react' 3 | import {Container, Col, Row} from 'reactstrap' 4 | import Search from './components/Search' 5 | import Statuses from './components/Statuses' 6 | import Results from './components/Results' 7 | import './Connections.css' 8 | 9 | const Connections = () => ( 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | ) 22 | 23 | export default Connections 24 | -------------------------------------------------------------------------------- /client/src/components/Notices/NoticeInformation.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import React from 'react' 3 | import type {Node} from 'react' 4 | import {branch, renderNothing} from 'recompose' 5 | import './NoticeInformation.css' 6 | 7 | type Props = {| 8 | data: Array<{body: string | Node, label: string}>, 9 | |} 10 | 11 | const _NoticeInformation = ({data}: Props) => ( 12 |
      13 | {data.map(({label, body}, index) => ( 14 |
    • 15 | {label && {label}:} {body} 16 |
    • 17 | ))} 18 |
    19 | ) 20 | 21 | export default branch(({data}: Props) => data === null || data.length === 0, renderNothing)( 22 | _NoticeInformation 23 | ) 24 | -------------------------------------------------------------------------------- /client/src/components/shared/Info/InfoButton.scss: -------------------------------------------------------------------------------- 1 | @import '../../variables.scss'; 2 | 3 | .info-button { 4 | border-top: 1px solid $border-color; 5 | padding-top: 1rem; 6 | margin-top: 1rem; 7 | } 8 | 9 | .info-button-list { 10 | margin-top: 1rem; 11 | margin-bottom: 0; 12 | 13 | > li { 14 | border-bottom: 1px solid $border-color; 15 | padding: 0.25rem 0; 16 | } 17 | > * .btn { 18 | white-space: normal; 19 | text-align: left; 20 | } 21 | > li:last-child { 22 | border-bottom: none; 23 | } 24 | } 25 | 26 | .info-badge { 27 | position: relative; 28 | bottom: 0.05rem; 29 | top: auto !important; 30 | &.info-badge-number { 31 | bottom: 0.065rem; 32 | } 33 | &.info-badge.badge { 34 | white-space: normal; 35 | text-align: left; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /client/src/components/Landing/Card.scss: -------------------------------------------------------------------------------- 1 | @import "../variables.scss"; 2 | 3 | .card { 4 | box-shadow: 0 4px 12px 0 $shadow-color; 5 | text-align: center; 6 | border-radius: 8px; 7 | transition: box-shadow 0.25s; 8 | height: 100%; 9 | 10 | &:hover { 11 | text-decoration: none; 12 | box-shadow: 0 6px 18px 0 darken($shadow-color, 20%); 13 | } 14 | 15 | p { 16 | color: $link-color; 17 | } 18 | } 19 | 20 | .card-image-wrap { 21 | height: 80px; 22 | padding-top: 20px; 23 | display: flex; 24 | justify-content: center; 25 | align-items: center; 26 | } 27 | 28 | .card-image { 29 | height: 40px; 30 | width: auto; 31 | } 32 | 33 | .card-text { 34 | margin-top: auto; 35 | } 36 | 37 | .card-title { 38 | font-family: Source Code Pro, monospace; 39 | font-weight: normal; 40 | } 41 | -------------------------------------------------------------------------------- /client/src/components/Notices/NoticeInformation.scss: -------------------------------------------------------------------------------- 1 | @import '../variables.scss'; 2 | 3 | .notice-information { 4 | background-color: $component-background; 5 | list-style: none; 6 | margin: 0; 7 | padding: 0 15px; 8 | box-shadow: 0 4px 12px $shadow-color; 9 | border: 2px solid $border-color; 10 | border-radius: 1px; 11 | position: relative; 12 | margin-bottom: 30px; 13 | 14 | &::after { 15 | content: ' '; 16 | display: block; 17 | width: 8px; 18 | height: 30px; 19 | position: absolute; 20 | bottom: -32px; 21 | background: $border-color; 22 | } 23 | } 24 | 25 | .notice-information-item { 26 | padding: 10px 0; 27 | 28 | & + & { 29 | border-top: 1px solid $border-color; 30 | } 31 | 32 | strong { 33 | color: $secondary; 34 | font-weight: normal; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /client/src/components/Connections/dataWrappers/EntitySearchWrapper.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import React from 'react' 3 | import {parse} from 'qs' 4 | import {withRouter, type ContextRouter} from 'react-router-dom' 5 | import type {ComponentType} from 'react' 6 | 7 | export type EntitySearchProps = { 8 | entitySearch1: string, 9 | entitySearch2: string, 10 | } 11 | 12 | const EntitySearchWrapper = (WrappedComponent: ComponentType<*>) => { 13 | const wrapped = (props: ContextRouter) => { 14 | const query = parse(props.location.search.substring(1)) 15 | return ( 16 | 21 | ) 22 | } 23 | 24 | return withRouter(wrapped) 25 | } 26 | 27 | export default EntitySearchWrapper 28 | -------------------------------------------------------------------------------- /client/src/components/Profile/components/MapContainer.scss: -------------------------------------------------------------------------------- 1 | @import '../../variables.scss'; 2 | 3 | div#map { 4 | .map { 5 | height: 50vh; 6 | width: 100%; 7 | margin-top: 15px; 8 | margin-bottom: 20px; 9 | box-shadow: 0 4px 12px 0 $shadow-color; 10 | border: 2px solid $border-color; 11 | 12 | .marker { 13 | width: 36px; 14 | height: 36px; 15 | border-radius: 50%; 16 | background: $marker-background; 17 | background-color: #fff; 18 | border: 2px solid $marker-border; 19 | font-size: 12px; 20 | font-weight: bold; 21 | color: $marker-text-color; 22 | text-align: center; 23 | padding-top: 8px; 24 | 25 | &:hover { 26 | z-index: 10; 27 | transform: none; 28 | text-decoration: none; 29 | } 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /client/src/components/shared/AutoComplete/AutoComplete.scss: -------------------------------------------------------------------------------- 1 | @import "../../variables.scss"; 2 | 3 | .autocomplete-item { 4 | color: $search-color; 5 | padding: 0.3rem; 6 | cursor: pointer; 7 | background-color: white; 8 | 9 | &--active { 10 | background-color: $asset-hover-color; 11 | } 12 | 13 | &--placeholder { 14 | cursor: unset; 15 | pointer-events: none; 16 | } 17 | 18 | border-bottom: 1px solid $border-color; 19 | 20 | &:last-child { 21 | border-bottom: none; 22 | } 23 | } 24 | 25 | .autocomplete-suggestions-menu { 26 | box-shadow: 0 4px 12px 0 $shadow-color; 27 | font-size: 90%; 28 | position: absolute; 29 | overflow: auto; 30 | padding: 0px; 31 | border-radius: 0px; 32 | background: white; 33 | z-index: 2; 34 | border: 1px solid $border-color; 35 | width: 100%; 36 | } 37 | -------------------------------------------------------------------------------- /client/src/components/Public/Map/AddressDetail/AddressDetail.scss: -------------------------------------------------------------------------------- 1 | @import '../../../variables.scss'; 2 | 3 | .address-detail { 4 | width: $verejne-sidebar-width; 5 | box-shadow: 0 4px 12px darken($shadow-color, 25%); 6 | background-color: $component-background; 7 | border-radius: 2px; 8 | 9 | @media screen and (max-width: 576px) { 10 | width: 100%; 11 | } 12 | } 13 | 14 | .address-detail-header { 15 | padding-top: .3rem; 16 | padding-right: .5em; 17 | padding-left: 1em; 18 | border-bottom: 2px solid $border-color; 19 | } 20 | 21 | .address-detail-list { 22 | overflow-y: auto; 23 | border-radius: 0; 24 | max-height: calc(100vh - 300px); 25 | 26 | @media screen and (max-width: 576px) { 27 | max-height: calc(100vh - 160px); 28 | } 29 | 30 | .detailed-info { 31 | padding: .5rem .75rem; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /client/src/components/shared/withTracker.js: -------------------------------------------------------------------------------- 1 | /** 2 | * From ReactGA Community Wiki Page 3 | * https://github.com/react-ga/react-ga/wiki/React-Router-v4-withTracker 4 | */ 5 | 6 | import React, {Component} from 'react' 7 | import ReactGA from 'react-ga' 8 | 9 | export default function withTracker(WrappedComponent, options = {}) { 10 | const trackPage = (page) => { 11 | ReactGA.set({ 12 | page, 13 | ...options, 14 | }) 15 | ReactGA.pageview(page) 16 | } 17 | 18 | const HOC = class extends Component { 19 | componentDidMount() { 20 | if (process.env.NODE_ENV === 'production') { 21 | const page = this.props.location.pathname 22 | trackPage(page) 23 | } 24 | } 25 | 26 | render() { 27 | return 28 | } 29 | } 30 | 31 | return HOC 32 | } 33 | -------------------------------------------------------------------------------- /client/src/components/Landing/Card.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import React from 'react' 3 | import {CardImg, CardBody, CardTitle, CardText, Badge} from 'reactstrap' 4 | import {Link} from 'react-router-dom' 5 | import './Card.css' 6 | 7 | type CardProps = {| 8 | title: string, 9 | text: string, 10 | imgSrc: string, 11 | to: string, 12 | beta?: boolean, 13 | |} 14 | 15 | const Card = ({title, text, imgSrc, to, beta}: CardProps) => ( 16 | 17 |
    18 | 19 |
    20 | 21 | {title} {beta && Beta} 22 | {text} 23 | 24 | 25 | ) 26 | 27 | export default Card 28 | -------------------------------------------------------------------------------- /client/src/types/reduxTypes.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import type {State} from '../state' 3 | 4 | export type PathElement = number | string 5 | export type Path = Array 6 | 7 | export type GenericAction = { 8 | +type: string, 9 | +path?: Path, 10 | +payload?: Payload, 11 | +reducer: SegmentReducer, 12 | +doNotLog?: boolean, 13 | } 14 | 15 | export type SegmentReducer = (state: Segment, payload: Payload) => Segment 16 | export type GetState = () => State 17 | // eslint-disable-next-line 18 | export type Dispatch = (action: GenericAction<*, *> | Thunk) => null 19 | export type ThunkExtra = { 20 | logger: { 21 | log: (args: any) => null, 22 | }, 23 | } 24 | export type Thunk = ( 25 | dispatch: Dispatch, 26 | getState: GetState, 27 | extra: ThunkExtra 28 | ) => Promise | void 29 | -------------------------------------------------------------------------------- /data/update_rpvs.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # set bash strict mode - fail immediately if anything fails 4 | set -eu 5 | IFS=$'\n\t' 6 | 7 | # Extract command line parameter. 8 | URL=$1 9 | 10 | # Create a temporary directory (deleted when the script terminates). 11 | TMPDIR=/tmp/update_rpvs.$$ 12 | mkdir $TMPDIR 13 | trap 'rm -rf ${TMPDIR}' EXIT 14 | 15 | # Download ZIP file from the provided URL. 16 | curl -sfo ${TMPDIR}/source_rpvs.zip "$URL" 17 | 18 | # Unzip into the temporary directory. 19 | unzip -o ${TMPDIR}/source_rpvs.zip -d ${TMPDIR} 20 | 21 | # Stage the CSV file for the source update. 22 | mv ${TMPDIR}/rpvs_dump_all.csv /tmp/source_rpvs.csv 23 | 24 | # Update source "rpvs". 25 | shift 26 | echo "python source_update.py rpvs" "$@" 27 | eval python source_update.py rpvs "$@" 28 | 29 | # Delete the source file. 30 | rm /tmp/source_rpvs.csv 31 | -------------------------------------------------------------------------------- /client/src/components/shared/ToggleBox.scss: -------------------------------------------------------------------------------- 1 | @import '../variables.scss'; 2 | 3 | .info-button { 4 | border-top: 1px solid $border-color; 5 | padding-top: 1rem; 6 | margin-top: 1rem; 7 | } 8 | 9 | .info-button-list { 10 | margin-top: 1rem; 11 | margin-bottom: 0; 12 | 13 | > li { 14 | border-bottom: 1px solid $border-color; 15 | padding: 0.25rem 0; 16 | } 17 | 18 | > * .btn { 19 | white-space: normal; 20 | text-align: left; 21 | } 22 | 23 | > li:last-child { 24 | border-bottom: none; 25 | } 26 | } 27 | 28 | .info-badge { 29 | position: relative; 30 | bottom: 0.05rem; 31 | top: auto !important; 32 | 33 | &.info-badge-number { 34 | bottom: 0.065rem; 35 | } 36 | 37 | &.info-badge.badge { 38 | white-space: normal; 39 | text-align: left; 40 | } 41 | } 42 | 43 | .content { 44 | margin-top: 1em; 45 | } 46 | -------------------------------------------------------------------------------- /client/src/components/Notices/LegendSymbols.scss: -------------------------------------------------------------------------------- 1 | @import '../variables.scss'; 2 | 3 | .similar-count { 4 | background-color: #b6c5d2; 5 | color: $component-background; 6 | border-radius: 1rem; 7 | padding: .15em .45em; 8 | font-size: .85rem; 9 | font-weight: bold; 10 | } 11 | 12 | .similarity { 13 | color: green; 14 | font-weight: lighter; 15 | } 16 | 17 | .similarity-high { 18 | font-weight: bold; 19 | } 20 | 21 | .similarity-medium { 22 | font-weight: bolder; 23 | } 24 | 25 | .similarity-low { 26 | font-weight: normal; 27 | } 28 | 29 | .warning-symbol { 30 | display: inline-block; 31 | width: fit-content; 32 | } 33 | 34 | .warning { 35 | font-size: 130%; 36 | } 37 | 38 | .warning-1 { 39 | color: $warning-1-color; 40 | } 41 | 42 | .warning-2 { 43 | color: $warning-1-color; 44 | } 45 | 46 | .warning-3 { 47 | color: $warning-1-color; 48 | } 49 | -------------------------------------------------------------------------------- /client/src/components/PlacesAutocomplete/PlacesAutocomplete.scss: -------------------------------------------------------------------------------- 1 | @import '../variables.scss'; 2 | 3 | .autocomplete { 4 | .autocomplete__input { 5 | height: auto; 6 | } 7 | &__input { 8 | width: 100%; 9 | } 10 | &__suggestions { 11 | border: 1px solid $border-color; 12 | box-shadow: 0 4px 12px 0 $shadow-color; 13 | width: $verejne-sidebar-width; 14 | &__item { 15 | & small { 16 | color: $search-color; 17 | } 18 | white-space: nowrap; 19 | overflow: hidden; 20 | text-overflow: ellipsis; 21 | border-bottom: 1px solid $border-color; 22 | padding: 0.3rem 0.6rem; 23 | cursor: pointer; 24 | background-color: white; 25 | &--active { 26 | background-color: $asset-hover-color; 27 | } 28 | } 29 | &__item:last-child { 30 | border-bottom: none; 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /client/src/components/Notices/Bulletin.scss: -------------------------------------------------------------------------------- 1 | @import "../variables.scss"; 2 | 3 | .bulletin { 4 | margin-top: 2rem; 5 | margin-bottom: 1rem; 6 | } 7 | 8 | .bulletin-title { 9 | padding-left: 70px; 10 | margin-bottom: 1rem; 11 | font-size: 1.1rem; 12 | 13 | small { 14 | font-size: .9em; 15 | margin-left: .5em; 16 | 17 | span { 18 | color: $secondary; 19 | } 20 | } 21 | } 22 | 23 | .bulletin > .table-responsive { 24 | box-shadow: 0 4px 12px 0 $shadow-color; 25 | } 26 | 27 | .bulletin-table { 28 | margin-bottom: 0; 29 | border: 2px solid $border-color; 30 | } 31 | 32 | .bulletin-table tr th { 33 | color: $secondary; 34 | font-weight: normal; 35 | border-top: 0; 36 | border-bottom: 1px solid $border-color; 37 | white-space: nowrap; 38 | background-color: $component-background; 39 | } 40 | 41 | .bulletin-table td { 42 | background-color: $component-background; 43 | } 44 | -------------------------------------------------------------------------------- /client/src/components/Profile/DetailPage.scss: -------------------------------------------------------------------------------- 1 | @import '../variables.scss'; 2 | 3 | .profile-header { 4 | h1.title { 5 | a { 6 | color: $link-color; 7 | font-weight: 400; 8 | } 9 | 10 | a:hover { 11 | text-decoration: none; 12 | color: $link-color; 13 | } 14 | } 15 | } 16 | 17 | .profile-tabs { 18 | margin-bottom: 15px; 19 | width: 100%; 20 | text-align: center; 21 | font-size: 14px; 22 | line-height: 20px; 23 | 24 | .tab { 25 | display: inline-block; 26 | padding: 3px; 27 | box-shadow: 0 4px 12px 0 $shadow-color; 28 | border: 2px solid $border-color; 29 | background-color: $component-background; 30 | cursor: pointer; 31 | margin: 0 5px 5px; 32 | min-width: 45px; 33 | } 34 | 35 | .tab.active { 36 | color: $active-tab-color; 37 | font-weight: bold; 38 | } 39 | } 40 | 41 | article.profile { 42 | text-align: left; 43 | } 44 | -------------------------------------------------------------------------------- /obstaravania/pdfsender/composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "verejne.digital/pdfsender", 3 | "description": "Sends PDF to customers using webservice.", 4 | "type": "project", 5 | "require": { 6 | "phpro/soap-client": "^0.5.3", 7 | "guzzlehttp/guzzle": "^6.2", 8 | "http-interop/http-factory-guzzle": "^0.1.0", 9 | "nategood/commando": "^0.2.9", 10 | "php": ">=7", 11 | "ext-curl": "*", 12 | "ext-soap": "*" 13 | }, 14 | "authors": [ 15 | { 16 | "name": "Martin Rejda", 17 | "email": "rejdi@ksp.sk" 18 | } 19 | ], 20 | "require-dev": { 21 | "zendframework/zend-code": "^3.3" 22 | }, 23 | "autoload": { 24 | "psr-4": { 25 | "zelenaposta\\api2\\user\\": "libs/zelenaposta/api2/user", 26 | "zelenaposta\\api2\\product\\": "libs/zelenaposta/api2/product", 27 | "zelenaposta\\api2\\sent\\": "libs/zelenaposta/api2/sent", 28 | "zelenaposta\\api2\\": "libs/zelenaposta/api2", 29 | "": "libs" 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /client/src/components/shared/CircleIcon.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import React from 'react' 3 | import {FaDotCircle} from 'react-icons/fa' 4 | import classnames from 'classnames' 5 | import {getCircleIconTitle} from './utilities' 6 | 7 | import './CircleIcon.css' 8 | 9 | export type Ties = { 10 | trade_with_government: boolean, 11 | contact_with_politics: boolean, 12 | political_entity: boolean, 13 | } 14 | type OwnProps = { 15 | data: Ties, 16 | className?: string, 17 | size?: string, 18 | } 19 | 20 | const CircleIcon = ({data, className, size = '16'}: OwnProps) => ( 21 | 29 | 30 | 31 | ) 32 | 33 | export default CircleIcon 34 | -------------------------------------------------------------------------------- /client/src/components/shared/Info/Eurofunds.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import React from 'react' 3 | 4 | import InfoButton from './InfoButton' 5 | import ExternalLink from '../ExternalLink' 6 | import {ShowNumberCurrency} from '../../../services/utilities' 7 | import type {Eufunds, Eufund} from '../../../state' 8 | 9 | type EurofundsProps = {| 10 | data: Eufunds, 11 | |} 12 | 13 | const buildEufund = (eufund: Eufund, i: number) => ( 14 | // no proper ID available 15 |
  • 16 | 17 | {`${eufund.title}, `} 18 | 19 | 20 |
  • 21 | ) 22 | 23 | const Eurofunds = ({data}: EurofundsProps) => ( 24 | 31 | ) 32 | 33 | export default Eurofunds 34 | -------------------------------------------------------------------------------- /client/src/components/Public/EntitySearch/EntitySearch.scss: -------------------------------------------------------------------------------- 1 | @import "../../variables.scss"; 2 | 3 | .search-results { 4 | box-shadow: 0 4px 12px darken($shadow-color, 25%); 5 | border-radius: 2px; 6 | width: $verejne-sidebar-width; 7 | 8 | @media screen and (max-width: 576px) { 9 | width: 100%; 10 | } 11 | } 12 | 13 | .search-results-header { 14 | position: relative; 15 | background: white; 16 | padding-top: .3rem; 17 | padding-bottom: .6rem; 18 | padding-left: 1em; 19 | padding-right: .5em; 20 | border-bottom: 2px solid $border-color; 21 | text-overflow: ellipsis; 22 | overflow: hidden; 23 | white-space: nowrap; 24 | } 25 | 26 | .search-results-panel { 27 | position: relative; 28 | background: white; 29 | padding: .5rem .75rem; 30 | max-height: calc(100vh - 300px); 31 | 32 | @media screen and (max-width: 576px) { 33 | max-height: calc(100vh - 160px); 34 | } 35 | 36 | overflow-y: auto; 37 | } 38 | -------------------------------------------------------------------------------- /client/src/components/shared/Info/Finances.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import React, {Fragment} from 'react' 3 | 4 | import type {EnhancedCompanyFinancial} from '../../../services/utilities' 5 | import FinancesItem from './FinancesItem' 6 | import ToggleBox from '../ToggleBox' 7 | 8 | type FinancesProps = { 9 | data: Array, 10 | ico: string, 11 | } 12 | 13 | const Finances = ({ 14 | data: [lastFinances, ...otherFinances], 15 | ico, 16 | expanded, 17 | toggle, 18 | }: FinancesProps) => ( 19 | 20 | {lastFinances && } 21 | {!!otherFinances.length && ( 22 | 23 | {otherFinances.map((finances) => ( 24 | 25 | ))} 26 | 27 | )} 28 | 29 | ) 30 | 31 | export default Finances 32 | -------------------------------------------------------------------------------- /data/update_KamIduEurofondy.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # set bash strict mode - fail immediately if anything fails 4 | set -eu 5 | IFS=$'\n\t' 6 | 7 | # Define working directory: 8 | dir="/tmp/" 9 | 10 | # Download and save raw JSON file: 11 | echo "Downloading KamIduEurofondy..." 12 | today=$(date '+%Y-%m-%d_%H-%M-%S') 13 | path_raw="${dir}kamidueurofondy_${today}.json" 14 | url="${1}?format=json&offset=0&limit=123456" 15 | echo "$url -o $path_raw" 16 | curl "$url" -o "$path_raw" 17 | 18 | # Flatten downloaded JSON file: 19 | echo "Flattening KamIduEurofondy..." 20 | path_flattened="${dir}kamidueurofondy_${today}_flattened.json" 21 | eval python kamidueurofondy.py "$path_raw" "$path_flattened" 22 | 23 | # Stage flattened JSON for source update: 24 | cp "$path_flattened" "/tmp/source_KamIduEurofondy.json" 25 | 26 | # Update the KamIduEurofondy source: 27 | shift 28 | echo "python source_update.py KamIduEurofondy" "$@" 29 | eval python source_update.py KamIduEurofondy "$@" 30 | -------------------------------------------------------------------------------- /client/src/configureStore.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import thunk from 'redux-thunk' 3 | import {createStore, applyMiddleware} from 'redux' 4 | import {createLogger} from 'redux-logger' 5 | import rootReducer from './rootReducer' 6 | import getInitialState from './state' 7 | 8 | export default () => { 9 | const logger = { 10 | log: () => null, 11 | } 12 | const loggerMiddleware = createLogger({ 13 | collapsed: true, 14 | predicate: (getState, action) => !action.doNotLog, 15 | }) 16 | 17 | const middlewares = [thunk.withExtraArgument({logger})] 18 | if (process.env.NODE_ENV === 'development') { 19 | middlewares.push(loggerMiddleware) 20 | } 21 | 22 | const store = createStore(rootReducer, getInitialState(), applyMiddleware(...middlewares)) 23 | 24 | if (process.env.NODE_ENV === 'development') { 25 | logger.log = (message, payload) => 26 | store.dispatch({ 27 | type: message, 28 | payload, 29 | }) 30 | } 31 | 32 | return store 33 | } 34 | -------------------------------------------------------------------------------- /client/src/components/Profile/components/PoliticiansList.scss: -------------------------------------------------------------------------------- 1 | @import "../../variables.scss"; 2 | 3 | article.profile { 4 | .table { 5 | border-radius: 4px; 6 | border: 2px; 7 | border-color: $border-color; 8 | border-style: solid; 9 | box-shadow: 0 4px 12px 0 $shadow-color; 10 | line-height: 20px; 11 | 12 | .thumb-photo { 13 | height: 30px; 14 | width: 24px; 15 | } 16 | 17 | .photo-column { 18 | max-width: 45px; 19 | } 20 | 21 | .number-column { 22 | text-align: center; 23 | } 24 | 25 | .party-column { 26 | text-overflow: ellipsis; 27 | white-space: nowrap; 28 | overflow: hidden; 29 | max-width: 150px; 30 | } 31 | 32 | .clickable { 33 | cursor: pointer; 34 | } 35 | } 36 | 37 | #politicians-table { 38 | background: $component-background; 39 | } 40 | 41 | @media (max-width: 767px) { 42 | .table { 43 | overflow: auto; 44 | display: block; 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /client/flow-typed/npm/node-sass-chokidar_vx.x.x.js: -------------------------------------------------------------------------------- 1 | // flow-typed signature: 0b5cde449620c8ccd26a2471d575d66c 2 | // flow-typed version: <>/node-sass-chokidar_v^1.2.2/flow_v0.71.0 3 | 4 | /** 5 | * This is an autogenerated libdef stub for: 6 | * 7 | * 'node-sass-chokidar' 8 | * 9 | * Fill this stub out by replacing all the `any` types. 10 | * 11 | * Once filled out, we encourage you to share your work with the 12 | * community by sending a pull request to: 13 | * https://github.com/flowtype/flow-typed 14 | */ 15 | 16 | declare module 'node-sass-chokidar' { 17 | declare module.exports: any 18 | } 19 | 20 | /** 21 | * We include stubs for each file inside this npm package in case you need to 22 | * require those files directly. Feel free to delete any files that aren't 23 | * needed. 24 | */ 25 | declare module 'node-sass-chokidar/test/cli' { 26 | declare module.exports: any 27 | } 28 | 29 | // Filename aliases 30 | declare module 'node-sass-chokidar/test/cli.js' { 31 | declare module.exports: $Exports<'node-sass-chokidar/test/cli'> 32 | } 33 | -------------------------------------------------------------------------------- /client/src/components/Navigation.scss: -------------------------------------------------------------------------------- 1 | @import "./variables.scss"; 2 | 3 | .navbar { 4 | box-shadow: 0 4px 12px 0 $shadow-color; 5 | background: $component-background; 6 | padding: 0 ; 7 | height: $navbar-height; 8 | z-index: 1000; 9 | } 10 | 11 | .navbar-brand { 12 | margin-left: 1rem; 13 | padding: .5rem 0; 14 | font-family: Source Code Pro, monospace; 15 | } 16 | 17 | .collapse.show, .collapsing { 18 | margin-top: -3px; 19 | box-shadow: 0 8px 12px -4px $shadow-color; 20 | } 21 | 22 | .nav-item { 23 | padding: 0 1rem; 24 | background: $component-background; 25 | } 26 | 27 | .nav-link { 28 | background: $component-background; 29 | padding-top: .8rem; 30 | border-bottom: 3px solid transparent; 31 | 32 | &:hover { 33 | border-bottom-color: $search-border-color; 34 | } 35 | 36 | &.active { 37 | border-bottom-color: $active-tab-color; 38 | } 39 | } 40 | 41 | .navbar-toggler { 42 | margin: .5rem 0; 43 | margin-right: 1rem; 44 | width: 2rem; 45 | height: 2rem; 46 | font-size: .8rem; 47 | padding: .1rem; 48 | } 49 | -------------------------------------------------------------------------------- /client/src/services/map.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import {fitBounds} from 'google-map-react/utils' 3 | import {minBy, maxBy} from 'lodash' 4 | 5 | import {ENTITY_CLOSE_ZOOM, DEFAULT_MAP_CENTER, COUNTRY_ZOOM} from '../constants' 6 | import type {Center} from '../state' 7 | 8 | // this function doesn't cover crossing 0th meridian and equator, but for Slovakia it's good enough 9 | export const getBoundsFromLocations = (locations: Center[], width: number, height: number) => { 10 | switch (locations.length) { 11 | case 0: 12 | return {center: DEFAULT_MAP_CENTER, zoom: COUNTRY_ZOOM} 13 | case 1: 14 | return {center: locations[0], zoom: ENTITY_CLOSE_ZOOM} 15 | default: 16 | return fitBounds( 17 | { 18 | sw: { 19 | lat: minBy(locations, 'lat').lat, 20 | lng: minBy(locations, 'lng').lng, 21 | }, 22 | ne: { 23 | lat: maxBy(locations, 'lat').lat, 24 | lng: maxBy(locations, 'lng').lng, 25 | }, 26 | }, 27 | {width, height} 28 | ) 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /client/src/components/Playground/components/ColabList.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import {compose} from 'redux' 3 | import {connect} from 'react-redux' 4 | import {withDataProviders} from 'data-provider' 5 | import {ListGroup} from 'reactstrap' 6 | import type {Colab, State} from '../../../state' 7 | import {colabsSelector} from '../../../selectors' 8 | import {colabsProvider} from '../../../dataProviders/colabDataProviders' 9 | import ColabDetail from './ColabDetail' 10 | 11 | export type ColabListProps = { 12 | colabs: Colab[], 13 | } 14 | 15 | const ColabList = ({colabs}: ColabListProps) => { 16 | return ( 17 | <> 18 |

    Zoznam reportov

    19 | 20 | {colabs.map((colab, index) => ( 21 | 22 | ))} 23 | 24 | 25 | ) 26 | } 27 | 28 | export default compose( 29 | withDataProviders(() => [colabsProvider()]), 30 | connect((state: State) => ({ 31 | colabs: colabsSelector(state), 32 | })) 33 | )(ColabList) 34 | -------------------------------------------------------------------------------- /client/src/components/shared/Info/Contracts.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import React from 'react' 3 | 4 | import InfoButton from './InfoButton' 5 | import ExternalLink from '../ExternalLink' 6 | import {ShowNumberCurrency, showContractStatus} from '../../../services/utilities' 7 | import type {Contracts as ContractsType, Contract} from '../../../state' 8 | 9 | type ContractsProps = {| 10 | data: ContractsType, 11 | |} 12 | 13 | const buildContract = (contract: Contract) => ( 14 |
  • 15 | 16 | {`${contract.client_name}, `} 17 | 18 | 19 |  ({showContractStatus(contract.status_id)}) 20 |
  • 21 | ) 22 | 23 | const Contracts = ({data}: ContractsProps) => ( 24 | 31 | ) 32 | 33 | export default Contracts 34 | -------------------------------------------------------------------------------- /client/src/components/shared/Info/Notices.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import React from 'react' 3 | import {Link} from 'react-router-dom' 4 | 5 | import InfoButton from './InfoButton' 6 | import {ShowNumberCurrency} from '../../../services/utilities' 7 | import type {Notices as NoticesType, NoticeNew} from '../../../state' 8 | 9 | type NoticesProps = {| 10 | data: NoticesType, 11 | |} 12 | 13 | const Notices = ({data}: NoticesProps) => ( 14 | ( 20 |
  • 21 | 22 | {notice.client_name} 23 | {notice.total_final_value_amount ? ', ' : ''} 24 | 25 |
    26 | {notice.title} 27 | 28 |
  • 29 | )} 30 | /> 31 | ) 32 | 33 | export default Notices 34 | -------------------------------------------------------------------------------- /client/src/slovakiaData/region-centers.json: -------------------------------------------------------------------------------- 1 | [{"name": "Bratislavský kraj","id": "SK010","COM": [17.17913991484353, 48.31702743772923],"centroid": [17.216635192857144, 48.20743832857144]},{"name": "Trnavský kraj","id": "SK021","COM": [17.671948, 48.3734285],"centroid": [17.771948, 48.3734285]},{"name": "Trenčiansky kraj","id": "SK022","COM": [18.21306755409922, 48.858637528619425],"centroid": [18.117979647398833, 48.831050028901736]},{"name": "Nitriansky kraj","id": "SK023","COM": [18.310653355215717, 48.14201958285858],"centroid": [18.336795553398073, 48.13573134466019]},{"name": "Žilinský kraj","id": "SK031","COM": [19.177214890371214, 49.17749480833444],"centroid": [19.214167658163266, 49.170340500000016]},{"name": "Banskobystrický kraj","id": "SK032","COM": [19.504584201317822, 48.515719407277146],"centroid": [19.706075951417012, 48.52751534817815]},{"name": "Prešovský kraj","id": "SK041","COM": [21.223683821543965, 49.123561512487505],"centroid": [21.043058, 49.11351596474359]},{"name": "Košický kraj","id": "SK042","COM": [21.26639502809723, 48.69743547387148],"centroid": [21.17882908208955, 48.71501465671642]}] -------------------------------------------------------------------------------- /client/flow-typed/npm/eslint-config-vacuumlabs_vx.x.x.js: -------------------------------------------------------------------------------- 1 | // flow-typed signature: 5055c7ccafa20765caed69321f6bc78e 2 | // flow-typed version: <>/eslint-config-vacuumlabs_v^1.5.0/flow_v0.71.0 3 | 4 | /** 5 | * This is an autogenerated libdef stub for: 6 | * 7 | * 'eslint-config-vacuumlabs' 8 | * 9 | * Fill this stub out by replacing all the `any` types. 10 | * 11 | * Once filled out, we encourage you to share your work with the 12 | * community by sending a pull request to: 13 | * https://github.com/flowtype/flow-typed 14 | */ 15 | 16 | declare module 'eslint-config-vacuumlabs' { 17 | declare module.exports: any 18 | } 19 | 20 | /** 21 | * We include stubs for each file inside this npm package in case you need to 22 | * require those files directly. Feel free to delete any files that aren't 23 | * needed. 24 | */ 25 | 26 | // Filename aliases 27 | declare module 'eslint-config-vacuumlabs/index' { 28 | declare module.exports: $Exports<'eslint-config-vacuumlabs'> 29 | } 30 | declare module 'eslint-config-vacuumlabs/index.js' { 31 | declare module.exports: $Exports<'eslint-config-vacuumlabs'> 32 | } 33 | -------------------------------------------------------------------------------- /client/src/dataWrappers/CompanyDetailWrapper.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import React from 'react' 3 | import {compose} from 'redux' 4 | import {connect} from 'react-redux' 5 | import {withDataProviders} from 'data-provider' 6 | import type {ComponentType} from 'react' 7 | import type {State, NewEntityDetail} from '../state' 8 | import {entityDetailProvider} from '../dataProviders/sharedDataProviders' 9 | import {entityDetailSelector} from '../selectors' 10 | 11 | type BaseCompanyDetailProps = { 12 | eid: number, 13 | } 14 | 15 | export type CompanyDetailProps = { 16 | eid: number, 17 | company: NewEntityDetail, 18 | onClose?: () => void, 19 | } 20 | 21 | const CompanyDetailWrapper = ( 22 | WrappedComponent: ComponentType 23 | ): ComponentType => { 24 | const wrapped = (props: CompanyDetailProps) => 25 | 26 | return compose( 27 | withDataProviders(({eid}: BaseCompanyDetailProps) => [entityDetailProvider(eid)]), 28 | connect((state: State, props: BaseCompanyDetailProps) => ({ 29 | company: entityDetailSelector(state, props.eid), 30 | })) 31 | )(wrapped) 32 | } 33 | 34 | export default CompanyDetailWrapper 35 | -------------------------------------------------------------------------------- /obstaravania/skip_norms.txt: -------------------------------------------------------------------------------- 1 | dodavk 2 | sutaznych 3 | podkladov 4 | blizs 5 | nakup 6 | kup 7 | novych 8 | kusov 9 | technologickej 10 | technologick 11 | technolog 12 | proces 13 | stroj 14 | logick 15 | min 16 | max 17 | celok 18 | celk 19 | zlozen 20 | specifikovan 21 | specifikovanych 22 | predmetom 23 | zakazk 24 | priloh 25 | ucelom 26 | pred 27 | program 28 | zadan 29 | obstaravan 30 | potrieb 31 | vsetk 32 | ucelovych 33 | sucast 34 | predmet 35 | bud 36 | nasledovn 37 | plnen 38 | podkladoch 39 | poziadaviek 40 | poziadavk 41 | podrobn 42 | popis 43 | uveden 44 | cinnost 45 | zmluv 46 | blizs 47 | specifikac 48 | zabezpecen 49 | sluzieb 50 | verejneh 51 | pred 52 | obstaravatel 53 | dohod 54 | dohodnutych 55 | jej 56 | sluzb 57 | vyber 58 | zmysl 59 | zakon 60 | statnych 61 | zakonov 62 | znen 63 | neskorsich 64 | predpisov 65 | doplnen 66 | dalej 67 | len 68 | doplnenim 69 | predpisov 70 | zaklad 71 | zakonnik 72 | zbierk 73 | projekt 74 | vseobecn 75 | zavaznych 76 | pravnych 77 | predpisov 78 | ktor 79 | vztahuj 80 | bratislav 81 | informac 82 | zriadovatelskej 83 | posobnost 84 | samospravneh 85 | ponuk 86 | predlozit 87 | vyhradzuj 88 | uchadzac 89 | predklad 90 | pozadovan 91 | zadefinovan 92 | -------------------------------------------------------------------------------- /test_all.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # set bash strict mode - fail immediately if anything fails 4 | set -eu 5 | IFS=$'\n\t' 6 | 7 | # Get the script's directory: 8 | DIR=$(dirname "$(readlink -f "$0")") 9 | 10 | # test verejne 11 | echo "Testing verejne" 12 | cd "${DIR}"/verejne 13 | sh deploy.sh 14 | . venv/bin/activate 15 | sudo -u verejne python test.py 16 | echo "Testing verejne completed!" 17 | 18 | # test prepojenia 19 | echo "Testing prepojenia" 20 | cd "${DIR}"/prepojenia 21 | sh deploy.sh 22 | . venv/bin/activate 23 | sudo -u prepojenia python test.py 24 | echo "Testing prepojenia completed!" 25 | 26 | # test obstaravania 27 | echo "Testing obstaravania" 28 | cd "${DIR}"/obstaravania 29 | sh deploy.sh 30 | . venv/bin/activate 31 | sudo -u obstaravania python test.py 32 | echo "Testing obstaravania completed!" 33 | 34 | # test kataster 35 | echo "Testing kataster" 36 | cd "${DIR}"/kataster 37 | sh deploy.sh 38 | . venv/bin/activate 39 | sudo -u kataster python test.py 40 | echo "Testing kataster completed!" 41 | 42 | # test data 43 | echo "Testing data" 44 | cd "${DIR}"/data 45 | sh deploy.sh 46 | . venv/bin/activate 47 | sudo -u data python test.py 48 | echo "Testing data completed!" 49 | 50 | echo "All tests completed" -------------------------------------------------------------------------------- /client/src/actions/sharedActions.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import {merge} from 'lodash' 3 | import {mappingFn as defaultMappingFn} from '../utils' 4 | import {refreshedUIState, type State} from '../state' 5 | 6 | import type {GenericAction, Path} from '../types/reduxTypes' 7 | 8 | // merges new data into destination Path according to the mappingFn provided 9 | export const receiveData = ( 10 | path: Path, 11 | data: Array | Object, 12 | dataProviderRef: string, 13 | mappingFn: (Array | Object, ...args?: Array) => Object = defaultMappingFn, 14 | ...mappingFnArgs: Array 15 | ): GenericAction | Object> => ({ 16 | type: `Received data from ${dataProviderRef}`, 17 | path, 18 | payload: data, 19 | reducer: (state, data) => ({...state, ...mappingFn(data, ...mappingFnArgs)}), 20 | }) 21 | 22 | export const updateValue = (path: Path, data: T, type?: string): GenericAction => ({ 23 | type: type || 'Update data on path', 24 | payload: data, 25 | path, 26 | reducer: (state: T, data: T) => data, 27 | }) 28 | 29 | export const refreshState = () => ({ 30 | type: 'refresh state', 31 | path: null, 32 | reducer: (state: State) => (merge({}, state, refreshedUIState)), 33 | }) 34 | -------------------------------------------------------------------------------- /client/src/components/variables.scss: -------------------------------------------------------------------------------- 1 | $text: #333; 2 | $secondary: #6c8294; 3 | $navbar-height: 45px; 4 | // Card 5 | $card-border: #cad3d9; 6 | // Verejne 7 | $item-success-color: #468966; 8 | $blue-color: #0062db; 9 | $form-control-bg-color: #f2f5f8; 10 | $orange-color: #e55600; 11 | $verejne-sidebar-width: 350px; 12 | $verejne-searched-entity-background: #f1f4f5; 13 | // google map 14 | $cluster-marker-border: rgba(0, 80, 255, .9); 15 | $marker-width: 2rem; 16 | $marker-height: 2rem; 17 | $marker-color: rgba(66, 134, 244, .9); 18 | // Profil 19 | $component-background: white; 20 | $footer-background: #f1f4f5; 21 | $border-color: #cddae3; 22 | $shadow-color: rgba(187, 198, 206, .5); 23 | $asset-hover-color: #fafafa; 24 | $input-inset-shadow-color: rgba(0, 0, 0, .075); 25 | $input-shadow-color: rgba(102, 175, 233, .6); 26 | $link-color: #333; 27 | $search-color: #555; 28 | $active-tab-color: #337ab7; 29 | $search-border-color: #66afe9; 30 | $marker-background: rgba(255, 255, 255, .75); 31 | $marker-border: #0062db; 32 | $marker-text-color: #337ab7; 33 | //Obstaravania 34 | $label-color: darkgrey; 35 | $warning-1-color: gold; 36 | $warning-2-color: orange; 37 | $warning-3-color: red; 38 | $plus-value-color: green; 39 | $minus-value-color: red; 40 | -------------------------------------------------------------------------------- /data/update_finstat.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # set bash strict mode - fail immediately if anything fails 4 | set -eu 5 | IFS=$'\n\t' 6 | 7 | # Parameters 8 | URL=$1 9 | TMPDIR=/tmp/update_finstat.$$ 10 | 11 | # Ensure the temporary directory is deleted whenever the script terminates 12 | trap 'rm -rf ${TMPDIR}' EXIT 13 | 14 | # Download URL into the temporary directory 15 | mkdir $TMPDIR 16 | echo "Downloading finstat from $URL" 17 | curl -sfo ${TMPDIR}/finstat.zip "$URL" 18 | 19 | # Unzip 20 | echo "Unzipping finstat..." 21 | unzip -o ${TMPDIR}/finstat.zip -d ${TMPDIR} 22 | 23 | # The header line of company_stats.csv starts with 4 unneeded characters. 24 | # Also, each subsequent line starts with = and ends with a redundant delimiter. 25 | # Remove these using awk and tail (to handle the header line) 26 | echo "Removing header and leading/trailing chars..." 27 | awk '{print substr($0, 2, length($0)-3)}' ${TMPDIR}/company_stats.csv | tail +3c > ${TMPDIR}/company_stats_cleaned.csv 28 | 29 | # Move the cleaned CSV into the location expected by the source data updating Python script 30 | mv ${TMPDIR}/company_stats_cleaned.csv /tmp/source_finstat.csv 31 | shift 32 | echo "python source_update.py finstat" "$@" 33 | eval python source_update.py finstat "$@" 34 | -------------------------------------------------------------------------------- /client/src/components/Profile/components/Cardboard.scss: -------------------------------------------------------------------------------- 1 | @import '../../variables.scss'; 2 | 3 | .profile-cardboard { 4 | text-align: left; 5 | width: 100%; 6 | padding: 10px; 7 | padding-left: 30px; 8 | border: 3px; 9 | border-color: $border-color; 10 | border-style: solid; 11 | background-color: $component-background; 12 | margin-top: 30px; 13 | margin-bottom: 20px; 14 | position: relative; 15 | min-height: 190px; 16 | box-shadow: 0 4px 12px 0 $shadow-color; 17 | 18 | @media screen and (max-width: 766px) { 19 | text-align: center; 20 | padding-left: 10px; 21 | } 22 | 23 | dd { 24 | float: left; 25 | } 26 | 27 | dt::after { 28 | content: ':'; 29 | } 30 | 31 | .picture { 32 | height: 180px; 33 | position: absolute; 34 | top: -20px; 35 | right: 50px; 36 | box-shadow: 0 4px 12px 0 $shadow-color; 37 | border: 2px solid $border-color; 38 | background: $component-background; 39 | 40 | @media screen and (max-width: 766px) { 41 | position: static; 42 | display: block; 43 | margin: 1rem auto; 44 | } 45 | } 46 | 47 | .bolder { 48 | font-weight: bolder; 49 | } 50 | 51 | .name { 52 | font-weight: bold; 53 | padding-bottom: 20px; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /client/src/dataProviders/noticesDataProviders.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import {dispatchReceivedData} from './dataProvidersUtils' 3 | import {DEFAULT_PROVIDER_KEEP_ALIVE} from '../constants' 4 | import {mapObjToId} from '../utils' 5 | import {updateValue} from '../actions/sharedActions' 6 | import type {Notice} from '../state' 7 | import type {Dispatch} from '../types/reduxTypes' 8 | 9 | const dispatchNoticesList = () => (ref: string, data: Array, dispatch: Dispatch) => 10 | dispatch(updateValue(['notices', 'list'], data, ref)) 11 | 12 | export const noticesProvider = () => ({ 13 | ref: 'notices', 14 | getData: [ 15 | fetch, 16 | `${process.env.REACT_APP_API_URL || ''}/api/o/list_notices`, 17 | { 18 | accept: 'application/json', 19 | }, 20 | ], 21 | onData: [dispatchNoticesList], 22 | keepAliveFor: DEFAULT_PROVIDER_KEEP_ALIVE, 23 | }) 24 | 25 | export const noticeDetailProvider = (id: string) => ({ 26 | ref: `noticeDetail-${id}`, 27 | getData: [ 28 | fetch, 29 | `${process.env.REACT_APP_API_URL || ''}/api/o/info_notice?id=${id}`, 30 | { 31 | accept: 'application/json', 32 | }, 33 | ], 34 | onData: [dispatchReceivedData, ['notices', 'details'], mapObjToId, id], 35 | keepAliveFor: 60 * 60 * 1000, 36 | }) 37 | -------------------------------------------------------------------------------- /client/src/components/Landing/icons/ihrisko.svg: -------------------------------------------------------------------------------- 1 | Asset 6 -------------------------------------------------------------------------------- /obstaravania/test.py: -------------------------------------------------------------------------------- 1 | """Unit tests for server obstaravania. 2 | Run all unit test from command line as: 3 | python test.py 4 | To run an individual unit test only, run (for example): 5 | python test.py TestHandlers.test_subgraph 6 | """ 7 | import json 8 | import os 9 | import sys 10 | import unittest 11 | import webapp2 12 | 13 | sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '../data/db'))) 14 | from db import DatabaseConnection 15 | 16 | import serving 17 | 18 | 19 | def _request_json(url, test_handler): 20 | """Verifies that the given URL returns a valid JSON.""" 21 | request = webapp2.Request.blank(url) 22 | response = request.get_response(serving.app) 23 | test_handler.assertEqual(response.status_int, 200) 24 | test_handler.assertEqual(response.content_type, 'application/json') 25 | j = json.loads(response.text) 26 | return j 27 | 28 | 29 | class TestHandlers(unittest.TestCase): 30 | 31 | def test_info_notice(self): 32 | url = '/info_notice?id=159012' 33 | content = _request_json(url, self) 34 | print('InfoNotice:\n%s' % (content)) 35 | 36 | 37 | def main(): 38 | serving.initialise_app() 39 | unittest.main() 40 | 41 | 42 | if __name__ == '__main__': 43 | main() 44 | -------------------------------------------------------------------------------- /client/flow-typed/npm/prettier-eslint_vx.x.x.js: -------------------------------------------------------------------------------- 1 | // flow-typed signature: f1a1dcb37faab036a3de2806c600a86e 2 | // flow-typed version: <>/prettier-eslint_v^8.8.1/flow_v0.71.0 3 | 4 | /** 5 | * This is an autogenerated libdef stub for: 6 | * 7 | * 'prettier-eslint' 8 | * 9 | * Fill this stub out by replacing all the `any` types. 10 | * 11 | * Once filled out, we encourage you to share your work with the 12 | * community by sending a pull request to: 13 | * https://github.com/flowtype/flow-typed 14 | */ 15 | 16 | declare module 'prettier-eslint' { 17 | declare module.exports: any 18 | } 19 | 20 | /** 21 | * We include stubs for each file inside this npm package in case you need to 22 | * require those files directly. Feel free to delete any files that aren't 23 | * needed. 24 | */ 25 | declare module 'prettier-eslint/dist/index' { 26 | declare module.exports: any 27 | } 28 | 29 | declare module 'prettier-eslint/dist/utils' { 30 | declare module.exports: any 31 | } 32 | 33 | // Filename aliases 34 | declare module 'prettier-eslint/dist/index.js' { 35 | declare module.exports: $Exports<'prettier-eslint/dist/index'> 36 | } 37 | declare module 'prettier-eslint/dist/utils.js' { 38 | declare module.exports: $Exports<'prettier-eslint/dist/utils'> 39 | } 40 | -------------------------------------------------------------------------------- /obstaravania/static/obstaravania.js: -------------------------------------------------------------------------------- 1 | function close_button(divid) { 2 | return ""; 3 | } 4 | 5 | function close_div(divid) { 6 | document.getElementById(divid+'_long').style.display = 'none'; 7 | document.getElementById(divid).style.display = 'block'; 8 | } 9 | 10 | function getSearchInfo(eid, divid) { 11 | var resultsText; 12 | var req = serverURL + 'getInfo?eid=' + eid; 13 | var xmlhttp = new XMLHttpRequest(); 14 | xmlhttp.onreadystatechange = function() { 15 | if (xmlhttp.readyState == 4 && xmlhttp.status == 200) { 16 | var jsonData = JSON.parse(xmlhttp.responseText); 17 | document.getElementById(divid+'_long').innerHTML = close_button(divid) + displayInfoPrepojenia(jsonData, eid); 18 | document.getElementById(divid+'_long').style.display = 'block'; 19 | document.getElementById(divid).style.display = 'none'; 20 | } 21 | } 22 | xmlhttp.open("GET", req, true); 23 | xmlhttp.send(); 24 | } -------------------------------------------------------------------------------- /client/src/components/Notices/LegendSymbols.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import {FaQuestionCircle, FaExclamationTriangle} from 'react-icons/fa' 3 | import classnames from 'classnames' 4 | import React from 'react' 5 | 6 | export const getWarningSymbol = (level: number, title: string | null = null) => { 7 | if (level < 0) { 8 | return ( 9 |
    10 | 11 |
    12 | ) 13 | } else if (level > 0) { 14 | return ( 15 |
    16 | 17 |
    18 | ) 19 | } else { 20 | return '' 21 | } 22 | } 23 | 24 | export const formatSimilarPercent = (value: number) => { 25 | let style 26 | if (value > 75) style = 'similarity-high' 27 | else if (value > 50) style = 'similarity-medium' 28 | else if (value > 25) style = 'similarity-low' 29 | else style = '' 30 | 31 | return {value}% 32 | } 33 | 34 | export const formatSimilarCount = (value: number) => ( 35 | 36 | {value > 20 ? '20+' : value} 37 | 38 | ) 39 | -------------------------------------------------------------------------------- /client/src/components/shared/Info/FinancesItem.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import React from 'react' 3 | import {isNumber} from 'lodash' 4 | 5 | import { 6 | icoUrl, 7 | ShowNumberCurrency, 8 | type EnhancedCompanyFinancial, 9 | } from '../../../services/utilities' 10 | import Item from './Item' 11 | import Trend from './Trend' 12 | import './FinancesItem.css' 13 | 14 | type FinancesItemProps = {| 15 | data: EnhancedCompanyFinancial, 16 | ico: string, 17 | |} 18 | 19 | const FinancesItem = ({ 20 | data: {employees, profit, profitTrend, revenue, revenueTrend, year}, 21 | ico, 22 | }: FinancesItemProps) => ( 23 |
    24 | {employees && {employees}} 25 | {isNumber(profit) && ( 26 | } 30 | > 31 | 32 | 33 | )} 34 | {isNumber(revenue) && ( 35 | } 39 | > 40 | 41 | 42 | )} 43 |
    44 | ) 45 | 46 | export default FinancesItem 47 | -------------------------------------------------------------------------------- /obstaravania/db_old.py: -------------------------------------------------------------------------------- 1 | # TODO: this is copied all over the place 2 | # Do proper packaging / deployment 3 | import psycopg2 4 | import psycopg2.extras 5 | import yaml 6 | 7 | # database used in the module 8 | db = None 9 | 10 | 11 | def getConfig(): 12 | with open("db_config_old.yaml", "r", encoding='utf-8') as stream: 13 | return yaml.load(stream, Loader=yaml.FullLoader) 14 | #return yaml.load(stream, Loader=yaml.FullLoader) 15 | 16 | 17 | def connect(local=True): 18 | global db, args 19 | config = getConfig() 20 | db = psycopg2.connect(user=config["user"], dbname=config["db"]) 21 | db.autocommit = True 22 | 23 | 24 | def log(s): 25 | print("LOG: " + s) 26 | 27 | 28 | def execute(cur, sql, params=None): 29 | if params is None: 30 | params = [] 31 | try: 32 | cur.execute(sql, params) 33 | except Exception as ex: 34 | print("Exception in SQL execution, retrying command once") 35 | print(ex) 36 | connect(False) 37 | cur = getCursor() 38 | cur.execute(sql, params) 39 | return cur 40 | 41 | 42 | def getCursor(): 43 | if db is None or db.closed: 44 | connect(False) 45 | cur = db.cursor(cursor_factory=psycopg2.extras.RealDictCursor) 46 | cur.execute("SET search_path = 'mysql'") 47 | return cur 48 | -------------------------------------------------------------------------------- /client/src/components/shared/Info/Findata.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import React, {Fragment} from 'react' 3 | 4 | import type {FinancialData} from '../../../services/utilities' 5 | import {icoUrl, showDate} from '../../../services/utilities' 6 | import Finances from './Finances' 7 | import Item from './Item' 8 | import ExternalLink from '../ExternalLink' 9 | 10 | type FindataProps = { 11 | data: FinancialData, 12 | } 13 | 14 | const Findata = ({ 15 | data: {established_on: establishedOn, finances, ico, terminated_on: terminatedOn, legal_form_id}, 16 | }: FindataProps) => ( 17 | 18 | 25 |  ( 26 | 27 | Detaily o {legal_form_id === 243 || legal_form_id === 6 ? 'podnikateľovi' : 'firme'} 28 | 29 | ) 30 | 31 | {establishedOn && {showDate(establishedOn)}} 32 | {terminatedOn && {showDate(terminatedOn)}} 33 | 34 | 35 | ) 36 | 37 | export default Findata 38 | -------------------------------------------------------------------------------- /client/src/components/shared/Legend/Legend.scss: -------------------------------------------------------------------------------- 1 | @import "../../variables.scss"; 2 | 3 | .legend { 4 | background: white; 5 | padding: .3rem; 6 | //width: 11.3rem; 7 | //height: 10.3rem; 8 | border: 1px solid $border-color; 9 | box-shadow: 0 4px 12px 0 $shadow-color; 10 | 11 | &__Header { 12 | display: flex; 13 | } 14 | 15 | &.position-absolute { 16 | position: absolute; 17 | right: 1.3rem; 18 | bottom: 2rem; 19 | } 20 | 21 | p { 22 | text-align: left; 23 | font-size: .8rem; 24 | margin-bottom: 0; 25 | } 26 | } 27 | 28 | 29 | button.legend { 30 | cursor: pointer; 31 | } 32 | 33 | .svg { 34 | color: $blue-color; 35 | margin-right: .2rem; 36 | } 37 | 38 | .orange { 39 | color: $orange-color; 40 | } 41 | 42 | .purple { 43 | color: purple; 44 | } 45 | 46 | .map-icon-image { 47 | width: 1rem; 48 | height: 1rem; 49 | } 50 | 51 | .legend-marker { 52 | position: relative; 53 | border-radius: 50%; 54 | border: 3px solid $cluster-marker-border; 55 | background-color: $marker-color; 56 | text-align: center; 57 | width: 1rem; 58 | height: 1rem; 59 | font-size: .7rem !important; 60 | font-weight: bold; 61 | display: inline-flex; 62 | justify-content: center; 63 | align-items: center; 64 | color: #fff !important; 65 | margin-right: .1rem; 66 | } 67 | -------------------------------------------------------------------------------- /data/prod_generation/graph_tools.py: -------------------------------------------------------------------------------- 1 | """Functions for manipulating the graph of entities.""" 2 | 3 | 4 | def add_or_get_edge_type(db, edge_type_name, log_prefix=""): 5 | """Returns id of edge type with given name, creating if needed.""" 6 | 7 | # Query edge types: 8 | edge_types = db.query(""" 9 | SELECT stakeholder_type_id, stakeholder_type_text 10 | FROM stakeholdertypes; 11 | """) 12 | edge_type_name_to_index = {edge_type["stakeholder_type_text"]: 13 | edge_type["stakeholder_type_id"] 14 | for edge_type in edge_types} 15 | 16 | # Find or create edge type for presumed family members: 17 | if edge_type_name in edge_type_name_to_index: 18 | edge_type_index = edge_type_name_to_index[edge_type_name] 19 | else: 20 | edge_type_index = max(edge_type["stakeholder_type_id"] 21 | for edge_type in edge_types) + 1 22 | db.execute(""" 23 | INSERT INTO stakeholdertypes( 24 | stakeholder_type_id, 25 | stakeholder_type_text 26 | ) VALUES (%s, %s);""", [edge_type_index, edge_type_name]) 27 | 28 | print('%sEdge type name "%s" has index %d' % (log_prefix, edge_type_name, edge_type_index)) 29 | return edge_type_index 30 | -------------------------------------------------------------------------------- /client/src/components/Connections/dataWrappers/EntityWrapper.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import React from 'react' 3 | import {compose} from 'redux' 4 | import {connect} from 'react-redux' 5 | import {withDataProviders} from 'data-provider' 6 | import type {ComponentType} from 'react' 7 | import type {EntitySearchProps} from './EntitySearchWrapper' 8 | import type {State, SearchedEntity} from '../../../state' 9 | import {entitySearchProvider} from '../../../dataProviders/sharedDataProviders' 10 | import {entitySearchSelector} from '../../../selectors' 11 | 12 | export type EntityProps = { 13 | entity1: SearchedEntity, 14 | entity2: SearchedEntity, 15 | } 16 | 17 | const EntityWrapper = (WrappedComponent: ComponentType<*>) => { 18 | const wrapped = (props: EntityProps) => 19 | props.entity1 && props.entity2 ? : null 20 | 21 | return compose( 22 | withDataProviders(({entitySearch1, entitySearch2}: EntitySearchProps) => [ 23 | entitySearchProvider(entitySearch1), 24 | entitySearchProvider(entitySearch2), 25 | ]), 26 | connect((state: State, props: EntitySearchProps) => ({ 27 | entity1: entitySearchSelector(state, props.entitySearch1), 28 | entity2: entitySearchSelector(state, props.entitySearch2), 29 | })) 30 | )(wrapped) 31 | } 32 | 33 | export default EntityWrapper 34 | -------------------------------------------------------------------------------- /client/src/components/Public/Map/ClusterMarker/ClusterMarker.scss: -------------------------------------------------------------------------------- 1 | @import "../../../variables.scss"; 2 | 3 | .cluster-marker { 4 | border-radius: 50%; 5 | border: 3px solid $cluster-marker-border; 6 | background-color: $marker-color; 7 | text-align: center; 8 | color: $marker-color !important; 9 | } 10 | 11 | .simple-marker { 12 | background: url('../../../../assets/mapIcon.svg') no-repeat; 13 | background-size: contain; 14 | transform: translate(0, -50%); 15 | 16 | &:hover { 17 | transform: translate(0, -50%) scale(1.2); 18 | transition: .2s ease; 19 | } 20 | } 21 | 22 | .selected { 23 | background: white !important; 24 | border-radius: 50%; 25 | box-shadow: 0 0 10px 8px $cluster-marker-border, 0 0 2px $cluster-marker-border inset; 26 | } 27 | 28 | .map-label { 29 | border-radius: .4em; 30 | border: 3px solid $cluster-marker-border; 31 | background-color: $marker-color; 32 | text-align: center; 33 | width: auto; 34 | height: auto; 35 | padding: .3em; 36 | transform: translate(-50%, -50%); 37 | 38 | &:hover { 39 | transform: translate(-50%, -50%) scale(1.2); 40 | transition: .2s ease; 41 | } 42 | } 43 | 44 | .company-marker { 45 | display: flex; 46 | justify-content: center; 47 | align-self: center; 48 | 49 | svg { 50 | transform: scale(0.9); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /client/src/dataProviders/publiclyDataProviders.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import {setAddresses, setEntities} from '../actions/publicActions' 3 | import type {Address, NewEntity} from '../state' 4 | import type {Dispatch} from '../types/reduxTypes' 5 | 6 | const dispatchAddresses = () => (ref: string, data: Address[], dispatch: Dispatch) => { 7 | dispatch(setAddresses(data)) 8 | } 9 | 10 | const dispatchEntities = () => (ref: number[], data: NewEntity[], dispatch: Dispatch) => { 11 | dispatch(setEntities(data, ref[1])) 12 | } 13 | 14 | export const addressesProvider = (addressesUrl: string) => { 15 | return { 16 | ref: addressesUrl, 17 | getData: [ 18 | fetch, 19 | addressesUrl, 20 | { 21 | accept: 'application/json', 22 | }, 23 | ], 24 | onData: [dispatchAddresses], 25 | needed: false, 26 | } 27 | } 28 | 29 | export const addressEntitiesProvider = (addressId: number) => { 30 | const requestPrefix = `${process.env.REACT_APP_API_URL || ''}` 31 | return { 32 | ref: ['addressEntities', addressId], 33 | getData: [ 34 | fetch, 35 | `${requestPrefix}/api/v/getEntitiesAtAddressId?address_id=${addressId}`, 36 | { 37 | accept: 'application/json', 38 | }, 39 | ], 40 | onData: [dispatchEntities], 41 | keepAliveFor: 60 * 60 * 1000, 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /client/src/components/Notices/Legend.scss: -------------------------------------------------------------------------------- 1 | @import '../variables.scss'; 2 | 3 | .notice-legend { 4 | width: 85%; 5 | margin: 2em auto 0 auto; 6 | display: flex; 7 | justify-content: center; 8 | 9 | @media screen and (max-width: 767px) { 10 | width: 90%; 11 | } 12 | 13 | @media screen and (max-width: 649px) { 14 | width: 95%; 15 | } 16 | 17 | @media screen and (max-width: 575px) { 18 | width: 100%; 19 | } 20 | 21 | @media screen and (max-width: 480px) { 22 | flex-direction: column; 23 | } 24 | } 25 | 26 | .notice-legend-label { 27 | color: $secondary; 28 | font-weight: normal; 29 | font-size: 1rem; 30 | margin-bottom: 0; 31 | 32 | @media screen and (max-width: 480px) { 33 | margin-bottom: 0.5em; 34 | } 35 | } 36 | 37 | .notice-legend-items { 38 | margin: 0; 39 | display: grid; 40 | grid-template-columns: repeat(4, auto); 41 | 42 | @media screen and (max-width: 767px) { 43 | grid-template-columns: repeat(2, auto); 44 | } 45 | 46 | @media screen and (max-width: 480px) { 47 | grid-template-columns: 3em auto; 48 | } 49 | 50 | dt, dd { 51 | margin: 0; 52 | } 53 | 54 | dt { 55 | padding-left: .75em; 56 | 57 | @media screen and (max-width: 480px) { 58 | padding-left: 0; 59 | } 60 | } 61 | 62 | dd { 63 | padding-left: .25em; 64 | } 65 | } -------------------------------------------------------------------------------- /data/geocoder_test.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | import geocoder as geocoder_lib 4 | from db.db import DatabaseConnection 5 | 6 | 7 | class GeocoderTest(unittest.TestCase): 8 | 9 | # Setup is a class method, otherwise it instantiates geocoder for each single test which 10 | # then causes to read data from database for every single test which is then slow. 11 | @classmethod 12 | def setUpClass(cls): 13 | super(GeocoderTest, cls).setUpClass() 14 | db_address_cache = DatabaseConnection( 15 | path_config='db_config_update_source.yaml', 16 | search_path='address_cache') 17 | cls.geocoder = geocoder_lib.Geocoder(db_address_cache, None, True) 18 | 19 | def test_case_insensitive(self): 20 | self.assertEqual( 21 | list(self.geocoder.GetKeysForAddress("ulica 11/222 33333 mesto")), 22 | list(self.geocoder.GetKeysForAddress("UliCa 11/222 33333 MesTO ")), 23 | ) 24 | 25 | def test_keys_match(self): 26 | self.assertCountEqual( 27 | self.geocoder.GetKeysForAddress("Ulica 11/222 33333 Mesto"), 28 | ['ulica11/22233333mesto', 'ulica222/1133333mesto', 'ulica22233333mesto', 29 | 'ulica11/222mesto', 'ulica222/11mesto', 'ulica222mesto'] 30 | ) 31 | 32 | 33 | if __name__ == '__main__': 34 | unittest.main() 35 | -------------------------------------------------------------------------------- /data/utils.py: -------------------------------------------------------------------------------- 1 | """Utility methods for data handling.""" 2 | 3 | import json 4 | import unicodedata 5 | import yaml 6 | 7 | 8 | def remove_accents(s): 9 | s_NFKD = unicodedata.normalize('NFKD', s) 10 | return ''.join([c for c in s_NFKD if not unicodedata.combining(c)]) 11 | 12 | 13 | def json_load(path): 14 | with open(path, 'rt', encoding='utf-8') as f: 15 | data_json = json.load(f) 16 | return data_json 17 | 18 | 19 | def json_dump_utf8(var, path, indent=4, flatten_level=None): 20 | with open(path, 'w', encoding='utf-8') as f: 21 | data = json.dumps(var, indent=indent, sort_keys=True, separators=(',', ': '), ensure_ascii=False) 22 | if (indent is not None) and (flatten_level is not None): 23 | flatten_string = '\n' + ' ' * (indent * flatten_level) 24 | data = data.replace(flatten_string, ' ') 25 | data = data.replace('\n' + ' ' * (indent * (flatten_level - 1)) + ']', ']') 26 | f.write(str(data)) 27 | 28 | 29 | def yaml_load(path): 30 | with open(path, 'rt', encoding='utf-8') as f: 31 | data_yaml = yaml.load(f, Loader=yaml.FullLoader) 32 | return data_yaml 33 | 34 | 35 | def execute_script(db, path): 36 | """Executes SQL script at `path` on database `db`.""" 37 | with open(path, 'r', encoding='utf-8') as f: 38 | db.execute(f.read()) 39 | -------------------------------------------------------------------------------- /client/src/components/Loading/Loading.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import React from 'react' 3 | import LoadingComponent from 'react-loading-components' 4 | import './Loading.css' 5 | import {defaultProps} from 'recompose' 6 | import {ListGroupItem} from 'reactstrap' 7 | import {LOADING_CIRCLE_COLOR} from '../../constants' 8 | 9 | type Props = { 10 | width: number, 11 | height: number, 12 | } 13 | 14 | const Loading = ({width, height}: Props) => ( 15 |
    16 | 17 |
    18 | ) 19 | export const EntityDetailLoading = () => ( 20 | 21 |
    22 | 23 |
    24 |
    25 | ) 26 | export const ModalLoading = () => ( 27 |
    28 | 29 |
    30 | ) 31 | export const GraphLoading = () => ( 32 |
    33 | 34 |
    35 | ) 36 | export default defaultProps({ 37 | width: 250, 38 | height: 250, 39 | })(Loading) 40 | -------------------------------------------------------------------------------- /client/src/components/Notices/Bulletin.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import React from 'react' 3 | import './Legend.css' 4 | import './LegendSymbols.css' 5 | import NoticeItem from './NoticeItem' 6 | import {Table} from 'reactstrap' 7 | import ExternalLink from '../shared/ExternalLink' 8 | 9 | import type {Notice} from '../../state' 10 | 11 | import './Bulletin.css' 12 | 13 | type Props = {| 14 | items: Array, 15 | number: number, 16 | year: number, 17 | date: string, 18 | |} 19 | 20 | const Bulletin = ({items, number, year, date}: Props) => ( 21 |
    22 |

    23 | {date} 24 | 25 | Vestník číslo 26 | 27 | {number}/{year} 28 | 29 | 30 |

    31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | {items.map((item) => )} 41 |
    Názov obstarávaniaObjednávateľKto by sa mal prihlásiťPod.
    42 |
    43 | ) 44 | 45 | export default Bulletin 46 | -------------------------------------------------------------------------------- /obstaravania/notifications/README.md: -------------------------------------------------------------------------------- 1 | # Development 2 | ## Dependencies 3 | ### runtime 4 | * php 7+ 5 | 6 | ### libraries 7 | * TCPDF (https://tcpdf.org) 8 | * Smarty (smarty.net) 9 | 10 | ### Dev 11 | * Composer (https://getcomposer.org/) 12 | 13 | ## Building 14 | `composer install` 15 | 16 | # Usage / Testing 17 | ## Directly 18 | `php makepdf.php ` 19 | 20 | example: 21 | 22 | `php makepdf.php sample_data/three_new.json ../pdfsender/input/three_new.pdf` 23 | 24 | ## Return codes 25 | * `0` - PDF successfully created. 26 | * `1` - Error during PDF creation. 27 | * `2` - Temporary error during PDF creation. Try again later. 28 | 29 | # Directory structure 30 | * `[vendor]` *- directory for libraries installed by composer* 31 | * `[templates]` *- directory for smarty templates with resources* 32 | * `[cache]` *- cache for smarty* 33 | * `[compiled]` *- compiled smarty templates* 34 | * `[resources]` *- images, icons and other resources used in result* 35 | * `[sample_data]` *- sample json data* 36 | * `composer.json` *- composer project file description* 37 | * `makepdf.php` *- main app* 38 | * `pdftemplate.php` *- template library for PDF output* 39 | * `makepdf_single.sh` *- script to create PDF files using PHP app and then move result to right directories.* 40 | * `makepdf_dir.sh` *- script to create all files from specified directory, for cron.* 41 | -------------------------------------------------------------------------------- /client/src/components/Connections/components/InfoLoader.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import React, {Fragment} from 'react' 3 | import {compose} from 'redux' 4 | import {connect} from 'react-redux' 5 | import {withDataProviders} from 'data-provider' 6 | import {chunk} from 'lodash' 7 | import Info from '../../shared/Info/Info' 8 | import {entityDetailProvider} from '../../../dataProviders/sharedDataProviders' 9 | import {entityDetailsSelector} from '../../../selectors/index' 10 | import {MAX_ENTITY_REQUEST_COUNT} from '../../../constants' 11 | import type {NewEntityDetail} from '../../../state' 12 | import type {ObjectMap} from '../../../types/commonTypes' 13 | import './InfoLoader.css' 14 | 15 | type Props = { 16 | eids: number[], 17 | data: ObjectMap, 18 | } 19 | 20 | const InfoLoader = ({data, eids}: Props) => ( 21 | 22 | {eids.map((eid) => ( 23 |
    24 | 25 |
    26 |
    27 |
    28 |
    29 | ))} 30 | 31 | ) 32 | 33 | export default compose( 34 | withDataProviders(({eids}: Props) => 35 | chunk(eids, MAX_ENTITY_REQUEST_COUNT).map((ids) => entityDetailProvider(ids)) 36 | ), 37 | connect((state, {eids}) => ({ 38 | data: entityDetailsSelector(state, eids), 39 | })) 40 | )(InfoLoader) 41 | -------------------------------------------------------------------------------- /client/src/components/Notices/NoticeList.scss: -------------------------------------------------------------------------------- 1 | @import "../variables.scss"; 2 | 3 | .notice-list { 4 | hr { 5 | border-top-color: $border-color; 6 | width: 85%; 7 | @media screen and (max-width: 767px) { 8 | width: 90%; 9 | } 10 | @media screen and (max-width: 649px) { 11 | width: 95%; 12 | } 13 | @media screen and (max-width: 575px) { 14 | width: 100%; 15 | } 16 | } 17 | } 18 | 19 | .notice-input { 20 | margin-left: auto; 21 | margin-right: auto; 22 | width: 80%; 23 | @media screen and (min-width: 576px) { 24 | width: 60%; 25 | } 26 | @media screen and (min-width: 650px) { 27 | width: 50%; 28 | } 29 | @media screen and (min-width: 768px) { 30 | width: 35%; 31 | } 32 | } 33 | 34 | .notice-list-table { 35 | width: 85%; 36 | @media screen and (max-width: 767px) { 37 | width: 90%; 38 | } 39 | @media screen and (max-width: 649px) { 40 | width: 95%; 41 | } 42 | @media screen and (max-width: 575px) { 43 | width: 100%; 44 | } 45 | border: 10px; 46 | margin-left: auto; 47 | margin-right: auto; 48 | } 49 | 50 | .fbfooter { 51 | margin-top: 10px; 52 | margin-left: 10%; 53 | padding-left: 1rem; 54 | height: 50px; 55 | overflow: hidden; 56 | .fbIframe { 57 | border: none; 58 | overflow: hidden; 59 | margin-top: 0; 60 | } 61 | } 62 | 63 | .notice-search-result-text { 64 | text-align: center; 65 | } 66 | -------------------------------------------------------------------------------- /client/src/components/shared/Info/RecursiveInfo.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import React, {Fragment, type Node} from 'react' 3 | import {compose, withState, withHandlers} from 'recompose' 4 | import {Button} from 'reactstrap' 5 | import CompanyDetails from '../CompanyDetails' 6 | import CircleIcon from '../CircleIcon' 7 | import type {StateUpdater} from '../../../types/commonTypes' 8 | import type {RelatedEntity} from '../../../state' 9 | 10 | 11 | type RecursiveInfoProps = {| 12 | related: RelatedEntity, 13 | badge: Node, 14 | useNewApi: boolean, 15 | toggledOn: boolean, 16 | toggle: () => void, 17 | |} 18 | 19 | type StateProps = { 20 | toggledOn: boolean, 21 | toggle: StateUpdater, 22 | } 23 | 24 | const RecursiveInfo = ({related, badge, useNewApi, toggledOn, toggle}: RecursiveInfoProps) => 25 | toggledOn ? ( 26 | 27 | ) : ( 28 | 29 | {badge} 30 | 31 | 32 |   33 | 36 | 37 | 38 | ) 39 | 40 | export default compose( 41 | withState('toggledOn', 'toggle', false), 42 | withHandlers({ 43 | toggle: ({toggle}: StateProps) => () => toggle((current) => !current), 44 | }) 45 | )(RecursiveInfo) 46 | -------------------------------------------------------------------------------- /client/src/components/Notices/CompaniesTable.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import React from 'react' 3 | import {compose, branch, renderNothing} from 'recompose' 4 | import {Table} from 'reactstrap' 5 | import Company from './Company' 6 | 7 | import type {NoticeDetail} from '../../state' 8 | 9 | import './CompaniesTable.css' 10 | 11 | type Props = {| 12 | item: NoticeDetail, 13 | |} 14 | 15 | const _CompaniesTable = ({item}: Props) => ( 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 26 | 27 | 28 | 29 | {item.candidates_extra && item.candidates_extra.length > 0 ? ( 30 | item.candidates_extra.map((candidate, i) => ( 31 | 32 | )) 33 | ) : ( 34 | 35 | 38 | 39 | )} 40 | 41 |
    Kto by sa mal prihlásiťČo podobné vyhralObjednávateľCena € 24 | Pod. 25 |
    36 | Nenašli sa vyhovujúci kandidáti. 37 |
    42 | ) 43 | 44 | export default compose(branch((props) => props.item === null, renderNothing))(_CompaniesTable) 45 | -------------------------------------------------------------------------------- /obstaravania/pdfsender/libs/zelenaposta/SentApiConfig.php: -------------------------------------------------------------------------------- 1 | libs/zelenaposta/SentClassMap.php 5 | // for now, we don't use it, because resulted classes are not OK. Ex. class mailing. 6 | 7 | require ('vendor/autoload.php'); 8 | 9 | use Phpro\SoapClient\CodeGenerator\Config\Config; 10 | use Phpro\SoapClient\CodeGenerator\Rules; 11 | use Phpro\SoapClient\CodeGenerator\Assembler; 12 | 13 | $res = Config::create() 14 | ->setWsdl('https://gateway.zelenaposta.sk/api/2/sent?wsdl') 15 | ->setDestination('libs/zelenaposta/api2/sent') 16 | ->setNamespace('zelenaposta\api2\sent') 17 | ->addSoapOption('features', SOAP_SINGLE_ELEMENT_ARRAYS) 18 | ->addRule(new Rules\AssembleRule(new Assembler\GetterAssembler())) 19 | ->addRule(new Rules\AssembleRule(new Assembler\SetterAssembler())) 20 | ->addRule(new Rules\TypenameMatchesRule( 21 | new Rules\AssembleRule(new Assembler\RequestAssembler()), 22 | '/Request$/' 23 | )) 24 | ->addRule(new Rules\TypenameMatchesRule( 25 | new Rules\AssembleRule(new Assembler\ResultAssembler()), 26 | '/Response$/' 27 | )) 28 | ; 29 | 30 | return $res; -------------------------------------------------------------------------------- /obstaravania/pdfsender/libs/zelenaposta/UserApiConfig.php: -------------------------------------------------------------------------------- 1 | libs/zelenaposta/UserClassMap.php 5 | // for now, we don't use it, because resulted classes are not OK. Ex. class mailing. 6 | 7 | require ('vendor/autoload.php'); 8 | 9 | use Phpro\SoapClient\CodeGenerator\Config\Config; 10 | use Phpro\SoapClient\CodeGenerator\Rules; 11 | use Phpro\SoapClient\CodeGenerator\Assembler; 12 | 13 | $res = Config::create() 14 | ->setWsdl('https://gateway.zelenaposta.sk/api/2/user?wsdl') 15 | ->setDestination('libs/zelenaposta/api2/user') 16 | ->setNamespace('zelenaposta\api2\user') 17 | ->addSoapOption('features', SOAP_SINGLE_ELEMENT_ARRAYS) 18 | ->addRule(new Rules\AssembleRule(new Assembler\GetterAssembler())) 19 | ->addRule(new Rules\AssembleRule(new Assembler\SetterAssembler())) 20 | ->addRule(new Rules\TypenameMatchesRule( 21 | new Rules\AssembleRule(new Assembler\RequestAssembler()), 22 | '/Request$/' 23 | )) 24 | ->addRule(new Rules\TypenameMatchesRule( 25 | new Rules\AssembleRule(new Assembler\ResultAssembler()), 26 | '/Response$/' 27 | )) 28 | ; 29 | 30 | return $res; -------------------------------------------------------------------------------- /client/src/components/shared/ToggleBox.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import React, {type Node} from 'react' 3 | import {compose, withState, withHandlers} from 'recompose' 4 | import {Badge, Button} from 'reactstrap' 5 | import {FaChevronUp, FaChevronDown} from 'react-icons/fa' 6 | 7 | import type {StateUpdater} from '../../types/commonTypes' 8 | import './ToggleBox.css' 9 | 10 | type ToggleBoxProps = {| 11 | buttonText: string, 12 | expanded: boolean, 13 | children: Node, 14 | buttonInfo: string, 15 | toggle: () => void, 16 | |} 17 | 18 | type StateProps = { 19 | expanded: boolean, 20 | setExpanded: StateUpdater, 21 | } 22 | 23 | const ToggleBox = ({buttonText, expanded, children, buttonInfo, toggle}: ToggleBoxProps) => ( 24 |
    25 | 36 |
    {expanded && children}
    37 |
    38 | ) 39 | 40 | export default compose( 41 | withState('expanded', 'setExpanded', false), 42 | withHandlers({ 43 | toggle: ({setExpanded}: StateProps) => () => setExpanded((current) => !current), 44 | }) 45 | )(ToggleBox) 46 | -------------------------------------------------------------------------------- /data/prod_generation/regenerate_prod_data.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # script to regenerate production data from schemas gained from update_weekly.sh 4 | 5 | # set bash strict mode - fail immediately if anything fails 6 | set -eu 7 | IFS=$'\n\t' 8 | 9 | # Get to the script's directory: 10 | DIR=$(dirname $(readlink -f "$0")) 11 | cd "${DIR}" 12 | cd .. 13 | 14 | # create virtual environment (switched off for now - takes too long) 15 | # sh deploy.sh 16 | 17 | # activate virtual environment 18 | . venv/bin/activate 19 | 20 | # Set up a log file path: 21 | DATE=$(date +%Y_%m_%d_%H_%M_%S) 22 | LOG_PATH="/tmp/regenerate_prod_data_${DATE}.log" 23 | echo "Command to monitor logs:" 24 | echo "tail ${LOG_PATH};" 25 | 26 | # Regenerate prod data: 27 | started=$(date) 28 | echo "Generation started: ${started}" 29 | echo "sudo -u datautils python3 generate_prod_data.py --disable_test_mode > ${LOG_PATH} 2>&1;" 30 | sudo -u datautils python3 generate_prod_data.py --disable_test_mode > ${LOG_PATH} 2>&1 31 | finished=$(date) 32 | echo "Generation finished: ${finished}" 33 | 34 | # Restart apps: 35 | sudo svc -t /service/verejne_prod 36 | sudo svc -t /service/prepojenia_prod 37 | sudo svc -t /service/obstaravania_prod 38 | sudo svc -t /service/kataster_prod 39 | sudo svc -t /service/data 40 | echo "Issued commands to restart all apps." 41 | 42 | # Regenerate public dumps: 43 | echo "python3 generate_public_dumps.py" 44 | cd prod_generation 45 | sudo -u datautils python3 generate_public_dumps.py 46 | -------------------------------------------------------------------------------- /obstaravania/pdfsender/libs/zelenaposta/ProductApiConfig.php: -------------------------------------------------------------------------------- 1 | libs/zelenaposta/ProductClassMap.php 5 | // for now, we don't use it, because resulted classes are not OK. Ex. class mailing. 6 | 7 | require ('vendor/autoload.php'); 8 | 9 | use Phpro\SoapClient\CodeGenerator\Config\Config; 10 | use Phpro\SoapClient\CodeGenerator\Rules; 11 | use Phpro\SoapClient\CodeGenerator\Assembler; 12 | 13 | $res = Config::create() 14 | ->setWsdl('https://gateway.zelenaposta.sk/api/2/product?wsdl') 15 | ->setDestination('libs/zelenaposta/api2/product') 16 | ->setNamespace('zelenaposta\api2\product') 17 | ->addSoapOption('features', SOAP_SINGLE_ELEMENT_ARRAYS) 18 | ->addRule(new Rules\AssembleRule(new Assembler\GetterAssembler())) 19 | ->addRule(new Rules\AssembleRule(new Assembler\SetterAssembler())) 20 | ->addRule(new Rules\TypenameMatchesRule( 21 | new Rules\AssembleRule(new Assembler\RequestAssembler()), 22 | '/Request$/' 23 | )) 24 | ->addRule(new Rules\TypenameMatchesRule( 25 | new Rules\AssembleRule(new Assembler\ResultAssembler()), 26 | '/Response$/' 27 | )) 28 | ; 29 | 30 | return $res; -------------------------------------------------------------------------------- /client/src/components/Connections/dataWrappers/ConnectionWrapper.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import React from 'react' 3 | import {compose} from 'redux' 4 | import {connect} from 'react-redux' 5 | import {branch} from 'recompose' 6 | import {withDataProviders} from 'data-provider' 7 | import {isNil} from 'lodash' 8 | import {connectionDetailSelector} from '../../../selectors' 9 | import {connectionDetailProvider} from '../../../dataProviders/connectionsDataProviders' 10 | import type {ComponentType} from 'react' 11 | import type {EntityProps} from './EntityWrapper' 12 | import type {State} from '../../../state' 13 | 14 | export type ConnectionProps = { 15 | connections: Array, 16 | } 17 | 18 | const ConnectionWrapper = (WrappedComponent: ComponentType<*>) => { 19 | const wrapped = (props: ConnectionProps & EntityProps) => 20 | isNil(props.connections) && props.entity2.query.length > 0 ? null : ( 21 | 22 | ) 23 | 24 | return compose( 25 | branch( 26 | ({entity1, entity2}: EntityProps) => 27 | entity1.eids.length > 0 && entity2.query.length > 0 && entity2.eids.length > 0, 28 | withDataProviders((props: EntityProps) => [ 29 | connectionDetailProvider(props.entity1.eids, props.entity2.eids), 30 | ]) 31 | ), 32 | connect((state: State, props: EntityProps) => ({ 33 | connections: connectionDetailSelector(state, props.entity1.eids, props.entity2.eids), 34 | })) 35 | )(wrapped) 36 | } 37 | 38 | export default ConnectionWrapper 39 | -------------------------------------------------------------------------------- /client/src/components/Profile/components/PoliticiansListWrapper.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import React from 'react' 3 | import {compose} from 'redux' 4 | import {connect} from 'react-redux' 5 | import {withRouter} from 'react-router-dom' 6 | import {withDataProviders} from 'data-provider' 7 | import type {ComponentType} from 'react' 8 | import {politiciansProvider} from '../../../dataProviders/profileDataProviders' 9 | import { 10 | filteredPoliticiansSelector, 11 | politicianGroupSelector, 12 | politicianSortingOptionSelector, 13 | } from '../../../selectors/profileSelectors' 14 | 15 | import type {ContextRouter} from 'react-router' 16 | import type {State, Politician} from '../../../state' 17 | 18 | export type PoliticiansListProps = { 19 | politicians: Array, 20 | politicianGroup: string, 21 | } 22 | 23 | const PoliticiansListWrapper = (WrappedComponent: ComponentType) => { 24 | const wrapped = (props: PoliticiansListProps) => 25 | 26 | return compose( 27 | withRouter, 28 | connect((state: State, props: ContextRouter) => ({ 29 | politicianGroup: politicianGroupSelector(state, props), 30 | politicians: filteredPoliticiansSelector(state, props), 31 | sortState: politicianSortingOptionSelector(state, props), 32 | })), 33 | withDataProviders(({politicianGroup}: PoliticiansListProps) => [ 34 | politiciansProvider(politicianGroup), 35 | ]) 36 | )(wrapped) 37 | } 38 | 39 | export default PoliticiansListWrapper 40 | -------------------------------------------------------------------------------- /obstaravania/pdfsender/README.md: -------------------------------------------------------------------------------- 1 | # Development 2 | ## Dependencies 3 | ### runtime 4 | * php 7+ 5 | * php extensions: soap, curl, dom, json 6 | 7 | ### libraries 8 | * soap-client (https://github.com/phpro/soap-client) 9 | * guzzlehttp/guzzle (http://docs.guzzlephp.org/en/stable/) 10 | * http-factory-guzzle (https://github.com/http-interop/http-factory-guzzle) 11 | * nategood/commando (https://github.com/nategood/commando) 12 | 13 | ### Dev 14 | * zend-code (https://docs.zendframework.com/zend-code/) 15 | * *not needed for now* 16 | 17 | ## Building 18 | `composer install` 19 | 20 | # Usage / Testing 21 | ## Directly 22 | `php sendpdf.php -u -p ` 23 | 24 | example: 25 | 26 | `php sendpdf.php -u verejne -p digital input/four_new.json input/four_new.pdf` 27 | 28 | see also `php sendpdf.php --help` 29 | 30 | ## Return codes 31 | * `0` - PDF successfully created. 32 | * `1` - Error during PDF creation. 33 | * `2` - Temporary error during PDF creation. Try again later. 34 | 35 | # Directory structure 36 | * `[vendor]` *- directory for libraries installed by composer* 37 | * `[libs]` *- directory with custom libraries* 38 | * `[zelenaposta]` *- libraries for integration with Zelena Pošta* 39 | * `composer.json` *- composer project file description* 40 | * `sendpdf.php` *- main app* 41 | * `send_single.sh` *- script to send files using PHP app and then move result to right directories.* 42 | * `send_dir.sh` *- script to send all files from specified directory, for cron.* 43 | -------------------------------------------------------------------------------- /client/src/assets/mapIcon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | icons 2 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /client/src/components/Connections/components/graph/gestures.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import type {Point} from './utils' 3 | 4 | const GESTURE_INTERVAL = 3000 // milis 5 | const STROKES_TO_SHAKE = 5 6 | const MIN_STROKE_LENGTH = 20 // px 7 | 8 | let shakes = 0 9 | let lastX = null 10 | let lastY = null 11 | let firstXInDir = 0 12 | let lastDir = null 13 | let gestureTimeout = null 14 | 15 | export const resetGesture = () => { 16 | gestureTimeout && clearTimeout(gestureTimeout) 17 | gestureTimeout = null 18 | lastX = lastY = null 19 | lastDir = null 20 | shakes = 0 21 | } 22 | 23 | export const checkShaking = ({x, y}: Point) => { 24 | if (lastX == null || lastY == null || lastX === x) { 25 | // start gesture 26 | lastX = firstXInDir = x 27 | lastY = y 28 | gestureTimeout = setTimeout(() => { 29 | resetGesture() // gesture must be finished before GESTURE_INTERVAL ends 30 | }, GESTURE_INTERVAL) 31 | return false 32 | } 33 | const dir = x - lastX > 0 ? 1 : -1 34 | if (dir !== lastDir && Math.abs(y - lastY) < 2 * MIN_STROKE_LENGTH) { 35 | // if x direction changed, while y movement is small enough: 36 | if (Math.abs(x - firstXInDir) > MIN_STROKE_LENGTH) { 37 | // if x movement is big enough, consider this a 'shake' stroke 38 | shakes++ 39 | } 40 | lastDir = dir 41 | firstXInDir = x 42 | } 43 | lastX = x 44 | if (shakes >= STROKES_TO_SHAKE) { 45 | // if enough shakes, consider this a shaking gesture 46 | resetGesture() 47 | return true 48 | } 49 | return false 50 | } 51 | -------------------------------------------------------------------------------- /client/src/components/Profile/components/DetailCadastralLV.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import React, {Component} from 'react' 3 | import ExternalLink from '../../shared/ExternalLink' 4 | 5 | import './DetailCadastralLV.css' 6 | 7 | import type {CadastralData} from '../../../state' 8 | 9 | type DetailCadastralLVProps = { 10 | lv: CadastralData, 11 | num: number, 12 | onParcelShow: () => void, 13 | } 14 | 15 | class DetailCadastralLV extends Component { 16 | disablePropagation = (event: Event) => { 17 | event.stopPropagation() 18 | } 19 | 20 | render() { 21 | return ( 22 | 26 | {this.props.num < 10 ? `0${this.props.num}` : this.props.num} 27 | 28 | 34 | {this.props.lv.landusename || 'List Vlastníctva'} 35 | 36 |
    37 | {`${this.props.lv.cadastralunitname}, LV č. ${this.props.lv.foliono}${ 38 | this.props.lv.parcelno ? `; parcely: ${this.props.lv.parcelno}` : '' 39 | }`} 40 | 41 | 42 | ) 43 | } 44 | } 45 | 46 | export default DetailCadastralLV 47 | -------------------------------------------------------------------------------- /client/src/components/Profile/Profile.scss: -------------------------------------------------------------------------------- 1 | @import "../variables.scss"; 2 | 3 | .profile-header { 4 | padding: 20px; 5 | padding-top: $navbar-height + 20; 6 | margin-bottom: 0; 7 | text-align: center; 8 | 9 | .sub-title { 10 | margin: auto; 11 | color: grey; 12 | font-weight: 300; 13 | line-height: 1.65rem; 14 | margin-bottom: 10px; 15 | } 16 | 17 | h1.title { 18 | margin: auto; 19 | padding-top: 0; 20 | padding-bottom: 15px; 21 | text-align: center; 22 | margin-top: 20px; 23 | margin-bottom: 0; 24 | line-height: 20px; 25 | height: 50px; 26 | } 27 | 28 | .bolder { 29 | font-weight: bolder; 30 | } 31 | } 32 | 33 | .profile-search { 34 | margin-bottom: 20px; 35 | margin-top: 20px; 36 | max-width: 350px; 37 | margin-left: auto; 38 | margin-right: auto; 39 | 40 | .search-form { 41 | .search-input { 42 | background: $component-background; 43 | border-radius: 2px; 44 | border-width: 2px; 45 | border-color: $border-color; 46 | border-style: solid; 47 | height: 34px; 48 | width: 100%; 49 | color: $search-color; 50 | 51 | &:placeholder { 52 | color: $search-color; 53 | } 54 | 55 | &:focus { 56 | box-shadow: 57 | inset 0 1px 1px $input-inset-shadow-color, 58 | 0 0 8px $input-shadow-color; 59 | } 60 | } 61 | } 62 | } 63 | 64 | .profile-fbframe { 65 | text-align: left; 66 | padding-right: 0; 67 | margin-right: 0; 68 | } 69 | 70 | .profile { 71 | text-align: center; 72 | } 73 | 74 | .profile-group-button { 75 | border-radius: 0px; 76 | background-color: white; 77 | } 78 | -------------------------------------------------------------------------------- /client/src/index.js: -------------------------------------------------------------------------------- 1 | // polyfills 2 | import 'regenerator-runtime/runtime' 3 | import 'whatwg-fetch' 4 | import 'react-app-polyfill/ie9' // For IE 9-11 support 5 | import Promise from 'bluebird' 6 | import smoothscroll from 'smoothscroll-polyfill' 7 | 8 | import React from 'react' 9 | import ReactDOM from 'react-dom' 10 | import PropTypes from 'prop-types' 11 | import {BrowserRouter} from 'react-router-dom' 12 | import {dataProvidersConfig} from 'data-provider' 13 | import './customBootstrap.css' 14 | import App from './components/App' 15 | import Loading from './components/Loading/Loading' 16 | import {GoogleAnalyticsInitializer} from './utils' 17 | import getConfiguredStore from './configureStore' 18 | import {Provider} from 'react-redux' 19 | 20 | window.Promise = Promise 21 | smoothscroll.polyfill() 22 | 23 | dataProvidersConfig({loadingComponent: }) 24 | 25 | // a short-term fix for data-provider, should get fixed in next release 26 | class DispatchProvider extends React.Component { 27 | static childContextTypes = { 28 | dispatch: PropTypes.func, 29 | } 30 | 31 | getChildContext() { 32 | return {dispatch: this.props.dispatch} 33 | } 34 | 35 | render() { 36 | return this.props.children 37 | } 38 | } 39 | 40 | const store = getConfiguredStore() 41 | ReactDOM.render( 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | , 51 | document.getElementById('root') 52 | ) 53 | -------------------------------------------------------------------------------- /client/src/components/shared/utilities.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | import type {Ties} from './CircleIcon' 4 | 5 | export const showRelationType = ( 6 | typeId: number, 7 | typeText: string, 8 | typeDate: string, 9 | arrow: boolean 10 | ) => 11 | typeId == null 12 | ? 'Neznáme' 13 | : `${typeText || 'Neznáme'}${typeDate ? ' do '.concat(typeDate) : ''}${ 14 | arrow ? (typeId > 0 ? ' >' : ' <') : '' 15 | }` 16 | 17 | export const getRelationTitle = ( 18 | typeId: number, 19 | name1: string, 20 | name2: string, 21 | typeDate: string, 22 | symmetric: boolean 23 | ) => 24 | typeId != null 25 | ? symmetric 26 | ? typeDate === '' 27 | ? `${name1} a ${name2} majú tento vzťah` 28 | : `${name1} a ${name2} mali tento vzťah do ${typeDate}` 29 | : typeDate === '' 30 | ? typeId > 0 31 | ? `${name1} zastupuje túto funkciu pre ${name2}` 32 | : `${name2} zastupuje túto funkciu pre ${name1}` 33 | : typeId > 0 34 | ? `${name1} zastupoval/a túto funkciu pre ${name2} do ${typeDate}` 35 | : `${name2} zastupoval/a túto funkciu pre ${name1} do ${typeDate}` 36 | : 'Spojenie neznáme' 37 | 38 | export const getColor = (type: number, date: string) => 39 | date === '' ? (type >= 0 ? 'primary' : 'dark') : 'secondary' 40 | 41 | export const getCircleIconTitle = (data: Ties) => { 42 | return data.political_entity 43 | ? 'Politik' 44 | : data.trade_with_government && data.contact_with_politics 45 | ? 'Kontakt s politikou a obchod so štátom' 46 | : data.trade_with_government 47 | ? 'Obchod so štátom' 48 | : data.contact_with_politics 49 | ? 'Kontakt s politikou' 50 | : 'Firma / osoba' 51 | } 52 | -------------------------------------------------------------------------------- /client/src/components/shared/Info/InfoButton.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import React from 'react' 3 | import {compose, withState, withHandlers} from 'recompose' 4 | import {FaChevronUp, FaChevronDown} from 'react-icons/fa' 5 | import {Badge, Button} from 'reactstrap' 6 | import type {Node} from 'react' 7 | 8 | import {ShowNumberCurrency} from '../../../services/utilities' 9 | import type {Contract, NoticeNew, Eufund} from '../../../state' 10 | import type {StateUpdater} from '../../../types/commonTypes' 11 | 12 | import './InfoButton.css' 13 | 14 | type InfoButtonProps = {| 15 | label: string, 16 | count: number, 17 | priceSum: number, 18 | list: Array, 19 | buildItem: (T, number, Array) => Node, 20 | toggledOn: boolean, 21 | toggle: () => void, 22 | |} 23 | type StateProps = { 24 | toggledOn: boolean, 25 | toggle: StateUpdater, 26 | } 27 | 28 | const InfoButton = ({ 29 | label, 30 | count, 31 | priceSum, 32 | list, 33 | buildItem, 34 | toggledOn, 35 | toggle, 36 | }: InfoButtonProps) => ( 37 |
    38 | 45 | {toggledOn &&
      {list.map(buildItem)}
    } 46 |
    47 | ) 48 | 49 | export default compose( 50 | withState('toggledOn', 'toggle', false), 51 | withHandlers({ 52 | toggle: ({toggle}: StateProps) => () => toggle((current: boolean) => !current), 53 | }) 54 | )(InfoButton) 55 | -------------------------------------------------------------------------------- /client/flow-typed/npm/qs_v6.5.x.js: -------------------------------------------------------------------------------- 1 | // flow-typed signature: 715c2f8b80fc0049acaff07253098596 2 | // flow-typed version: a7cda84c32/qs_v6.5.x/flow_>=v0.45.x 3 | 4 | declare module "qs" { 5 | declare type ParseOptions = { 6 | allowPrototypes?: boolean, 7 | arrayLimit?: number, 8 | decoder?: Function, 9 | delimiter?: string, 10 | depth?: number, 11 | parameterLimit?: number, 12 | plainObjects?: boolean, 13 | strictNullHandling?: boolean, 14 | ignoreQueryPrefix?: boolean, 15 | parseArrays?: boolean, 16 | allowDots?: boolean 17 | }; 18 | 19 | declare type ArrayFormat = "brackets" | "indices" | "repeat"; 20 | 21 | declare type FilterFunction = (prefix: string, value: any) => any; 22 | declare type FilterArray = Array; 23 | declare type Filter = FilterArray | FilterFunction; 24 | 25 | declare type StringifyOptions = { 26 | encoder?: Function, 27 | delimiter?: string, 28 | strictNullHandling?: boolean, 29 | skipNulls?: boolean, 30 | encode?: boolean, 31 | sort?: Function, 32 | allowDots?: boolean, 33 | serializeDate?: Function, 34 | encodeValuesOnly?: boolean, 35 | format?: string, 36 | addQueryPrefix?: boolean, 37 | arrayFormat?: ArrayFormat, 38 | filter?: Filter 39 | }; 40 | 41 | declare type Formatter = (any) => string; 42 | 43 | declare type Formats = { 44 | RFC1738: string, 45 | RFC3986: string, 46 | "default": string, 47 | formatters: { 48 | RFC1738: Formatter, 49 | RFC3986: Formatter 50 | } 51 | }; 52 | 53 | declare module.exports: { 54 | parse(str: string, opts?: ParseOptions): Object, 55 | stringify(obj: Object | Array, opts?: StringifyOptions): string, 56 | formats: Formats 57 | }; 58 | } 59 | -------------------------------------------------------------------------------- /client/src/components/Public/EntitySearch/EntitySearch.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import React from 'react' 3 | import {connect} from 'react-redux' 4 | import {compose} from 'recompose' 5 | import EntitySearchResult from '../EntitySearchResult/EntitySearchResult' 6 | import { 7 | entitySearchEidsSelector, 8 | entitySearchForSelector, 9 | entitySearchLoadedSelector, 10 | } from '../../../selectors' 11 | import {toggleEntitySearchOpen} from '../../../actions/publicActions' 12 | import {resultPlurality} from '../../../services/utilities' 13 | import './EntitySearch.css' 14 | 15 | import type {State} from '../../../state' 16 | 17 | type EntitySearchProps = { 18 | toggleEntitySearchOpen: () => Object, 19 | entitySearchEids: Array, 20 | entitySearchFor: string, 21 | entitySearchLoaded: boolean, 22 | } 23 | 24 | const EntitySearch = ({ 25 | toggleEntitySearchOpen, 26 | entitySearchEids, 27 | entitySearchFor, 28 | entitySearchLoaded, 29 | }: EntitySearchProps) => ( 30 |
    31 | {entitySearchLoaded && ( 32 |
    33 | 36 | {`${resultPlurality(entitySearchEids.length)} pre "${entitySearchFor}".`} 37 |
    38 | )} 39 |
    40 | 41 |
    42 |
    43 | ) 44 | 45 | export default compose( 46 | connect( 47 | (state: State) => ({ 48 | entitySearchEids: entitySearchEidsSelector(state), 49 | entitySearchFor: entitySearchForSelector(state), 50 | entitySearchLoaded: entitySearchLoadedSelector(state), 51 | }), 52 | {toggleEntitySearchOpen} 53 | ) 54 | )(EntitySearch) 55 | -------------------------------------------------------------------------------- /client/src/components/shared/Info/Info.scss: -------------------------------------------------------------------------------- 1 | @import '../../variables.scss'; 2 | 3 | .info { 4 | background-color: $component-background; 5 | margin-bottom: 0; 6 | padding: 0; 7 | border-radius: 4px; 8 | border: 2px solid $border-color; 9 | box-shadow: 0 4px 12px 0 $shadow-color; 10 | position: relative; 11 | 12 | &.active { 13 | box-shadow: 0 4px 12px 0 rgba(117, 127, 134, .75); 14 | border-color: $blue-color; 15 | } 16 | 17 | &.index { 18 | top: 15px; 19 | } 20 | 21 | .info-header { 22 | padding: .5rem .75rem .4rem .75rem; 23 | border-bottom: 1px solid $border-color; 24 | position: relative; 25 | 26 | h3 { 27 | color: $marker-border; 28 | margin-bottom: 0; 29 | font-size: 1rem; 30 | line-height: 1rem; 31 | display: inline-flex; 32 | align-items: center; 33 | 34 | &.politician { 35 | color: $orange-color; 36 | } 37 | } 38 | 39 | .blue { 40 | color: $blue-color 41 | } 42 | } 43 | 44 | &.closable .info-header > h3 { 45 | cursor: pointer; 46 | } 47 | } 48 | 49 | .info-index { 50 | position: absolute; 51 | top: -10px; 52 | right: -10px; 53 | background-color: #fff; 54 | color: #0062db; 55 | border: 2px solid #0062db; 56 | padding: 4px; 57 | width: 30px; 58 | height: 30px; 59 | border-radius: 30px; 60 | display: flex; 61 | justify-content: center; 62 | align-items: center; 63 | } 64 | 65 | .info-main { 66 | padding: .5rem .75rem; 67 | } 68 | 69 | .info-close-button { 70 | position: absolute; 71 | right: .5rem; 72 | top: .5rem; 73 | cursor: pointer; 74 | } 75 | 76 | .info-list { 77 | list-style: none; 78 | padding: 0; 79 | margin: 0; 80 | } 81 | 82 | .info-badges { 83 | font-size: 1rem; 84 | 85 | & > * + * { 86 | margin-left: .5em; 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /data/prod_generation/generate_public_dumps.py: -------------------------------------------------------------------------------- 1 | """Script to generate public data dump files from latest prod data. 2 | This script should be invoked whenever new prod data is generated. 3 | Configuration (dumps to create, and where to save them) is stored in 4 | public_dumps.yaml. 5 | """ 6 | 7 | import os 8 | import shutil 9 | import sys 10 | 11 | sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '../db'))) 12 | from db import DatabaseConnection 13 | 14 | from utils import yaml_load 15 | 16 | 17 | def main(): 18 | """Generates public data dump files from the latest prod data.""" 19 | 20 | # Connect to the latest schemas. 21 | db = DatabaseConnection(path_config='db_config.yaml') 22 | schema = db.get_latest_schema('prod_') 23 | schema_profil = db.get_latest_schema('source_internal_profil_') 24 | db.execute('SET search_path="' + schema + '", "' + schema_profil + '";') 25 | timestamp = schema[schema.rfind('_') + 1:] 26 | print('[OK] Dumping from schemas "%s" and "%s"...' % (schema, schema_profil)) 27 | 28 | # Read YAML configuration file. 29 | config = yaml_load('public_dumps.yaml') 30 | dir_save = config['save_directory'] 31 | dumps = config['dumps'] 32 | 33 | # Process all dumps. 34 | for dump_name in dumps: 35 | save_path = os.path.join(dir_save, '%s_%s.csv' % (dump_name, timestamp)) 36 | db.dump_to_CSV(dumps[dump_name]['query'], save_path) 37 | print('[OK] Saved dump "%s" to %s' % (dump_name, save_path)) 38 | 39 | stage_path = os.path.join(dir_save, dump_name + '.csv') 40 | shutil.copyfile(save_path, stage_path) 41 | print('[OK] Copied dump "%s" to %s' % (dump_name, stage_path)) 42 | 43 | # Close database connection. 44 | db.close() 45 | 46 | 47 | if __name__ == '__main__': 48 | main() 49 | -------------------------------------------------------------------------------- /client/src/components/Profile/components/MapContainer.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import React, {Component} from 'react' 3 | import GoogleMapReact from 'google-map-react' 4 | import { 5 | COUNTRY_ZOOM, 6 | SLOVAKIA_COORDS, 7 | createMapOptions, 8 | GOOGLE_MAP_CONFIG, 9 | } from '../../../constants' 10 | 11 | import type {CadastralData, GeolocationPoint} from '../../../state' 12 | 13 | import './MapContainer.css' 14 | 15 | const Marker = ({title, label, onClick}) => ( 16 |
    17 | {label} 18 |
    19 | ) 20 | 21 | type MapContainerProps = { 22 | assets: Array, 23 | center: GeolocationPoint, 24 | zoom: number, 25 | } 26 | 27 | // TODO fix flow 28 | class MapContainer extends Component { 29 | render() { 30 | return ( 31 |
    32 | 40 | {this.props.assets.map((asset, key) => { 41 | return asset.lat ? ( 42 | this.props.markerAction(asset.eid) : undefined 48 | } 49 | lat={asset.lat} 50 | lng={asset.lon || asset.lng} 51 | /> 52 | ) : null 53 | })} 54 | 55 |
    56 | ) 57 | } 58 | } 59 | 60 | export default MapContainer 61 | -------------------------------------------------------------------------------- /client/src/components/App.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import React from 'react' 3 | import Navigation from './Navigation' 4 | import {Route} from 'react-router-dom' 5 | import {Switch} from 'react-router' 6 | import Public from './Public/Public' 7 | import Connections from './Connections/Connections' 8 | import NoticeList from './Notices/NoticeList' 9 | import NoticeDetail from './Notices/NoticeDetail' 10 | import Profile from './Profile/Profile' 11 | import DetailPage from './Profile/DetailPage' 12 | import Search from './Search/Search' 13 | import Playground from './Playground/Playground' 14 | import Landing from './Landing/Landing' 15 | 16 | import withTracker from './shared/withTracker' 17 | 18 | import './App.css' 19 | 20 | const MainApp = () => ( 21 |
    22 | 23 | 24 | {/* has tracking inside Map because of componentDidUpdate infinite loop */} 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 |
    34 | ) 35 | 36 | const App = () => ( 37 |
    38 | 39 | 40 | 41 | 42 | 43 | 44 |
    45 | ) 46 | 47 | export default App 48 | -------------------------------------------------------------------------------- /client/flow-typed/npm/redux-thunk_vx.x.x.js: -------------------------------------------------------------------------------- 1 | // flow-typed signature: 11afcacf02ad9c0abe8497e170adf731 2 | // flow-typed version: <>/redux-thunk_v^2.2.0/flow_v0.71.0 3 | 4 | /** 5 | * This is an autogenerated libdef stub for: 6 | * 7 | * 'redux-thunk' 8 | * 9 | * Fill this stub out by replacing all the `any` types. 10 | * 11 | * Once filled out, we encourage you to share your work with the 12 | * community by sending a pull request to: 13 | * https://github.com/flowtype/flow-typed 14 | */ 15 | 16 | declare module 'redux-thunk' { 17 | declare module.exports: any 18 | } 19 | 20 | /** 21 | * We include stubs for each file inside this npm package in case you need to 22 | * require those files directly. Feel free to delete any files that aren't 23 | * needed. 24 | */ 25 | declare module 'redux-thunk/dist/redux-thunk' { 26 | declare module.exports: any 27 | } 28 | 29 | declare module 'redux-thunk/dist/redux-thunk.min' { 30 | declare module.exports: any 31 | } 32 | 33 | declare module 'redux-thunk/es/index' { 34 | declare module.exports: any 35 | } 36 | 37 | declare module 'redux-thunk/lib/index' { 38 | declare module.exports: any 39 | } 40 | 41 | declare module 'redux-thunk/src/index' { 42 | declare module.exports: any 43 | } 44 | 45 | // Filename aliases 46 | declare module 'redux-thunk/dist/redux-thunk.js' { 47 | declare module.exports: $Exports<'redux-thunk/dist/redux-thunk'> 48 | } 49 | declare module 'redux-thunk/dist/redux-thunk.min.js' { 50 | declare module.exports: $Exports<'redux-thunk/dist/redux-thunk.min'> 51 | } 52 | declare module 'redux-thunk/es/index.js' { 53 | declare module.exports: $Exports<'redux-thunk/es/index'> 54 | } 55 | declare module 'redux-thunk/lib/index.js' { 56 | declare module.exports: $Exports<'redux-thunk/lib/index'> 57 | } 58 | declare module 'redux-thunk/src/index.js' { 59 | declare module.exports: $Exports<'redux-thunk/src/index'> 60 | } 61 | -------------------------------------------------------------------------------- /obstaravania/stop_words.txt: -------------------------------------------------------------------------------- 1 | a 2 | aby 3 | aj 4 | ak 5 | ako 6 | ale 7 | alebo 8 | and 9 | ani 10 | áno 11 | asi 12 | až 13 | bez 14 | bude 15 | budem 16 | budeš 17 | budeme 18 | budete 19 | budú 20 | by 21 | bol 22 | bola 23 | boli 24 | bolo 25 | byť 26 | cez 27 | čo 28 | či 29 | ďalší 30 | ďalšia 31 | ďalšie 32 | dnes 33 | do 34 | ho 35 | ešte 36 | for 37 | i 38 | ja 39 | je 40 | jeho 41 | jej 42 | ich 43 | iba 44 | iné 45 | iný 46 | som 47 | si 48 | sme 49 | sú 50 | k 51 | kam 52 | každý 53 | každá 54 | každé 55 | každí 56 | kde 57 | keď 58 | kto 59 | ktorá 60 | ktoré 61 | ktorou 62 | ktorý 63 | ktorí 64 | ku 65 | lebo 66 | len 67 | ma 68 | mať 69 | má 70 | máte 71 | medzi 72 | mi 73 | mna 74 | mne 75 | mnou 76 | musieť 77 | môcť 78 | môj 79 | môže 80 | my 81 | na 82 | nad 83 | nám 84 | náš 85 | naši 86 | nie 87 | nech 88 | než 89 | nič 90 | niektorý 91 | nové 92 | nový 93 | nová 94 | nové 95 | noví 96 | o 97 | od 98 | odo 99 | of 100 | on 101 | ona 102 | ono 103 | oni 104 | ony 105 | po 106 | pod 107 | podľa 108 | pokiaľ 109 | potom 110 | práve 111 | pre 112 | prečo 113 | preto 114 | pretože 115 | prvý 116 | prvá 117 | prvé 118 | prví 119 | pred 120 | predo 121 | pri 122 | pýta 123 | s 124 | sa 125 | so 126 | si 127 | svoje 128 | svoj 129 | svojich 130 | svojím 131 | svojími 132 | ta 133 | tak 134 | takže 135 | táto 136 | teda 137 | te 138 | tě 139 | ten 140 | tento 141 | the 142 | tieto 143 | tým 144 | týmto 145 | tiež 146 | to 147 | toto 148 | toho 149 | tohoto 150 | tom 151 | tomto 152 | tomuto 153 | toto 154 | tu 155 | tú 156 | túto 157 | tvoj 158 | ty 159 | tvojími 160 | už 161 | v 162 | vám 163 | váš 164 | vaše 165 | vo 166 | viac 167 | však 168 | všetok 169 | vy 170 | z 171 | za 172 | zo 173 | že 174 | -------------------------------------------------------------------------------- /data/kamidueurofondy.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | 3 | from utils import json_load, json_dump_utf8 4 | 5 | 6 | def load_results(path_load): 7 | j = json_load(path_load) 8 | 9 | # TEMP 10 | # return j['results'] 11 | 12 | count = j['count'] 13 | assert j['next'] is None 14 | results = j['results'] 15 | assert len(results) == count 16 | print('[OK] Loaded %d results from %s' % (count, path_load)) 17 | return results 18 | 19 | 20 | def flatten_dict(d, prefix=''): 21 | """ Recursively flattens nested dictionaries. 22 | Warning: Eliminates any lists! 23 | """ 24 | result = {} 25 | for key in d: 26 | if isinstance(d[key], str): 27 | result[prefix + key] = d[key] 28 | elif isinstance(d[key], dict): 29 | prefix = key + '_' 30 | subdict_flattened = flatten_dict(d[key], prefix=prefix) 31 | result.update(subdict_flattened) 32 | return result 33 | 34 | 35 | def main(args_dict): 36 | path_load = args_dict['path_load'] 37 | path_save = args_dict['path_save'] 38 | # verbose = args_dict['verbose'] 39 | 40 | results = load_results(path_load) 41 | results = list(map(flatten_dict, results)) 42 | json_dump_utf8(results, path_save) 43 | print('[OK] Saved flattened results to %s' % path_save) 44 | 45 | 46 | if __name__ == '__main__': 47 | parser = argparse.ArgumentParser() 48 | parser.add_argument('path_load', type=str, help='path to raw downloaded JSON file') 49 | parser.add_argument('path_save', type=str, help='path where to save flattened JSON') 50 | parser.add_argument('--verbose', default=0, type=int, help='Verbosity level') 51 | args_dict = vars(parser.parse_args()) 52 | try: 53 | main(args_dict) 54 | except: 55 | import pdb 56 | import sys 57 | import traceback 58 | 59 | _, _, tb = sys.exc_info() 60 | traceback.print_exc() 61 | pdb.post_mortem(tb) 62 | raise 63 | -------------------------------------------------------------------------------- /client/src/components/Profile/components/DetailAssets.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import React from 'react' 3 | import './DetailAssets.css' 4 | import {Table} from 'reactstrap' 5 | import ExternalLink from '../../shared/ExternalLink' 6 | import {branch, compose, withState} from 'recompose' 7 | import {withDataProviders} from 'data-provider/dist/withDataProviders' 8 | import {imageSrcProvider} from '../../../dataProviders/profileDataProviders' 9 | 10 | export type DetailAssetProps = { 11 | assets: Array, 12 | year: string, 13 | title: string, 14 | preloadedImageSrc: string, 15 | source: string, 16 | } 17 | 18 | const DetailAssetDeclaration = ({ 19 | assets, 20 | year, 21 | title, 22 | preloadedImageSrc, 23 | source, 24 | }: DetailAssetProps) => ( 25 | 26 | 27 | 28 | 35 | 36 | 37 | 38 | {assets.map((asset, key) => ( 39 | 40 | 41 | 42 | 43 | ))} 44 | 45 | {preloadedImageSrc && ( 46 | 47 | 48 | 51 | 52 | 53 | )} 54 |
    29 | 30 | {title} ({assets.length})
    31 | zdroj 32 | NRSR 33 | {year !== 0 ? `rok ${year}` : ''} 34 |
    {key < 9 ? `0${key + 1}` : key + 1}{asset}
    49 | majetok 50 |
    55 | ) 56 | 57 | export default compose( 58 | withState('preloadedImageSrc', 'setPreloadedImageSrc', undefined), 59 | branch( 60 | ({image}) => !!image, 61 | withDataProviders(({image, setPreloadedImageSrc, cachebreak}) => [ 62 | imageSrcProvider(image, setPreloadedImageSrc, cachebreak), 63 | ]) 64 | ) 65 | )(DetailAssetDeclaration) 66 | -------------------------------------------------------------------------------- /client/src/components/Landing/Landing.scss: -------------------------------------------------------------------------------- 1 | @import "../variables.scss"; 2 | 3 | .landing { 4 | height: calc(100vh); 5 | display: flex; 6 | flex-direction: column; 7 | } 8 | 9 | .landing-container { 10 | margin-top: auto; 11 | margin-bottom: auto; 12 | max-width: 1300px; 13 | } 14 | 15 | .landing-head { 16 | display: flex; 17 | justify-content: space-between; 18 | align-items: flex-start; 19 | margin-top: 16px; 20 | } 21 | 22 | .landing-search { 23 | max-width: 400px; 24 | min-width: 300px; 25 | } 26 | 27 | .landing-search-input { 28 | min-width: 250px; 29 | 30 | &:focus { 31 | box-shadow: none; 32 | box-shadow: 0 4px 12px 0 $shadow-color; 33 | } 34 | } 35 | 36 | .landing-title { 37 | font-family: Source Code Pro, monospace; 38 | font-size: 1.1rem; 39 | font-weight: normal; 40 | } 41 | 42 | .landing-lead { 43 | font-family: Source Code Pro, monospace; 44 | font-size: 1.1rem; 45 | } 46 | 47 | .landing-cards { 48 | padding: 1rem 0; // Fix, without it the row will crop shadows on cards. 49 | display: flex; 50 | align-items: stretch; 51 | flex-wrap: wrap; 52 | justify-content: space-between; 53 | margin-top: 60px; 54 | 55 | > * { 56 | margin-bottom: 2rem; 57 | justify-content: space-between; 58 | height: auto; 59 | width: 19%; 60 | } 61 | 62 | @media screen and (max-width: 941px) { 63 | > * { 64 | flex-basis: 48%; 65 | } 66 | } 67 | 68 | @media screen and (max-width: 767px) { 69 | > * { 70 | flex-basis: 100%; 71 | } 72 | } 73 | } 74 | 75 | .landing-footer { 76 | background: $footer-background; 77 | height: auto; 78 | width: 100%; 79 | margin-top: 50px; 80 | 81 | .list-inline-item-text ~ .list-inline-item-text { 82 | border-left: 2px solid $card-border; 83 | padding-left: 0.5rem; 84 | } 85 | } 86 | 87 | .partners { 88 | &.list-inline-item:not(:last-child) { 89 | margin-right: 1.5rem; 90 | @media screen and (max-width: 767px) { 91 | margin-right: 0 !important; 92 | } 93 | } 94 | } 95 | 96 | .gray { 97 | color: rgb(165, 165, 165); 98 | } 99 | -------------------------------------------------------------------------------- /client/flow-typed/npm/redux-logger_vx.x.x.js: -------------------------------------------------------------------------------- 1 | // flow-typed signature: 731f00fd4ac956e9e6f13a8e0417cb9c 2 | // flow-typed version: <>/redux-logger_v^3.0.6/flow_v0.71.0 3 | 4 | /** 5 | * This is an autogenerated libdef stub for: 6 | * 7 | * 'redux-logger' 8 | * 9 | * Fill this stub out by replacing all the `any` types. 10 | * 11 | * Once filled out, we encourage you to share your work with the 12 | * community by sending a pull request to: 13 | * https://github.com/flowtype/flow-typed 14 | */ 15 | 16 | declare module 'redux-logger' { 17 | declare module.exports: any 18 | } 19 | 20 | /** 21 | * We include stubs for each file inside this npm package in case you need to 22 | * require those files directly. Feel free to delete any files that aren't 23 | * needed. 24 | */ 25 | declare module 'redux-logger/dist/redux-logger' { 26 | declare module.exports: any 27 | } 28 | 29 | declare module 'redux-logger/src/core' { 30 | declare module.exports: any 31 | } 32 | 33 | declare module 'redux-logger/src/defaults' { 34 | declare module.exports: any 35 | } 36 | 37 | declare module 'redux-logger/src/diff' { 38 | declare module.exports: any 39 | } 40 | 41 | declare module 'redux-logger/src/helpers' { 42 | declare module.exports: any 43 | } 44 | 45 | declare module 'redux-logger/src/index' { 46 | declare module.exports: any 47 | } 48 | 49 | // Filename aliases 50 | declare module 'redux-logger/dist/redux-logger.js' { 51 | declare module.exports: $Exports<'redux-logger/dist/redux-logger'> 52 | } 53 | declare module 'redux-logger/src/core.js' { 54 | declare module.exports: $Exports<'redux-logger/src/core'> 55 | } 56 | declare module 'redux-logger/src/defaults.js' { 57 | declare module.exports: $Exports<'redux-logger/src/defaults'> 58 | } 59 | declare module 'redux-logger/src/diff.js' { 60 | declare module.exports: $Exports<'redux-logger/src/diff'> 61 | } 62 | declare module 'redux-logger/src/helpers.js' { 63 | declare module.exports: $Exports<'redux-logger/src/helpers'> 64 | } 65 | declare module 'redux-logger/src/index.js' { 66 | declare module.exports: $Exports<'redux-logger/src/index'> 67 | } 68 | -------------------------------------------------------------------------------- /data/server.py: -------------------------------------------------------------------------------- 1 | """Runs the server for backend application `data`.""" 2 | 3 | import argparse 4 | import json 5 | from paste import httpserver 6 | import webapp2 7 | 8 | import status 9 | 10 | 11 | class MyServer(webapp2.RequestHandler): 12 | """Abstract request handler, to be subclasses by server hooks.""" 13 | 14 | def get(self): 15 | """Implements actual hook logic and responds to requests.""" 16 | raise NotImplementedError('Must implement method `get`.') 17 | 18 | def returnJSON(self,j): 19 | self.response.headers['Content-Type'] = 'application/json' 20 | self.response.write(json.dumps(j, separators=(',',':'))) 21 | 22 | 23 | class SourceDataInfo(MyServer): 24 | def get(self): 25 | result = status.get_source_data_info() 26 | self.returnJSON(result) 27 | 28 | 29 | class ProdDataInfo(MyServer): 30 | def get(self): 31 | result = status.get_prod_data_info() 32 | self.returnJSON(result) 33 | 34 | 35 | class PublicDumpsInfo(MyServer): 36 | def get(self): 37 | result = status.get_public_dumps_info() 38 | self.returnJSON(result) 39 | 40 | 41 | class ColabsInfo(MyServer): 42 | def get(self): 43 | result = status.get_colabs_info() 44 | self.returnJSON(result) 45 | 46 | 47 | # Setup the webapp2 WSGI application. 48 | app = webapp2.WSGIApplication([ 49 | ('/source_data_info', SourceDataInfo), 50 | ('/prod_data_info', ProdDataInfo), 51 | ('/public_dumps_info', PublicDumpsInfo), 52 | ('/colabs_info', ColabsInfo), 53 | ], debug=False) 54 | 55 | 56 | def main(): 57 | parser = argparse.ArgumentParser() 58 | parser.add_argument('--listen', 59 | help='host:port to listen on', 60 | default='127.0.0.1:8084') 61 | args = parser.parse_args() 62 | 63 | host, port = args.listen.split(':') 64 | httpserver.serve( 65 | app, 66 | host=host, 67 | port=port, 68 | request_queue_size=128, 69 | use_threadpool=True, 70 | threadpool_workers=32, 71 | ) 72 | 73 | 74 | if __name__ == '__main__': 75 | main() 76 | -------------------------------------------------------------------------------- /obstaravania/suspicious.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Work being done from here 3 | from sqlalchemy import Column, Float, Integer, String, Boolean, and_ 4 | import json 5 | # Dirty hack to import from parent directory. TODO packaging... 6 | import os 7 | import sys 8 | 9 | from data_model import Firma, Obstaravanie, Candidate, Session 10 | 11 | sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) 12 | import db 13 | from db import parser 14 | 15 | # parser.add_argument("--download_datanest", action="store_true") 16 | options = parser.parse_args() 17 | 18 | db.connect(False) 19 | cur = db.getCursor() 20 | 21 | sql = ("SELECT ico, trzby2015, zisk2015, datum_vzniku " 22 | "FROM company_stats " 23 | "WHERE trzby2015 IS NOT NULL") 24 | 25 | cur = db.execute(cur, sql) 26 | data = {} 27 | for row in cur.fetchall(): 28 | ico = int(row["ico"]) 29 | data[ico] = row 30 | 31 | print("Number of companies with data", len(data)) 32 | 33 | with Session() as session: 34 | cnt = 0 35 | for obstaravanie in session.query(Obstaravanie). \ 36 | filter(and_(Obstaravanie.winner_id.isnot(None), 37 | Obstaravanie.bulletin_year >= 2015)). \ 38 | order_by(-Obstaravanie.bulletin_year, -Obstaravanie.bulleting_number): 39 | j = json.loads(obstaravanie.json) 40 | try: 41 | value = float(j["estimated_value_amount"]) 42 | except: 43 | # No amount, skip for now. 44 | continue 45 | try: 46 | ico = int(obstaravanie.winner.ico) # TODO: can have multiple winners... 47 | except: 48 | continue 49 | if ico in data: 50 | trzby = data[ico]["trzby2015"] 51 | zisk = data[ico]["zisk2015"] 52 | if (value > trzby) or (zisk < -value): 53 | print("Suspicious", obstaravanie.title, obstaravanie.customer.name, 54 | "Vyherca", obstaravanie.winner.name, 55 | "Trzby", data[ico]["trzby2015"], "Zisk", data[ico]["zisk2015"], 56 | "Hodnota: ", value, 57 | "Vestnik", obstaravanie.bulletin_year, obstaravanie.bulleting_number) 58 | -------------------------------------------------------------------------------- /client/src/components/Profile/components/Politician.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import React from 'react' 3 | import {withHandlers} from 'recompose' 4 | import {NavLink, type ContextRouter} from 'react-router-dom' 5 | 6 | import {withRouter} from 'react-router' 7 | import {connect} from 'react-redux' 8 | import {compose} from 'redux' 9 | import {isItCandidatesListSelector} from '../../../selectors' 10 | import type {Politician as PoliticianType, State} from '../../../state' 11 | 12 | type PoliticianProps = { 13 | politician: PoliticianType, 14 | useDefaultPicture: Function, 15 | isItCandidatesList: boolean, 16 | index: number, 17 | } 18 | 19 | const Politician = ({ 20 | politician, 21 | useDefaultPicture, 22 | isItCandidatesList, 23 | index, 24 | }: PoliticianProps) => ( 25 | 26 | {index + 1}. 27 | 28 | foto 36 | 37 | 38 | 39 | {politician.firstname} {politician.surname} 40 | 41 | 42 | {!isItCandidatesList && {politician.party_abbreviation}} 43 | 44 | {politician.latest_income && politician.latest_income !== -1 45 | ? `${politician.latest_income.toLocaleString('sk')} €` 46 | : '?'} 47 | 48 | {politician.num_houses_flats} 49 | {politician.num_fields_gardens} 50 | {politician.num_others} 51 | 52 | ) 53 | 54 | export default compose( 55 | withRouter, 56 | connect((state: State, props: ContextRouter) => ({ 57 | isItCandidatesList: isItCandidatesListSelector(state, props), 58 | })), 59 | withHandlers({ 60 | useDefaultPicture: ({history}) => (e) => { 61 | e.target.src = '/politician_default_s.png' 62 | }, 63 | }) 64 | )(Politician) 65 | -------------------------------------------------------------------------------- /client/README.md: -------------------------------------------------------------------------------- 1 | ## Setup 2 | 3 | To install and run 4 | 5 | ``` 6 | yarn 7 | yarn start 8 | ``` 9 | 10 | We don't have lint-staged, or any other method to enforce styling as a pre-commit hook (lint-staged does not work well without it being setup in root dir), so you might want to setup prettier/eslint in your editor of choice (or run the `fix-js` and `fix-scss` script before submitting PR). 11 | 12 | ## Redux 13 | 14 | We use a less boilerplate-heavy way of writing redux actions/reducers - essentially merging them together - so our actionCreators (and respective actions returned from them) look like this: 15 | 16 | ``` 17 | const someAction = () => ({ 18 | type: 'Anything that serves you well as action identifier (ideally a string) - used only in logging', 19 | doNotLog: false, // optional, if true the action is ignored by redux-logger middleware 20 | path: ['path', 'to', 'changed', 'substate'], // optional, without path you'll receive the whole state 21 | payload: {any: 'data'}, // passed to reducer, again mostly usefull for clearer logging 22 | reducer: (substateDefinedByPath, payload) => newSubstate 23 | }) 24 | ``` 25 | 26 | This means the actions are no longer serializable so you can't use time-travel, but all other features of redux dev-tools still work. 27 | 28 | ## Sass and Css 29 | 30 | You should write styles in `Component.scss` and then import a `.css` file in `Component.js`: 31 | 32 | ``` 33 | import './Component.css' 34 | ``` 35 | 36 | The required `.css` files are created automatically by `node-sass-chokidar`, and are ignored (as they are essentially build files) by `.gitignore`. 37 | 38 | ## Flow 39 | 40 | We use flow to add type safety to our javascript code. There are many editor extensions to take advanteges of flow. Flow is **not** used 41 | automtically in js files. You have to add `// @flow` on the first line. 42 | 43 | There is a command for testing flow coverage: 44 | 45 | ``` 46 | yarn flow 47 | ``` 48 | 49 | This command check for `// @flow` in every js file in the `src` directory (which doesn't already have the flow tag), and will display 50 | flow errors and print a table of coverage... The script also generates a webpage, where you can see the errors in a nicer format. The web page 51 | is located in `flow-coverage/index.html`. 52 | -------------------------------------------------------------------------------- /client/src/components/shared/Info/RelationList.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import React from 'react' 3 | import {Badge} from 'reactstrap' 4 | import {sortBy} from 'lodash' 5 | 6 | import RecursiveInfo from './RecursiveInfo' 7 | import {showRelationType, getRelationTitle, getColor} from '../utilities' 8 | import type {RelatedEntity} from '../../../state' 9 | 10 | type RelationListProps = { 11 | data: Array, 12 | name: string, 13 | } 14 | 15 | type RelationItemProps = { 16 | related: RelatedEntity, 17 | name: string, 18 | } 19 | 20 | type TitleBadgeProps = { 21 | related: RelatedEntity, 22 | name: string, 23 | } 24 | 25 | export default ({data, name, useNewApi}: RelationListProps) => ( 26 |
      27 | {sortBy(data, [ 28 | 'political_entity', 29 | 'contact_with_politics', 30 | 'trade_with_government', 31 | 'edge_types', 32 | ]).reverse().map((related: RelatedEntity) => ( 33 | 34 | ))} 35 |
    36 | ) 37 | 38 | const RelationItem = ({related, name}: RelationItemProps) => ( 39 |
  • 40 | } 43 | /> 44 |
  • 45 | ) 46 | 47 | const TitleBadge = ({related, name}: TitleBadgeProps) => { 48 | const result = [] 49 | related.edge_types.forEach((type: number, i: number) => { 50 | const symmetric: boolean = related.edge_types.includes(-type) 51 | if (type >= 0 || !symmetric) { 52 | result.push( 53 | 65 | {showRelationType( 66 | type, 67 | related.edge_type_texts[i], 68 | related.edge_effective_to_dates[i], 69 | !symmetric 70 | )} 71 | 72 | ) 73 | } 74 | }) 75 | return result 76 | } 77 | -------------------------------------------------------------------------------- /client/src/components/Profile/utilities.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import type {Politician, PoliticianDetail, PoliticianOffice} from '../../state' 3 | 4 | export const getTerm = (politician: Politician | PoliticianDetail | PoliticianOffice): string => 5 | politician.term_start || politician.term_finish 6 | ? politician.term_start === politician.term_finish 7 | ? `${politician.term_start}` 8 | : `${politician.term_start || ''} - ${politician.term_finish || ''}` 9 | : '' 10 | 11 | export const mergeConsecutiveTerms = (offices: Array): Array => 12 | offices.reduce((acc, cur) => { 13 | acc.some((office) => { 14 | if ( 15 | office.term_start === cur.term_finish && 16 | office.party_abbreviation === cur.party_abbreviation && 17 | office.office_name_male === cur.office_name_male 18 | ) { 19 | office.term_start = cur.term_start 20 | return true 21 | } 22 | return false 23 | }) || acc.push({...cur}) 24 | return acc 25 | }, []) 26 | 27 | export type SplitOffices = { 28 | currentOffices: Array, 29 | pastOffices: Array, 30 | } 31 | 32 | export const splitOfficesByYear = ( 33 | offices: Array, 34 | currentYear: number 35 | ): SplitOffices => { 36 | let current = [] 37 | const past = [] 38 | offices.forEach((office) => { 39 | if (office.term_finish >= currentYear || office.term_start >= currentYear) { 40 | current.push(office) 41 | } else { 42 | past.push(office) 43 | } 44 | }) 45 | if (current.length === 0) { 46 | current = [past.shift()] 47 | } 48 | return {currentOffices: current, pastOffices: past} 49 | } 50 | 51 | export const getQueryFromGroup = (group: string): string => 52 | group === 'active' 53 | ? 'poslanci' 54 | : group === 'candidates_2018_bratislava_mayor' 55 | ? 'kandidati_bratislava' 56 | : group === 'candidates_2019_president' 57 | ? 'kandidati_prezident' 58 | : '' 59 | 60 | export const getGroupFromQuery = (group: string): string => 61 | group === 'poslanci' 62 | ? 'active' 63 | : group === 'kandidati_bratislava' 64 | ? 'candidates_2018_bratislava_mayor' 65 | : group === 'kandidati_prezident' 66 | ? 'candidates_2019_president' 67 | : '' 68 | -------------------------------------------------------------------------------- /obstaravania/pdfsender/sendpdf.php: -------------------------------------------------------------------------------- 1 | option('u') 6 | ->aka('username') 7 | ->describedAs('Username used in remote service call.') 8 | ->require(); 9 | 10 | $arguments->option('p') 11 | ->aka('password') 12 | ->describedAs('Password used in remote service call.') 13 | ->require(); 14 | 15 | $arguments->option() 16 | ->file() 17 | ->describedAs('Input json file.') 18 | ->require(); 19 | 20 | $arguments->option() 21 | ->file() 22 | ->describedAs('Input pdf file.') 23 | ->require(); 24 | 25 | $start = microtime(true); 26 | 27 | $ext1 = substr($arguments[0], -4); 28 | $ext2 = substr($arguments[1], -4); 29 | $jsonFile = ''; 30 | $pdfFile = ''; 31 | if ($ext1 == '.pdf' && $ext2 == 'json') { 32 | $jsonFile = $arguments[1]; 33 | $pdfFile = $arguments[0]; 34 | } else if ($ext1 == 'json' && $ext2 == '.pdf') { 35 | $jsonFile = $arguments[0]; 36 | $pdfFile = $arguments[1]; 37 | } else { 38 | fwrite(STDERR, sprintf("Input files %s, %s are not json and pdf.\n", $arguments[0], $arguments[1])); 39 | exit(1); 40 | } 41 | 42 | $jsonData = file_get_contents($jsonFile); 43 | if ($jsonData === null) { 44 | fwrite(STDERR, sprintf("Cannot read input json file %s.\n", $jsonFile)); 45 | exit(1); 46 | } 47 | $json = json_decode($jsonData, true); 48 | if ($json === null) { 49 | fwrite(STDERR, sprintf("Unable to decode input json %s.\n", $jsonFile)); 50 | exit(1); 51 | } 52 | 53 | $pdf = file_get_contents($pdfFile); 54 | if ($pdf === null) { 55 | fwrite(STDERR, sprintf("Cannot read input pdf file %s.\n", $pdfFile)); 56 | exit(1); 57 | } 58 | 59 | $exitCode = 0; 60 | try { 61 | $zelenaPosta = new \ZelenaPosta($arguments['u'], $arguments['p']); 62 | $zelenaPosta->setJson($json); 63 | $zelenaPosta->setPdf($pdf); 64 | 65 | $result = $zelenaPosta->sendFiles(); 66 | } catch(RetryableException $e) { 67 | fwrite(STDERR, sprintf("Error: %s.\n", $e->getMessage())); 68 | fwrite(STDERR, "Failed to send PDF file. Please try again later.\n"); 69 | $exitCode = 1; 70 | } catch (Exception $e) { 71 | fwrite(STDERR, sprintf("Error: %s.\n", $e->getMessage())); 72 | fwrite(STDERR, "Failed to send PDF file.\n"); 73 | $exitCode = 2; 74 | } 75 | 76 | $end = microtime(true); 77 | fwrite(STDERR, sprintf("%fms to send PDF file.\n", ($end - $start))); 78 | exit($exitCode); 79 | -------------------------------------------------------------------------------- /client/src/components/Connections/components/Statuses.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import React from 'react' 3 | import {compose} from 'redux' 4 | import {branch, renderNothing} from 'recompose' 5 | import EntitySearchWrapper, {type EntitySearchProps} from '../dataWrappers/EntitySearchWrapper' 6 | import EntityWrapper, {type EntityProps} from '../dataWrappers/EntityWrapper' 7 | import ConnectionWrapper, {type ConnectionProps} from '../dataWrappers/ConnectionWrapper' 8 | import './Statuses.css' 9 | 10 | type EmptyHandler = () => void 11 | 12 | const translateZaznam = (count: number) => { 13 | const button = {count} 14 | if (count === 1) { 15 | return Nájdený {button} záznam 16 | } else if (count > 1 && count < 5) { 17 | return Nájdené {button} záznamy 18 | } 19 | return Nájdených {button} záznamov 20 | } 21 | 22 | type Props = { 23 | showAlternatives1: boolean, 24 | showAlternatives2: boolean, 25 | toggleAlternatives1: EmptyHandler, 26 | toggleAlternatives2: EmptyHandler, 27 | } & EntitySearchProps & 28 | EntityProps & 29 | ConnectionProps 30 | 31 | const Statuses = ({ 32 | entity1, 33 | entity2, 34 | connections, 35 | showAlternatives1, 36 | showAlternatives2, 37 | toggleAlternatives1, 38 | toggleAlternatives2, 39 | }: Props) => ( 40 |
    41 | {connections.length > 0 ? ( 42 |

    43 | Dĺžka prepojenia: {connections.length - 1} 44 |

    45 | ) : ( 46 |

    47 | Prepojenie neexistuje. 48 |

    49 | )} 50 |

    51 | {translateZaznam(entity1.eids.length)} 52 | pre "{entity1.query}" 53 |

    54 |

    55 | {translateZaznam(entity2.eids.length)} 56 | pre "{entity2.query}" 57 |

    58 |
    59 | ) 60 | 61 | export default compose( 62 | EntitySearchWrapper, 63 | branch( 64 | ({entitySearch1, entitySearch2}: EntitySearchProps): boolean => 65 | !!entitySearch1 && !!entitySearch2, 66 | compose( 67 | EntityWrapper, 68 | ConnectionWrapper, 69 | ), 70 | renderNothing 71 | ) 72 | )(Statuses) 73 | -------------------------------------------------------------------------------- /obstaravania/notifications/sample_data/one.json: -------------------------------------------------------------------------------- 1 | { 2 | "company": { 3 | "address": "Dr. J. Zeleny\u00e1ka 28", 4 | "address_full": "Doktor J\u00e1na Zeleny\u00e1ka 506/28, 935 61 Hronovce, Slovakia", 5 | "ico": "36769002", 6 | "name": "M&G Company s.r.o." 7 | }, 8 | "notifications": [ 9 | { 10 | "reason": { 11 | "bulletin_number": null, 12 | "bulletin_year": null, 13 | "customer": "Obec \u0160alov", 14 | "id": 142918, 15 | "price": 55500.0, 16 | "text": "zber odpadu, nakladanie odpadu, odvoz komun\u00e1lneho odpadu, odvoz stavebn\u00e9ho odpadu, odvoz ostatn\u00e9ho odpadu, ulo\u017eenie odpadu na skl\u00e1dku, \u00faprava miesta do p\u00f4vodn\u00e9ho stavu/san\u00e1cia", 17 | "title": "SAN\u00c1CIA MIEST S NEZ\u00c1KONNE UMIESTNEN\u00ddM ODPADOM v obci \u0160ALOV" 18 | }, 19 | "what": { 20 | "bulletin_date": "29. j\u00fan 2017", 21 | "bulletin_day": 29, 22 | "bulletin_month": 6, 23 | "bulletin_number": 127, 24 | "bulletin_year": 2017, 25 | "customer": "Mestsk\u00e1 \u010das\u0165 Bratislava - Ra\u010da", 26 | "id": 173851, 27 | "price": 29784.6, 28 | "price_avg": 11.1714600112613, 29 | "price_num": 20, 30 | "price_stdev": 1.13647785918956, 31 | "text": "Predmetom z\u00e1kazky je odvoz, vytriedenie a n\u00e1sledn\u00e9 zhodnotenie alebo zne\u0161kodnenie komun\u00e1lneho odpadu zaraden\u00e9ho pod\u013ea Katal\u00f3gu odpadov do skupiny 20 03 07 objemn\u00fd odpad \u010dinnos\u0165ou R 1 a 20 03 08 drobn\u00fd stavebn\u00fd odpad \u010dinnos\u0165ou R 5, vznikaj\u00faceho pri prev\u00e1dzkovan\u00ed Zbern\u00e9ho dvora Mestskej \u010dasti Bratislava Ra\u010da, Pri \u0160ajb\u00e1ch v Bratislave a pren\u00e1jom ve\u013ekokapacitn\u00fdch kontajnerov. S\u00fa\u010das\u0165ou odvozu odpadu je nalo\u017eenie kontajnera na dopravn\u00fd prostriedok a jeho vykl\u00e1dka na mieste spracovania odpadu ako aj poskytnutie ve\u013ekoobjemov\u00fdch kontajnerov na skladovanie odpadu pred ich odvozom na spracovanie.", 32 | "title": "Odvoz a likvid\u00e1cia odpadu" 33 | } 34 | } 35 | ] 36 | } -------------------------------------------------------------------------------- /data/intelligence/translate.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | import psycopg2 3 | import psycopg2.extras 4 | 5 | 6 | def google_translate(sk_text): 7 | """ CAUTION! This is a paid service! """ 8 | from google.cloud import translate 9 | translate_client = translate.Client() 10 | result = translate_client.translate(sk_text, source_language='sk', target_language='en') 11 | result = result['translatedText'] 12 | print("Google Translate: {} -> {}".format(sk_text, result)) 13 | return result 14 | 15 | 16 | def getConfig(): 17 | import yaml 18 | with open("../db_config_update_source.yaml", "r") as stream: 19 | return yaml.load(stream, Loader=yaml.FullLoader) 20 | 21 | 22 | def translate(sk_texts, verbose=False, enable_google_translate=False): 23 | """ Returns English translation of sk_texts """ 24 | 25 | # Connect to the latest production data schema 26 | config = getConfig() 27 | db = psycopg2.connect(user=config["user"], dbname=config["db"]) 28 | 29 | results = [] 30 | cur = db.cursor(cursor_factory=psycopg2.extras.RealDictCursor) 31 | cur.execute('SET search_path="translation_cache";') 32 | for sk_text in sk_texts: 33 | sql = "select en from translations where sk=%s" 34 | cur.execute(sql, (sk_text,)) 35 | result = None 36 | for row in cur: 37 | result = row["en"] 38 | if result is None and enable_google_translate: 39 | # If the result is not in cache, use Google translate and remember the result. 40 | result = google_translate(sk_text) 41 | insert_sql = "insert into translations values(%s,%s)" 42 | cur.execute(insert_sql, (sk_text, result,)) 43 | results.append(result) 44 | 45 | if verbose: 46 | for sk_text, result in zip(sk_texts, results): 47 | print("Translation: {}->{}".format(sk_text, result)) 48 | 49 | # Close database connection 50 | db.commit() 51 | db.close() 52 | return results 53 | 54 | 55 | def main(args_dict): 56 | verbose = args_dict['verbose'] 57 | translate(["Ako sa mas?", "pes"], verbose=verbose, enable_google_translate=True) 58 | 59 | 60 | if __name__ == '__main__': 61 | parser = argparse.ArgumentParser() 62 | parser.add_argument('--verbose', default=False, action='store_true', help='Report progress to stdout') 63 | args_dict = vars(parser.parse_args()) 64 | main(args_dict) 65 | -------------------------------------------------------------------------------- /obstaravania/notifications/sample_data/one_new.json: -------------------------------------------------------------------------------- 1 | { 2 | "company": { 3 | "address": "Dr. J. Zeleny\u00e1ka 28", 4 | "address_full": "Doktor J\u00e1na Zeleny\u00e1ka 506/28, 935 61 Hronovce, Slovakia", 5 | "ico": "36769002", 6 | "name": "M&G Company s.r.o.", 7 | "city": "Bratislava", 8 | "street": "Pifflova 6", 9 | "zip": "85101", 10 | "country": "sk" 11 | }, 12 | "notifications": [ 13 | { 14 | "reason": { 15 | "bulletin_number": null, 16 | "bulletin_year": null, 17 | "customer": "Obec \u0160alov", 18 | "id": 142918, 19 | "price": 55500.0, 20 | "text": "zber odpadu, nakladanie odpadu, odvoz komun\u00e1lneho odpadu, odvoz stavebn\u00e9ho odpadu, odvoz ostatn\u00e9ho odpadu, ulo\u017eenie odpadu na skl\u00e1dku, \u00faprava miesta do p\u00f4vodn\u00e9ho stavu/san\u00e1cia", 21 | "title": "SAN\u00c1CIA MIEST S NEZ\u00c1KONNE UMIESTNEN\u00ddM ODPADOM v obci \u0160ALOV" 22 | }, 23 | "what": { 24 | "bulletin_date": "29. j\u00fan 2017", 25 | "bulletin_day": 29, 26 | "bulletin_month": 6, 27 | "bulletin_number": 127, 28 | "bulletin_year": 2017, 29 | "customer": "Mestsk\u00e1 \u010das\u0165 Bratislava - Ra\u010da", 30 | "id": 173851, 31 | "price": 29784.6, 32 | "price_avg": 11.1714600112613, 33 | "price_num": 20, 34 | "price_stdev": 1.13647785918956, 35 | "text": "Predmetom z\u00e1kazky je odvoz, vytriedenie a n\u00e1sledn\u00e9 zhodnotenie alebo zne\u0161kodnenie komun\u00e1lneho odpadu zaraden\u00e9ho pod\u013ea Katal\u00f3gu odpadov do skupiny 20 03 07 objemn\u00fd odpad \u010dinnos\u0165ou R 1 a 20 03 08 drobn\u00fd stavebn\u00fd odpad \u010dinnos\u0165ou R 5, vznikaj\u00faceho pri prev\u00e1dzkovan\u00ed Zbern\u00e9ho dvora Mestskej \u010dasti Bratislava Ra\u010da, Pri \u0160ajb\u00e1ch v Bratislave a pren\u00e1jom ve\u013ekokapacitn\u00fdch kontajnerov. S\u00fa\u010das\u0165ou odvozu odpadu je nalo\u017eenie kontajnera na dopravn\u00fd prostriedok a jeho vykl\u00e1dka na mieste spracovania odpadu ako aj poskytnutie ve\u013ekoobjemov\u00fdch kontajnerov na skladovanie odpadu pred ich odvozom na spracovanie.", 36 | "title": "Odvoz a likvid\u00e1cia odpadu" 37 | } 38 | } 39 | ] 40 | } -------------------------------------------------------------------------------- /client/src/components/Notices/NoticeItem.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import React, {Fragment} from 'react' 3 | import {getWarning} from './utilities' 4 | import {Link} from 'react-router-dom' 5 | import {compose, withState, withHandlers} from 'recompose' 6 | 7 | import {formatSimilarPercent} from './LegendSymbols' 8 | import CompanyDetails from '../shared/CompanyDetails' 9 | 10 | import type {Notice} from '../../state' 11 | 12 | import './NoticeItem.css' 13 | import './LegendSymbols.css' 14 | 15 | type Props = {| 16 | item: Notice, 17 | showSupplierInfo: boolean, 18 | showCustomerInfo: boolean, 19 | toggleSupplier: () => void, 20 | toggleCustomer: () => void, 21 | |} 22 | const _NoticeItem = ({ 23 | item, 24 | showSupplierInfo, 25 | showCustomerInfo, 26 | toggleSupplier, 27 | toggleCustomer, 28 | }: Props) => ( 29 | 30 | 31 | 32 | {getWarning(item)} 33 | 34 | {item.title} 35 | 36 | 37 | 38 | 39 | {showCustomerInfo ? [−] : '[+]'} {item.name} 40 | 41 | 42 | 43 | {item.best_supplier_name && ( 44 | 45 | {showSupplierInfo ? [−] : '[+]'} {item.best_supplier_name} 46 | 47 | )} 48 | 49 | 50 | {item.best_similarity ? formatSimilarPercent(Math.round(item.best_similarity * 100)) : ''} 51 | 52 | 53 | {showSupplierInfo && ( 54 | 55 | 56 | 57 | 58 | 59 | )} 60 | {showCustomerInfo && ( 61 | 62 | 63 | 64 | 65 | 66 | )} 67 | 68 | ) 69 | 70 | export default compose( 71 | withState('showSupplierInfo', 'setSupplier', false), 72 | withState('showCustomerInfo', 'setCustomer', false), 73 | withHandlers({ 74 | toggleSupplier: ({setSupplier}) => () => setSupplier((current) => !current), 75 | toggleCustomer: ({setCustomer}) => () => setCustomer((current) => !current), 76 | }) 77 | )(_NoticeItem) 78 | -------------------------------------------------------------------------------- /data/sources.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "description": "Centrálny register zmlúv (CRZ)", 4 | "name": "ekosystem_CRZ", 5 | "path": "/tmp/source_ekosystem_CRZ.sql.gz", 6 | "schemas": 7 | [ 8 | "crz" 9 | ], 10 | "type": "SQL", 11 | "url": "https://s3.eu-central-1.amazonaws.com/ekosystem-slovensko-digital-dumps/crz.sql.gz" 12 | }, 13 | { 14 | "description": "ITMS2014+", 15 | "name": "ekosystem_ITMS", 16 | "path": "/tmp/source_ekosystem_ITMS.sql.gz", 17 | "schemas": 18 | [ 19 | "itms" 20 | ], 21 | "type": "SQL", 22 | "url": "https://s3.eu-central-1.amazonaws.com/ekosystem-slovensko-digital-dumps/itms.sql.gz" 23 | }, 24 | { 25 | "description": "Register právnických osôb (RPO)", 26 | "name": "ekosystem_RPO", 27 | "path": "/tmp/source_ekosystem_RPO.sql.gz", 28 | "schemas": 29 | [ 30 | "rpo" 31 | ], 32 | "type": "SQL", 33 | "url": "https://s3.eu-central-1.amazonaws.com/ekosystem-slovensko-digital-dumps/rpo.sql.gz" 34 | }, 35 | { 36 | "description": "Vestník verejného obstarávania (VVO)", 37 | "name": "ekosystem_VVO", 38 | "path": "/tmp/source_ekosystem_VVO.sql.gz", 39 | "schemas": 40 | [ 41 | "vvo" 42 | ], 43 | "type": "SQL", 44 | "url": "https://s3.eu-central-1.amazonaws.com/ekosystem-slovensko-digital-dumps/vvo.sql.gz" 45 | }, 46 | { 47 | "delimiter": ";", 48 | "description": "FinStat.sk", 49 | "name": "finstat", 50 | "path": "/tmp/source_finstat.csv", 51 | "table_name": "company_stats", 52 | "type": "CSV" 53 | }, 54 | { 55 | "delimiter": "|", 56 | "description": "Register partnerov verejného sektora (RPVS)", 57 | "name": "rpvs", 58 | "path": "/tmp/source_rpvs.csv", 59 | "table_name": "rpvs", 60 | "type": "CSV" 61 | }, 62 | { 63 | "description": "KamIduEurofondy.sk", 64 | "name": "KamIduEurofondy", 65 | "path": "/tmp/source_KamIduEurofondy.json", 66 | "table_name": "kamidueurofondy", 67 | "type": "JSON" 68 | }, 69 | { 70 | "description": "profil.verejne.digital", 71 | "name": "internal_profil", 72 | "path": "/tmp/source_internal_profil.sql.gz", 73 | "schemas": 74 | [ 75 | "profil" 76 | ], 77 | "type": "SQL" 78 | } 79 | ] 80 | -------------------------------------------------------------------------------- /client/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 14 | 15 | 18 | 19 | 28 | Verejne.digital 29 | 30 | 31 | 32 | 35 |
    36 | 46 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /data/clean_db.py: -------------------------------------------------------------------------------- 1 | import os 2 | import argparse 3 | 4 | from db.db import DatabaseConnection 5 | 6 | 7 | def pretty_print(schemas: list) -> None: 8 | """ 9 | Pretty print all available schemas. 10 | :param schemas: list(str) - schemas to list 11 | :return: None 12 | """ 13 | print('Available schemas:') 14 | for i, schema in enumerate(schemas): 15 | print('{i:3d} {schema}'.format(i=i, schema=schema)) 16 | 17 | 18 | def main(args_dict): 19 | # connect to Database 20 | db_conn = DatabaseConnection(path_config=os.path.abspath(os.path.join(os.path.dirname(__file__), 'db_config_update_source.yaml'))) 21 | 22 | # list schemas 23 | schemas = db_conn.list_schemas() 24 | pretty_print(schemas) 25 | 26 | if args_dict.rename: 27 | # ask for rename 28 | print('Number to rename (q to quit): ') 29 | inp = input() 30 | try: 31 | to_del_num = int(inp) 32 | except ValueError: 33 | print('Exiting') 34 | to_del_num = -1 35 | 36 | if 0 <= to_del_num < len(schemas): 37 | # ask for renaming to 38 | print('Rename schema {schema} to (provide new name): '.format(schema=schemas[to_del_num])) 39 | new_name = input() 40 | db_conn.rename_schema(schemas[to_del_num], new_name, verbose=True) 41 | db_conn.commit() 42 | 43 | else: 44 | # ask for deletion 45 | print('Number(s) to delete (comma separated, q to quit): ') 46 | inp = input() 47 | to_del_nums = inp.split(',') 48 | try: 49 | to_del_nums = list(map(int, to_del_nums)) 50 | except ValueError: 51 | print('Exiting') 52 | to_del_nums = [] 53 | 54 | if to_del_nums != []: 55 | # ask if delete 56 | print('Deleting schema(s) {schema}? (Y/N):'.format(schema=', '.join([schemas[to_del_num] for to_del_num in to_del_nums]))) 57 | if str(input()).upper() != 'Y': 58 | print('Aborted deletion') 59 | else: 60 | # delete: 61 | for to_del_num in to_del_nums: 62 | if 0 <= to_del_num < len(schemas): 63 | db_conn.remove_schema(schemas[to_del_num], verbose=True) 64 | db_conn.commit() 65 | 66 | 67 | if __name__ == '__main__': 68 | parser = argparse.ArgumentParser() 69 | parser.add_argument('--rename', default=False, action='store_true', help='Rename, not delete') 70 | args_dict = parser.parse_args() 71 | main(args_dict) 72 | -------------------------------------------------------------------------------- /client/src/components/PlacesAutocomplete/PlacesAutocomplete.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import React from 'react' 3 | import GoogleAutocomplete from 'react-places-autocomplete' 4 | import {withHandlers, defaultProps, compose} from 'recompose' 5 | import classnames from 'classnames' 6 | import './PlacesAutocomplete.css' 7 | 8 | type OnError = (status: string, clearSuggestions: Function) => any 9 | type OnSelect = (address: string, placeId: ?string) => any 10 | type Props = { 11 | value: string, 12 | onChange: (value: string) => any, 13 | onErrorBinded: OnError, 14 | searchOptions: Object, 15 | onSelect: OnSelect, 16 | className: string, 17 | } 18 | 19 | const PlacesAutocomplete = ({ 20 | value, 21 | onChange, 22 | onSelect, 23 | onErrorBinded, 24 | searchOptions, 25 | className, 26 | }: Props) => ( 27 | 38 | {({getInputProps, suggestions, getSuggestionItemProps}) => ( 39 |
    40 | 47 | {suggestions.length > 0 && ( 48 |
    49 | {suggestions.map((suggestion) => { 50 | const className = classnames( 51 | 'autocomplete__suggestions__item', 52 | suggestion.active && 'autocomplete__suggestions__item--active' 53 | ) 54 | return ( 55 |
    56 | {suggestion.formattedSuggestion.mainText}{' '} 57 | {suggestion.formattedSuggestion.secondaryText} 58 |
    59 | ) 60 | })} 61 |
    62 | )} 63 |
    64 | )} 65 |
    66 | ) 67 | 68 | export default compose( 69 | defaultProps({ 70 | searchOptions: {}, 71 | }), 72 | withHandlers({ 73 | onErrorBinded: (props) => (status, clearSuggestions) => 74 | props.onError && props.onError(status, clearSuggestions), 75 | }) 76 | )(PlacesAutocomplete) 77 | -------------------------------------------------------------------------------- /data/test.py: -------------------------------------------------------------------------------- 1 | """Unit tests for backend application data. 2 | 3 | Run all unit tests from the command line by executing: 4 | ./test.sh 5 | 6 | Alternatively, under user `data` and with the appropriate Python 7 | virtual environment installed and activated, run all unit tests using: 8 | python test.py 9 | To only run an individual unit test, run (for example): 10 | python test.py TestHandlers.test_source_data_info 11 | """ 12 | import json 13 | import unittest 14 | import webapp2 15 | 16 | import server 17 | 18 | 19 | def _request_json(url, test_handler): 20 | """Utility method to check a JSON is returned from the given URL.""" 21 | request = webapp2.Request.blank(url) 22 | response = request.get_response(server.app) 23 | test_handler.assertEqual(response.status_int, 200) 24 | test_handler.assertEqual(response.content_type, 'application/json') 25 | j = json.loads(response.text) 26 | return j 27 | 28 | 29 | class TestHandlers(unittest.TestCase): 30 | 31 | def test_source_data_info(self): 32 | content = _request_json('/source_data_info', self) 33 | self.assertIsInstance(content, list) 34 | self.assertTrue(content) 35 | print('SourceDataInfo responded with %d items.' % len(content)) 36 | print('Schemas and their update times:') 37 | for source in content: 38 | print('%s (schema %s) last updated %s' % (source['name'], source['schema'], source['update'])) 39 | 40 | def test_prod_data_info(self): 41 | content = _request_json('/prod_data_info', self) 42 | self.assertIsInstance(content, dict) 43 | self.assertTrue(content) 44 | self.assertTrue('tables' in content) 45 | self.assertTrue('schema' in content) 46 | self.assertTrue('update' in content) 47 | print('ProdDataInfo responded with schema %s.' % content['schema']) 48 | 49 | def test_public_dumps_info(self): 50 | content = _request_json('/public_dumps_info', self) 51 | self.assertIsInstance(content, list) 52 | self.assertTrue(content) 53 | print('PublicDumpsInfo responded with %d items:' % len(content)) 54 | print(json.dumps(content, indent=2, ensure_ascii=False)) 55 | 56 | def test_colabs_info(self): 57 | content = _request_json('/colabs_info', self) 58 | self.assertIsInstance(content, list) 59 | self.assertTrue(content) 60 | print('ColabsInfo responded with %d items:' % len(content)) 61 | print(json.dumps(content, indent=2, ensure_ascii=False)) 62 | 63 | 64 | if __name__ == '__main__': 65 | unittest.main() 66 | --------------------------------------------------------------------------------