├── .gitignore ├── LICENSE.md ├── README.md ├── TODO.txt ├── VicBikeMap ├── __init__.py ├── settings │ ├── __init__.py │ ├── base.py │ └── dev.py ├── urls.py └── wsgi.py ├── blogApp ├── __init__.py ├── admin.py ├── forms │ ├── __init__.py │ ├── post.py │ └── upload_image.py ├── locale │ ├── da │ │ └── LC_MESSAGES │ │ │ └── django.mo │ ├── de │ │ └── LC_MESSAGES │ │ │ ├── django.mo │ │ │ └── django.po │ ├── en │ │ └── LC_MESSAGES │ │ │ ├── django.mo │ │ │ └── django.po │ ├── es │ │ └── LC_MESSAGES │ │ │ └── django.mo │ ├── fi │ │ └── LC_MESSAGES │ │ │ ├── django.mo │ │ │ └── django.po │ ├── fr │ │ └── LC_MESSAGES │ │ │ ├── django.mo │ │ │ └── django.po │ ├── is │ │ └── LC_MESSAGES │ │ │ └── django.mo │ └── nl │ │ └── LC_MESSAGES │ │ ├── django.mo │ │ └── django.po ├── migrations │ ├── 0001_initial.py │ ├── 0002_auto_20220118_1545.py │ └── __init__.py ├── models │ ├── __init__.py │ └── post.py ├── static │ └── blogApp │ │ ├── css │ │ ├── create.css │ │ └── post.css │ │ └── js │ │ ├── create.js │ │ └── post.js ├── templates │ └── blogApp │ │ ├── base_blog.html │ │ ├── create_post.html │ │ ├── index.html │ │ ├── post_template.html │ │ └── view_post.html ├── tests.py ├── urls.py ├── utils │ ├── __init__.py │ └── hash62.py └── views │ ├── __init__.py │ ├── index.py │ ├── post.py │ └── upload_image.py ├── docs ├── query-and-export-data.md └── set-up-project-mac.md ├── locale ├── da │ └── LC_MESSAGES │ │ └── django.mo ├── de │ └── LC_MESSAGES │ │ ├── django.mo │ │ ├── django.po │ │ ├── djangojs.mo │ │ └── djangojs.po ├── en │ └── LC_MESSAGES │ │ ├── django.mo │ │ ├── django.po │ │ ├── djangojs.mo │ │ └── djangojs.po ├── es │ └── LC_MESSAGES │ │ └── django.mo ├── fi │ └── LC_MESSAGES │ │ ├── django.mo │ │ └── django.po ├── fr │ └── LC_MESSAGES │ │ ├── django.mo │ │ └── django.po ├── is │ └── LC_MESSAGES │ │ └── django.mo └── nl │ └── LC_MESSAGES │ ├── django.mo │ └── django.po ├── manage.py ├── mapApp ├── __init__.py ├── admin.py ├── apps.py ├── fixtures │ ├── UKM_official.xml │ ├── icbc_fixture.json │ └── police_fixture.json ├── forms │ ├── __init__.py │ ├── contact.py │ ├── edit_geom.py │ ├── edit_hazard.py │ ├── geofences.py │ ├── hazard.py │ ├── incident.py │ ├── nearmiss.py │ ├── newInfrastructure.py │ └── theft.py ├── locale │ ├── da │ │ └── LC_MESSAGES │ │ │ └── django.mo │ ├── de │ │ └── LC_MESSAGES │ │ │ ├── django.mo │ │ │ ├── django.po │ │ │ ├── djangojs.mo │ │ │ └── djangojs.po │ ├── en │ │ └── LC_MESSAGES │ │ │ ├── django.mo │ │ │ ├── django.po │ │ │ ├── djangojs.mo │ │ │ └── djangojs.po │ ├── es │ │ └── LC_MESSAGES │ │ │ ├── django.mo │ │ │ └── djangojs.mo │ ├── fi │ │ └── LC_MESSAGES │ │ │ ├── django.mo │ │ │ └── djangojs.mo │ ├── fr │ │ └── LC_MESSAGES │ │ │ ├── django.mo │ │ │ ├── django.po │ │ │ ├── djangojs.mo │ │ │ └── djangojs.po │ ├── is │ │ └── LC_MESSAGES │ │ │ ├── django.mo │ │ │ └── djangojs.mo │ └── nl │ │ └── LC_MESSAGES │ │ ├── django.mo │ │ └── django.po ├── migrations │ ├── 0001_initial.py │ ├── 0002_update_age_fields.py │ ├── 0003_add_ebike_fields.py │ ├── 0004_add_gender_fields.py │ ├── 0005_add_gender_options.py │ ├── 0006_migrate_sex_to_gender.py │ └── __init__.py ├── models │ ├── __init__.py │ ├── alert_area.py │ ├── alert_notification.py │ ├── gender.py │ ├── hazard.py │ ├── incident.py │ ├── newInfrastructure.py │ ├── official.py │ ├── point.py │ ├── theft.py │ └── weather.py ├── permissions.py ├── serializers.py ├── signals.py ├── static │ ├── bootstrap-slider │ │ ├── bootstrap-slider.js │ │ └── css │ │ │ └── bootstrap-slider.min.css │ ├── bootstrap │ │ ├── config.json │ │ ├── css │ │ │ └── bootstrap-theme.min.css │ │ ├── fonts │ │ │ ├── glyphicons-halflings-regular.eot │ │ │ ├── glyphicons-halflings-regular.svg │ │ │ ├── glyphicons-halflings-regular.ttf │ │ │ └── glyphicons-halflings-regular.woff │ │ └── js │ │ │ ├── bootstrap.js │ │ │ └── bootstrap.min.js │ ├── datetimepicker │ │ ├── css │ │ │ ├── bootstrap-datetimepicker.css │ │ │ └── bootstrap-datetimepicker.min.css │ │ └── js │ │ │ ├── bootstrap-datetimepicker.js │ │ │ ├── bootstrap-datetimepicker.min.js │ │ │ └── locales │ │ │ ├── bootstrap-datetimepicker.ar.js │ │ │ ├── bootstrap-datetimepicker.bg.js │ │ │ ├── bootstrap-datetimepicker.ca.js │ │ │ ├── bootstrap-datetimepicker.cs.js │ │ │ ├── bootstrap-datetimepicker.da.js │ │ │ ├── bootstrap-datetimepicker.de.js │ │ │ ├── bootstrap-datetimepicker.ee.js │ │ │ ├── bootstrap-datetimepicker.el.js │ │ │ ├── bootstrap-datetimepicker.es.js │ │ │ ├── bootstrap-datetimepicker.fi.js │ │ │ ├── bootstrap-datetimepicker.fr.js │ │ │ ├── bootstrap-datetimepicker.he.js │ │ │ ├── bootstrap-datetimepicker.hr.js │ │ │ ├── bootstrap-datetimepicker.hu.js │ │ │ ├── bootstrap-datetimepicker.id.js │ │ │ ├── bootstrap-datetimepicker.is.js │ │ │ ├── bootstrap-datetimepicker.it.js │ │ │ ├── bootstrap-datetimepicker.ja.js │ │ │ ├── bootstrap-datetimepicker.ko.js │ │ │ ├── bootstrap-datetimepicker.lt.js │ │ │ ├── bootstrap-datetimepicker.lv.js │ │ │ ├── bootstrap-datetimepicker.ms.js │ │ │ ├── bootstrap-datetimepicker.nb.js │ │ │ ├── bootstrap-datetimepicker.nl.js │ │ │ ├── bootstrap-datetimepicker.no.js │ │ │ ├── bootstrap-datetimepicker.pl.js │ │ │ ├── bootstrap-datetimepicker.pt-BR.js │ │ │ ├── bootstrap-datetimepicker.pt.js │ │ │ ├── bootstrap-datetimepicker.ro.js │ │ │ ├── bootstrap-datetimepicker.rs-latin.js │ │ │ ├── bootstrap-datetimepicker.rs.js │ │ │ ├── bootstrap-datetimepicker.ru.js │ │ │ ├── bootstrap-datetimepicker.sk.js │ │ │ ├── bootstrap-datetimepicker.sl.js │ │ │ ├── bootstrap-datetimepicker.sv.js │ │ │ ├── bootstrap-datetimepicker.sw.js │ │ │ ├── bootstrap-datetimepicker.th.js │ │ │ ├── bootstrap-datetimepicker.tr.js │ │ │ ├── bootstrap-datetimepicker.ua.js │ │ │ ├── bootstrap-datetimepicker.uk.js │ │ │ ├── bootstrap-datetimepicker.zh-CN.js │ │ │ └── bootstrap-datetimepicker.zh-TW.js │ ├── files │ │ ├── Carta de consentimiento informado.pdf │ │ └── Letter of informed consent.pdf │ ├── leaflet │ │ └── plugins │ │ │ ├── extra-markers │ │ │ ├── css │ │ │ │ └── leaflet.extra-markers.min.css │ │ │ ├── img │ │ │ │ ├── markers_default.png │ │ │ │ ├── markers_default@2x.png │ │ │ │ ├── markers_shadow.png │ │ │ │ └── markers_shadow@2x.png │ │ │ └── js │ │ │ │ └── leaflet.extra-markers.min.js │ │ │ ├── leaflet-heatmap │ │ │ ├── heatmap.min.js │ │ │ └── leaflet-heatmap.js │ │ │ └── usermarker │ │ │ ├── LICENSE │ │ │ ├── img │ │ │ └── bluedot.png │ │ │ ├── leaflet.usermarker.css │ │ │ └── leaflet.usermarker.js │ └── mapApp │ │ ├── css │ │ ├── about.css │ │ ├── barchart.css │ │ ├── common.css │ │ ├── edit_hazards.css │ │ ├── forms.css │ │ ├── index.css │ │ ├── recentReports.css │ │ └── vis.css │ │ ├── data │ │ ├── icbcBike.csv │ │ ├── icbcData.geojson │ │ ├── policeData.geojson │ │ ├── toolkit.zip │ │ └── vpdBike.csv │ │ ├── font │ │ ├── faktos.regular.ttf │ │ ├── faktos.regular.woff │ │ └── timeburner_regular.ttf │ │ ├── images │ │ ├── 5788_TIRF_BikeMapsORG_Logo_ART_OL.PDF │ │ ├── App Store Badge │ │ │ ├── App Store Marketing Getting Started Guide.pdf │ │ │ ├── Print EPS │ │ │ │ └── Download_on_the_App_Store_Badge_US-UK_135x40.eps │ │ │ └── Web SVG │ │ │ │ └── Download_on_the_App_Store_Badge_US-UK_135x40.svg │ │ ├── BikeMapsORG_Logo.ico │ │ ├── BikeMapsORG_Logo.jpg │ │ ├── BikeMapsORG_Logo.png │ │ ├── BikeMapsORG_Logo.xcf │ │ ├── BikeMapsORG_Logo_notxt.png │ │ ├── BikeMapsORG_Logo_notxt_sm.png │ │ ├── BikeMapsSocialMediaLogo.jpg │ │ ├── BikeMapsSocialMediaLogo.png │ │ ├── BikeMapsSocialMediaLogoFB.jpg │ │ ├── BikeMapsTwitterLogo.jpg │ │ ├── BikeMapsTwitterLogo.png │ │ ├── BikeMaps_French_crop_sm.png │ │ ├── WalkRollMapLogo.png │ │ ├── bespoke_logo_215.png │ │ ├── bike near miss.png │ │ ├── bike_crash.png │ │ ├── bikemaps.org.pdf │ │ ├── custom_icons │ │ │ ├── collision_icon.png │ │ │ └── nearmiss_icon.png │ │ ├── geocoder_alt.png │ │ ├── googleButton.png │ │ ├── sponsorLogos │ │ │ ├── BCCC.png │ │ │ ├── BikeBridge-Logo-03-left-e1281156539228.png │ │ │ ├── CAA.svg │ │ │ ├── CRDlogo.jpg │ │ │ ├── Capital-Bike.png │ │ │ ├── HUB.png │ │ │ ├── Mitacs.jpg │ │ │ ├── NSERC.png │ │ │ ├── PHAC.png │ │ │ ├── Pedalheads-logo.jpg │ │ │ ├── SPAR_logo2_transparent.png │ │ │ ├── SPAR_logo_transparent.png │ │ │ ├── Saanich_Police_logo.png │ │ │ ├── TIRF.jpg │ │ │ ├── UC_Santa_Barbara_Wordmark_Navy_RGB.png │ │ │ ├── UKM.jpg │ │ │ ├── affinity_bridge.png │ │ │ ├── bunt.jpg │ │ │ ├── kidical_mass1.gif │ │ │ ├── saanich_logo.jpg │ │ │ ├── saferroadsOttawa.png │ │ │ ├── strava.jpg │ │ │ ├── uvic-logo.jpg │ │ │ └── victoria.gif │ │ ├── team_photos │ │ │ ├── Colin.jpg │ │ │ ├── Jeneva.jpg │ │ │ ├── Thumbs.db │ │ │ ├── ben.jpg │ │ │ ├── dan.jpg │ │ │ ├── darren.jpg │ │ │ ├── finn.jpg │ │ │ ├── heather.jpg │ │ │ ├── jaimy.jpg │ │ │ ├── karen.jpg │ │ │ ├── meghan.jpg │ │ │ ├── michael.jpg │ │ │ ├── moreno.jpg │ │ │ ├── taylor.jpg │ │ │ └── trisalyn.jpg │ │ ├── updates │ │ │ ├── Piechartnov14.jpg │ │ │ ├── countries.jpg │ │ │ ├── fatalityrates.jpg │ │ │ └── hotspots.jpg │ │ └── url_logo.xcf │ │ └── js │ │ ├── csrfheader.js │ │ ├── edit_hazards.js │ │ ├── geofence │ │ ├── US_Boundary.js │ │ └── outTurf.js │ │ ├── icons.js │ │ ├── index-helpers.js │ │ ├── index.js │ │ ├── legend_collapse.js │ │ ├── map.js │ │ ├── override.js │ │ ├── recentReports.js │ │ └── vis │ │ ├── map.js │ │ ├── vis.js │ │ └── visHelpers.js ├── templates │ └── mapApp │ │ ├── about.html │ │ ├── base.html │ │ ├── disclaimer.html │ │ ├── edit_hazards.html │ │ ├── ethics.html │ │ ├── incident_form.html │ │ ├── index.html │ │ ├── map_legend.html │ │ ├── navbar.html │ │ ├── overlays.html │ │ ├── recent_reports.html │ │ ├── util │ │ ├── bootstrap3_datepicker.html │ │ ├── bootstrap3_datepicker_future.html │ │ ├── draw.html │ │ └── tips.html │ │ └── vis.html ├── templatetags │ ├── __init__.py │ └── bikemaps_tags.py ├── tests.py ├── urls.py ├── utils │ ├── __init__.py │ ├── geofenceHelpers.py │ ├── geofencePolygonsHazards.py │ ├── geofencePolygonsRaffle.py │ ├── weather.py │ └── weather4all.py └── views │ ├── __init__.py │ ├── about.py │ ├── alerts.py │ ├── disclaimer.py │ ├── edit.py │ ├── index.py │ ├── postPoint.py │ ├── pushNotification.py │ ├── recentReports.py │ ├── restApi.py │ ├── termsAndConditions.py │ └── vis.py ├── media └── mapApp │ ├── collision_teardrop.png │ └── nearmiss_teardrop.png ├── middlewares ├── __init__.py └── force_default_middleware.py ├── requirements.txt ├── spirit ├── __init__.py ├── locale │ ├── da │ │ └── LC_MESSAGES │ │ │ └── django.mo │ ├── de │ │ └── LC_MESSAGES │ │ │ ├── django.mo │ │ │ └── django.po │ ├── en │ │ └── LC_MESSAGES │ │ │ ├── django.mo │ │ │ └── django.po │ ├── es │ │ └── LC_MESSAGES │ │ │ ├── django.mo │ │ │ └── django.po │ ├── fi │ │ └── LC_MESSAGES │ │ │ ├── django.mo │ │ │ └── django.po │ ├── fr │ │ └── LC_MESSAGES │ │ │ ├── django.mo │ │ │ └── django.po │ ├── is │ │ └── LC_MESSAGES │ │ │ └── django.mo │ └── nl │ │ └── LC_MESSAGES │ │ ├── django.mo │ │ └── django.po ├── migrations │ ├── 0001_initial.py │ └── __init__.py ├── models │ ├── __init__.py │ └── user.py └── utils │ ├── __init__.py │ ├── decorators.py │ ├── forms.py │ ├── markdown │ ├── __init__.py │ ├── audio.py │ ├── emoji.py │ ├── image.py │ ├── mention.py │ ├── quote.py │ ├── video.py │ ├── vimeo.py │ └── youtube.py │ ├── models.py │ ├── paginator │ ├── __init__.py │ ├── infinite_paginator.py │ └── yt_paginator.py │ ├── ratelimit │ ├── __init__.py │ ├── decorators.py │ └── ratelimit.py │ ├── timezone.py │ ├── user │ ├── __init__.py │ ├── email.py │ └── tokens.py │ └── widgets.py ├── templates ├── admin │ ├── base_site.html │ ├── index.html │ └── login.html └── robots.txt ├── userApp ├── __init__.py ├── admin.py ├── forms.py ├── locale │ ├── da │ │ └── LC_MESSAGES │ │ │ └── django.mo │ ├── de │ │ └── LC_MESSAGES │ │ │ ├── django.mo │ │ │ └── django.po │ ├── en │ │ └── LC_MESSAGES │ │ │ ├── django.mo │ │ │ └── django.po │ ├── es │ │ └── LC_MESSAGES │ │ │ └── django.mo │ ├── fi │ │ └── LC_MESSAGES │ │ │ ├── django.mo │ │ │ └── django.po │ ├── fr │ │ └── LC_MESSAGES │ │ │ ├── django.mo │ │ │ └── django.po │ ├── is │ │ └── LC_MESSAGES │ │ │ └── django.mo │ └── nl │ │ └── LC_MESSAGES │ │ ├── django.mo │ │ └── django.po ├── migrations │ └── __init__.py ├── models.py ├── static │ └── userApp │ │ └── css │ │ └── profile.css ├── templates │ └── userApp │ │ ├── logged_out.html │ │ ├── login.html │ │ ├── password_change_done.html │ │ ├── password_change_form.html │ │ ├── password_reset_complete.html │ │ ├── password_reset_confirm.html │ │ ├── password_reset_done.html │ │ ├── password_reset_email.html │ │ ├── password_reset_form.html │ │ ├── profile.html │ │ ├── rate_limited.html │ │ └── register.html ├── tests.py ├── urls.py ├── utils │ ├── __init__.py │ └── recaptcha.py └── views.py └── utils ├── __init__.py └── management ├── __init__.py └── commands ├── __init__.py └── clearcache.py /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # See https://help.github.com/articles/ignoring-files for more about ignoring files. 3 | # 4 | # If you find yourself ignoring temporary files generated by your text editor 5 | # or operating system, you probably want to add a global ignore instead: 6 | # git config --global core.excludesfile '~/.gitignore_global' 7 | 8 | # Ignore data folder 9 | /data 10 | 11 | # Ignore compiled python files 12 | *.pyc 13 | */settings/prod.py 14 | /static/ 15 | /media/blogApp/ 16 | /.idea 17 | .DS_store 18 | *.po 19 | *.po 20 | *.po 21 | *.po 22 | blogApp/locale/de/LC_MESSAGES/django.po 23 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 BikeMaps.org 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | BikeMaps 2 | ========= 3 | [http://bikemaps.org] 4 | 5 | ### A [SPARLab](https://www.sparlab.org/) project. 6 | A database driven webapp that allows users to submit cycling collisions, near misses, hazards, and thefts. Data is analyzed to detect areas/routes with high traffic and rates of incidents. 7 | 8 | ##### Dependencies 9 | + Python 3.6 10 | + Postgres 13 + PostGIS 11 | + psycopg2 2.8.6 12 | + Django 3.1.7 13 | 14 | ##### Quick Set Up 15 | The development settings require a Postgres database called "bikeDB" accessible by user "postgres" that is not password protected. Be sure to add the postGIS extension. From the terminal, run: 16 | ``` 17 | createdb -U postgres bikeDB 18 | psql -U postgres -d bikeDB -c "CREATE EXTENSION postgis;" 19 | ``` 20 | 21 | Syncing the tables from the Django app requires running 22 | ``` 23 | ./manage.py makemigrations 24 | ./manage.py migrate 25 | ``` 26 | 27 | A full list of required python packages can be found in requirements.txt and can be installed via pip 28 | `pip install -r requirements.txt` 29 | 30 | If all dependencies have been met, running `./manage.py runserver` should start the development server at 127.0.0.1:8000 31 | 32 | _Note: There are additional requirements for serving this application in a production setting, and the relevant Django documentation should be consulted in this scenario. This repo does not provide production settings for security reasons._ 33 | 34 | ##### Detailed Set Up 35 | For a more in depth tutorial on setting up the project, please refer to this [additional documentation](docs/set-up-project-mac.md). 36 | 37 | ##### Data Output 38 | 39 | For a more in depth tutorial on querying and exporting data, please refer to the [additional documentation](docs/query-and-export-data.md). 40 | 41 | 42 | ##### People 43 | + Dr. Trisalyn Nelson (Project Lead) 44 | + Karen Laberee (Executive Director) 45 | + Finn Short (Developer) 46 | + Darren Boss (Developer) 47 | + Taylor Denouden (Developer) 48 | -------------------------------------------------------------------------------- /TODO.txt: -------------------------------------------------------------------------------- 1 | ##### TO DO 2 | 3 | ### GENERAL SITE UPDATES 4 | # HIGHER PRIORITY 5 | * Track down memory/DOM issues causing site load problems 6 | * Fix ICBC loading problems 7 | * Serve some pages over http to get around unsafe site resources warnings (do during new server setup since this will have to be configured then anyway) 8 | * Colour report buttons / make them more obvious 9 | * Cleanup index.html code 10 | * Hide expired hazards on the visualization page 11 | * Include and flag expired/fixed hazards in the api 12 | 13 | # LOWER PRIORITY 14 | * Open311 data sharing 15 | * Display open street map (OSM) bike lanes and bike racks on main map 16 | * Automate monthly emails of stats page 17 | * Option to report for different person 18 | * OAuth2 (Facebook Google+) login options 19 | * opt in for emails (double opt in if possible) 20 | * Search engine optimization ie keywords as meta tags? 21 | * Documentation for future devs 22 | * Make use of AJAX to prevent unnecessary page redirects (eg when submitting a point, eliminate redirect to index page) 23 | * Intersection search 24 | * Alert emails to include graphics 25 | * Improve search (text hard to read, Android problems?) 26 | 27 | 28 | ### HAZARDS MODEL UPDATES 29 | * Severity rating 30 | * Short term hazards auto resolve and removed from map (ie weather hazards disappear after 1 day) 31 | * Long term hazards (eg road condition) can be removed by privileged users (eg municipal workers) 32 | * Remove injury field 33 | 34 | 35 | ### MOBILE WISH LIST 36 | * Hazard photos (mobile app) 37 | * Route tracking (mobile app) 38 | * Safest route finding algorithm and visualization 39 | 40 | 41 | ### BUGS 42 | * Broken modal popups on some browsers 43 | * Date picker does not scroll with modal (bind to something?) 44 | * Some users reporting blank screen on browsing to site (Probably a non-webkit browser issue that can't be fixed without updating browser/OS older than Windows XP, display error message) 45 | -------------------------------------------------------------------------------- /VicBikeMap/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/VicBikeMap/__init__.py -------------------------------------------------------------------------------- /VicBikeMap/settings/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/VicBikeMap/settings/__init__.py -------------------------------------------------------------------------------- /VicBikeMap/urls.py: -------------------------------------------------------------------------------- 1 | import certbot_django.server.urls 2 | from django.conf import settings 3 | from django.conf.urls import include, url 4 | from django.conf.urls.i18n import i18n_patterns 5 | from django.contrib import admin 6 | from django.views import static 7 | from django.views.generic.base import TemplateView 8 | from django.views.i18n import JavaScriptCatalog 9 | from rest_framework.authtoken import views as auth_views 10 | 11 | admin.autodiscover() 12 | js_info_dict = { 13 | 'domain': "djangojs", 14 | 'packages': ('BikeMaps','mapApp',), 15 | } 16 | 17 | 18 | urlpatterns = [ 19 | url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework')), 20 | url(r'^api-token-auth/', auth_views.obtain_auth_token), 21 | url(r'^rest-auth/', include('rest_auth.urls')), 22 | url(r'^rest-auth/registration/', include('rest_auth.registration.urls')), 23 | url(r'^accounts/', include('allauth.urls')), 24 | url(r'^accounts/', include('django.contrib.auth.urls')), 25 | url(r'^admin/', admin.site.urls), 26 | url(r'^robots.txt$', TemplateView.as_view(template_name='robots.txt', content_type='text/plain')), 27 | url(r'^jsi18n/$', JavaScriptCatalog.as_view(), name='javascript-catalog'), 28 | url(r'^\.well-known/', include(certbot_django.server.urls)), 29 | ] 30 | 31 | # # Add internationalization url patters to these pages 32 | urlpatterns += i18n_patterns( 33 | url(r'^', include(('mapApp.urls', '/'), namespace="mapApp")), 34 | url(r'^user/', include(('userApp.urls', 'user'), namespace="userApp")), 35 | url(r'^blog/', include(('blogApp.urls', 'blog'), namespace="blogApp")), 36 | url(r'^jsi18n/$', JavaScriptCatalog.as_view(), name='javascript-catalog'), 37 | prefix_default_language=False 38 | ) 39 | 40 | if settings.DEBUG: 41 | import debug_toolbar 42 | urlpatterns += [ 43 | url(r'^__debug__/', include(debug_toolbar.urls)), 44 | url(r'^media/(?P.*)$', static.serve, {'document_root': settings.MEDIA_ROOT, 'show_indexes':True}), 45 | ] 46 | -------------------------------------------------------------------------------- /VicBikeMap/wsgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for VicBikeMap project. 3 | 4 | It exposes the WSGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/1.6/howto/deployment/wsgi/ 8 | """ 9 | 10 | import os 11 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "VicBikeMap.settings.prod") 12 | os.environ['HTTPS'] = "on" 13 | 14 | from django.core.wsgi import get_wsgi_application 15 | application = get_wsgi_application() 16 | -------------------------------------------------------------------------------- /blogApp/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/blogApp/__init__.py -------------------------------------------------------------------------------- /blogApp/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | 3 | # Register your models here. 4 | from blogApp.models import Post 5 | admin.site.register(Post) 6 | -------------------------------------------------------------------------------- /blogApp/forms/__init__.py: -------------------------------------------------------------------------------- 1 | __author__ = 'Admin' 2 | 3 | from .post import BlogPostForm 4 | from .upload_image import UploadImageForm 5 | -------------------------------------------------------------------------------- /blogApp/forms/post.py: -------------------------------------------------------------------------------- 1 | from django.utils.translation import gettext_lazy as _ 2 | from django.utils.translation import gettext_lazy as trans 3 | from django import forms 4 | 5 | from crispy_forms.helper import FormHelper 6 | from crispy_forms.bootstrap import FormActions, Div 7 | from crispy_forms.layout import Layout, Field, HTML, Button, Submit, Reset 8 | 9 | from blogApp.models import Post 10 | 11 | class BlogPostForm(forms.ModelForm): 12 | helper = FormHelper() 13 | # helper.form_tag = False 14 | 15 | helper.layout = Layout( 16 | _('Create a blog post'), 17 | Field('published'), 18 | Field('title'), 19 | Field('description'), 20 | Field('post_date'), 21 | Field('language'), 22 | Field('content'), 23 | Div( 24 | HTML(""" 25 |
26 | 27 | 28 | 29 | 30 | 31 |
32 | """.format(trans("Insert italics code"), trans("Insert bold text code"), trans("Insert a list item"), trans("Insert a link"), trans("Upload picture"))), 33 | css_class="pull-left" 34 | ), 35 | Div( 36 | FormActions( 37 | Submit('save', _('Save')), 38 | ), 39 | css_class="pull-right" 40 | ), 41 | ) 42 | 43 | class Meta: 44 | model = Post 45 | fields = '__all__' 46 | -------------------------------------------------------------------------------- /blogApp/forms/upload_image.py: -------------------------------------------------------------------------------- 1 | from django.utils.translation import gettext_lazy as _ 2 | from django.utils.translation import gettext as trans 3 | from django import forms 4 | 5 | from crispy_forms.helper import FormHelper 6 | from crispy_forms.bootstrap import FormActions, Div, AppendedText 7 | from crispy_forms.layout import Layout, Field, HTML, Button, Submit, Reset 8 | 9 | class UploadImageForm(forms.Form): 10 | helper = FormHelper() 11 | helper.form_tag = False 12 | helper.form_class = 'form-horizontal' 13 | helper.label_class = 'col-xs-3' 14 | helper.field_class = 'col-xs-9' 15 | 16 | title = forms.CharField( 17 | label = _("Alt. Title"), 18 | required = True, 19 | max_length=50, 20 | ) 21 | 22 | image = forms.FileField( 23 | label = "Image", 24 | required = True, 25 | ) 26 | 27 | resize = forms.IntegerField( 28 | label = _("Resize to this width or height"), 29 | initial = 1000, 30 | required = True, 31 | ) 32 | 33 | helper.layout = Layout( 34 | Field('title'), 35 | Field('image'), 36 | # Translators: This is the shortform for pixels 37 | AppendedText('resize', _('px')), 38 | 39 | Div( 40 | FormActions( 41 | HTML(''.format(trans('Close'))), 42 | Submit('save', _('Upload')), 43 | ), 44 | css_class="modal-footer" 45 | ), 46 | 47 | ) 48 | -------------------------------------------------------------------------------- /blogApp/locale/da/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/blogApp/locale/da/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /blogApp/locale/de/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/blogApp/locale/de/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /blogApp/locale/en/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/blogApp/locale/en/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /blogApp/locale/es/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/blogApp/locale/es/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /blogApp/locale/fi/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/blogApp/locale/fi/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /blogApp/locale/fr/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/blogApp/locale/fr/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /blogApp/locale/is/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/blogApp/locale/is/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /blogApp/locale/nl/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/blogApp/locale/nl/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /blogApp/migrations/0001_initial.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.2 on 2021-02-12 20:58 2 | 3 | import datetime 4 | from django.db import migrations, models 5 | 6 | 7 | class Migration(migrations.Migration): 8 | 9 | initial = True 10 | 11 | dependencies = [ 12 | ] 13 | 14 | operations = [ 15 | migrations.CreateModel( 16 | name='Post', 17 | fields=[ 18 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 19 | ('date', models.DateTimeField(auto_now_add=True, verbose_name='Date created')), 20 | ('title', models.CharField(max_length=100, verbose_name='Title')), 21 | ('description', models.CharField(max_length=300, verbose_name='Description')), 22 | ('post_date', models.DateTimeField(default=datetime.datetime.now, verbose_name='Date posted')), 23 | ('slug', models.SlugField(blank=True, max_length=100, unique=True, unique_for_date='created', verbose_name='Slug')), 24 | ('published', models.BooleanField(default=False, verbose_name='Published')), 25 | ('content', models.TextField(blank=True, verbose_name='Content')), 26 | ('language', models.CharField(choices=[('en', 'English'), ('fr', 'French')], default='en', max_length=50, verbose_name='Language')), 27 | ], 28 | ), 29 | ] 30 | -------------------------------------------------------------------------------- /blogApp/migrations/0002_auto_20220118_1545.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 3.1.7 on 2022-01-18 15:45 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('blogApp', '0001_initial'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AlterField( 14 | model_name='post', 15 | name='slug', 16 | field=models.SlugField(blank=True, max_length=100, unique=True, unique_for_date='date', verbose_name='Slug'), 17 | ), 18 | ] 19 | -------------------------------------------------------------------------------- /blogApp/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/blogApp/migrations/__init__.py -------------------------------------------------------------------------------- /blogApp/models/__init__.py: -------------------------------------------------------------------------------- 1 | from .post import Post 2 | -------------------------------------------------------------------------------- /blogApp/models/post.py: -------------------------------------------------------------------------------- 1 | from django.utils.translation import gettext_lazy as _ 2 | from django.template.defaultfilters import slugify 3 | from django.urls import reverse 4 | 5 | from django.db import models 6 | from blogApp.utils import hash62 7 | from datetime import datetime 8 | 9 | # Create your models here. 10 | 11 | 12 | ########## 13 | # Blog Post class. 14 | # Main class for blog posts. 15 | class Post(models.Model): 16 | LANGUAGE_CHOICES = ( 17 | ('en', _('English')), 18 | ('fr', _('French')) 19 | ) 20 | 21 | date = models.DateTimeField(_('Date created'), auto_now_add=True) 22 | 23 | title = models.CharField(_('Title'), max_length=100) 24 | description = models.CharField(_('Description'), max_length=300) 25 | post_date = models.DateTimeField(_('Date posted'), default=datetime.now) 26 | slug = models.SlugField( 27 | _('Slug'), unique=True, blank=True, max_length=100, unique_for_date='date') 28 | published = models.BooleanField(_('Published'), default=False) 29 | content = models.TextField(_('Content'), blank=True) 30 | language = models.CharField( 31 | _('Language'), 32 | max_length=50, 33 | choices=LANGUAGE_CHOICES, 34 | default='en' 35 | ) 36 | 37 | 38 | def get_absolute_url(self): 39 | return reverse('blogApp:view_post', kwargs={'slug': self.slug}) 40 | 41 | def get_short_url(self): 42 | return reverse('blogApp:short_url_redirect', kwargs={'s62': hash62.hash(self.id)}) 43 | 44 | def save(self, *args, **kwargs): 45 | self.slug = slugify(self.title) 46 | super(Post, self).save(*args, **kwargs) 47 | 48 | # toString() 49 | def __unicode__(self): 50 | return str(self.title) 51 | 52 | def __str__(self): 53 | return str(self.title) 54 | 55 | class Meta: 56 | app_label = 'blogApp' 57 | -------------------------------------------------------------------------------- /blogApp/static/blogApp/css/create.css: -------------------------------------------------------------------------------- 1 | .row{ 2 | margin-top: 25px; 3 | } 4 | #upload-image-form .form-group { 5 | height: 50px; 6 | } 7 | #upload-image-form .modal-body { 8 | padding-bottom: 0px; 9 | } 10 | -------------------------------------------------------------------------------- /blogApp/static/blogApp/css/post.css: -------------------------------------------------------------------------------- 1 | #post-title a{ 2 | color: #2c3e50; 3 | } 4 | .container { 5 | min-height:100%; 6 | position:relative; 7 | } 8 | .list-group { 9 | padding:10px; 10 | padding-bottom:60px; /* Height of the footer */ 11 | } 12 | #footer { 13 | position:absolute; 14 | bottom:0; 15 | width:100%; 16 | height:60px; /* Height of the footer */ 17 | /*background:#6cf;*/ 18 | } 19 | h1 a, 20 | h1 a:focus, 21 | h1 a:hover{ 22 | color: #2c3e50; 23 | } 24 | 25 | .fb-like span { 26 | /*top: -5px;*/ 27 | margin-left: 15px; 28 | } 29 | 30 | .share-btns{ 31 | padding-top: 8px; 32 | padding-bottom: 5px; 33 | 34 | border-top: thin solid #b4bcc2; 35 | border-bottom: thin solid #b4bcc2; 36 | 37 | margin-bottom: 15px; 38 | } 39 | -------------------------------------------------------------------------------- /blogApp/static/blogApp/js/post.js: -------------------------------------------------------------------------------- 1 | $(function(){ 2 | $('.post-content img').addClass('img-responsive'); 3 | $('.post-content').removeClass('hidden'); 4 | 5 | }) 6 | -------------------------------------------------------------------------------- /blogApp/templates/blogApp/base_blog.html: -------------------------------------------------------------------------------- 1 | {% extends "mapApp/base.html" %} 2 | {% block title %}BikeMaps Blog{% endblock %} 3 | 4 | {% load static markdown_deux_tags %} 5 | {% load i18n %} 6 | 7 | 8 | {% block headerCSS %} 9 | 10 | {% endblock %} 11 | 12 | 13 | {% block body %} 14 | 15 |
16 | 24 | 25 | 26 |
27 | 28 |
29 | 38 | 39 | {% block base_post_header %}{% endblock %} 40 |
41 | 42 | 43 | {% block base_post_body %}{% endblock %} 44 | 45 | 46 | 49 | 50 |
51 | {% endblock %} 52 | 53 | 54 | {% block footerJS %} 55 | 56 | 57 | {% endblock %} 58 | -------------------------------------------------------------------------------- /blogApp/templates/blogApp/index.html: -------------------------------------------------------------------------------- 1 | {% extends "blogApp/base_blog.html" %} 2 | {% load i18n cache %} 3 | {% get_current_language as LANGUAGE_CODE %} 4 | 5 | {% cache 30 blog_index_template LANGUAGE_CODE request.user.is_superuser %} 6 | {% block title %}{% trans "BikeMaps Blog" %}{% endblock %} 7 | 8 | {% block base_post_body %} 9 | 10 | 22 | {% endblock %} 23 | 24 | 25 | {% block base_post_footer %} 26 | 27 |
28 | {% if posts.has_previous %} 29 | 30 | {% trans "Newer posts" context "Next page link" %} 31 | 32 | {% endif %} 33 | 34 | {% if posts.has_next %} 35 | 36 | {% trans "Older posts" context "Previous page link" %} 37 | 38 | {% endif %} 39 |
40 | {% endblock %} 41 | {% endcache %} 42 | -------------------------------------------------------------------------------- /blogApp/templates/blogApp/view_post.html: -------------------------------------------------------------------------------- 1 | {% extends "blogApp/base_blog.html" %} 2 | {% load static %} 3 | 4 | {% block title %}{{ post.title }}{% endblock %} 5 | 6 | {% block headerCSS %} 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | {% endblock %} 27 | 28 | {% block base_post_body %} 29 | 44 | {% endblock %} 45 | -------------------------------------------------------------------------------- /blogApp/urls.py: -------------------------------------------------------------------------------- 1 | from django.conf.urls import url 2 | from blogApp import views 3 | 4 | urlpatterns = [ 5 | url(r'^$', views.index, name='index'), 6 | url(r'^post/(?P[\w\-]+)$', views.view_post, name='view_post'), 7 | url(r'^p/(?P[\w]+)$', views.short_url_redirect, name='short_url_redirect'), 8 | url(r'^create/$', views.create_post, name='create_post'), 9 | url(r'^edit/(?P[\w\-]+)$', views.edit_post, name='edit_post'), 10 | url(r'^upload_image/$', views.upload_image, name='upload_image'), 11 | ] 12 | -------------------------------------------------------------------------------- /blogApp/utils/__init__.py: -------------------------------------------------------------------------------- 1 | from .hash62 import * 2 | -------------------------------------------------------------------------------- /blogApp/utils/hash62.py: -------------------------------------------------------------------------------- 1 | ALPHA62 = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" 2 | 3 | def hash(i10): 4 | """ Convert a base-10 integer into a base-62 integer and return the string """ 5 | if i10 == 0: 6 | return ALPHA62[0] 7 | digits = [] 8 | base = len(ALPHA62) 9 | while i10: 10 | i10, rem = divmod(i10, base) 11 | digits.append(ALPHA62[rem]) 12 | digits.reverse() 13 | return ''.join(digits) 14 | 15 | 16 | def dehash(s62): 17 | """ Convert a base-62 integer (as type:string) into a base-10 integer and return the integer """ 18 | res = 0 19 | for i, c in enumerate(s62): 20 | res += ALPHA62.index(c) * 62**i 21 | return res 22 | -------------------------------------------------------------------------------- /blogApp/views/__init__.py: -------------------------------------------------------------------------------- 1 | from .index import index 2 | from .post import view_post, short_url_redirect, create_post, edit_post 3 | from .upload_image import upload_image 4 | -------------------------------------------------------------------------------- /blogApp/views/index.py: -------------------------------------------------------------------------------- 1 | from django.shortcuts import render, get_list_or_404 2 | from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger 3 | 4 | from blogApp.models import Post 5 | 6 | from django.http import HttpResponse 7 | from django.views.decorators.clickjacking import xframe_options_exempt 8 | 9 | # import logging 10 | # logger = logging.getLogger(__name__) 11 | @xframe_options_exempt 12 | def index(request): 13 | POSTS_PER_PAGE = 5 14 | 15 | if request.user.is_superuser: 16 | post_list = Post.objects.all().order_by('-post_date') 17 | else: 18 | #post_list = Post.objects.filter(published=True).order_by('-post_date') 19 | post_list = get_Posts_By_Language_Code(request.LANGUAGE_CODE) 20 | 21 | paginator = Paginator(post_list, POSTS_PER_PAGE) 22 | 23 | page = request.GET.get('page') 24 | try: 25 | posts = paginator.page(page) 26 | except PageNotAnInteger: 27 | # If page is not an integer, deliver first page. 28 | posts = paginator.page(1) 29 | except EmptyPage: 30 | # If page is out of range, deliver last page of results. 31 | posts = paginator.page(paginator.num_pages) 32 | 33 | return render(request, 'blogApp/index.html', {'posts': posts}) 34 | 35 | def get_Posts_By_Language_Code(language_code): 36 | if language_code == 'fr': 37 | return Post.objects.filter(language='fr', published=True).order_by('-post_date') 38 | else: 39 | return Post.objects.filter(published=True).exclude(language='fr').order_by('-post_date') 40 | 41 | -------------------------------------------------------------------------------- /blogApp/views/post.py: -------------------------------------------------------------------------------- 1 | from django.utils.translation import gettext as _ 2 | from django.shortcuts import render, get_object_or_404, redirect 3 | 4 | from django.contrib.auth.decorators import user_passes_test 5 | from django.contrib import messages 6 | 7 | from blogApp.models import Post 8 | from blogApp.utils import hash62 9 | from blogApp.forms import BlogPostForm, UploadImageForm 10 | 11 | # import logging 12 | # logger = logging.getLogger(__name__) 13 | 14 | def view_post(request, slug): 15 | context = { 16 | 'post': get_object_or_404(Post, slug=slug), 17 | } 18 | 19 | return render(request, 'blogApp/view_post.html', context) 20 | 21 | def short_url_redirect(request, s62): 22 | post_id = hash62.dehash(s62) 23 | return redirect(get_object_or_404(Post, id=post_id)) 24 | 25 | 26 | @user_passes_test(lambda u: u.is_superuser) 27 | def create_post(request): 28 | if request.method == "GET": 29 | return render(request, 'blogApp/create_post.html', { 30 | 'blog_post_form': BlogPostForm(), 31 | 'image_form': UploadImageForm(), 32 | }) 33 | 34 | else: 35 | form = BlogPostForm(request.POST) 36 | 37 | if form.is_valid(): 38 | new_post = form.save() 39 | 40 | messages.success(request, _('Blog post was added.')) 41 | return redirect(new_post) 42 | 43 | else: # not valid, return errors 44 | return render(request, 'blogApp/create_post.html', { 45 | 'blog_post_form': form, 46 | 'image_form': UploadImageForm() 47 | }) 48 | 49 | 50 | @user_passes_test(lambda u: u.is_superuser) 51 | def edit_post(request, slug): 52 | instance = get_object_or_404(Post.objects.filter(slug=slug)) 53 | 54 | if request.method == "GET": return render( request, 'blogApp/create_post.html', { 55 | 'blog_post_form': BlogPostForm(instance=instance), 56 | 'image_form': UploadImageForm() 57 | }) 58 | 59 | else: 60 | form = BlogPostForm(request.POST or None, instance=instance) 61 | 62 | if form.is_valid(): 63 | new_post = form.save() 64 | 65 | messages.success(request, _('Blog post saved.')) 66 | return redirect(new_post) 67 | 68 | else: # not valid, return errors 69 | return render(request, 'blogApp/create_post.html', { 70 | 'blog_post_form': form, 71 | 'image_form': UploadImageForm() 72 | }) 73 | -------------------------------------------------------------------------------- /blogApp/views/upload_image.py: -------------------------------------------------------------------------------- 1 | from django.http import JsonResponse 2 | from django.conf import settings 3 | 4 | from django.contrib.auth.decorators import user_passes_test 5 | from django.views.decorators.http import require_POST 6 | 7 | from PIL import Image 8 | import os 9 | 10 | from blogApp.forms import UploadImageForm, BlogPostForm 11 | from crispy_forms.utils import render_crispy_form 12 | 13 | import time 14 | 15 | @user_passes_test(lambda u: u.is_superuser) 16 | @require_POST 17 | def upload_image(request): 18 | form = UploadImageForm(request.POST, request.FILES) 19 | if form.is_valid(): 20 | f = request.FILES['image'] 21 | f = _handle_uploaded_file(f, form.cleaned_data['resize']) 22 | 23 | return JsonResponse({ 24 | 'success': True, 25 | 'url': (settings.MEDIA_URL + "blogApp/" + f.name), 26 | 'title': form.cleaned_data['title'], 27 | }) 28 | 29 | else: 30 | form_html = render_crispy_form(form) 31 | return JsonResponse({'success': False, 'form_html': form_html}) 32 | 33 | 34 | def _handle_uploaded_file(f, size): 35 | im = Image.open(f) 36 | reduction = float(max(im.size)) / float(size) 37 | im = im.resize([int(x/reduction) for x in im.size]) 38 | 39 | # Include date in filename to prevent clobbering of older images 40 | name, ext = f.name.split(".") 41 | m, d, y = time.strftime("%x").split("/") 42 | f.name = "_".join([name, m, d, y]) + "." + ext 43 | 44 | with open(os.path.join(settings.MEDIA_ROOT, "blogApp", f.name), 'wb+') as destination: 45 | im.save(destination) 46 | 47 | return f 48 | -------------------------------------------------------------------------------- /locale/da/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/locale/da/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /locale/de/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/locale/de/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /locale/de/LC_MESSAGES/django.po: -------------------------------------------------------------------------------- 1 | msgid "" 2 | msgstr "" 3 | "MIME-Version: 1.0\n" 4 | "Content-Type: text/plain; charset=UTF-8\n" 5 | "Content-Transfer-Encoding: 8bit\n" 6 | "X-Generator: POEditor.com\n" 7 | "Project-Id-Version: bikemaps root\n" 8 | "Language: de\n" 9 | 10 | #: .\VicBikeMap\settings\base.py:46 11 | msgid "English" 12 | msgstr "Englisch" 13 | 14 | #: .\VicBikeMap\settings\base.py:47 15 | msgid "French" 16 | msgstr "Französisch" 17 | 18 | #: .\VicBikeMap\settings\base.py:48 19 | msgid "German" 20 | msgstr "Deutsch" 21 | 22 | #: .\VicBikeMap\settings\base.py:49 23 | msgid "Dutch" 24 | msgstr "Holländisch" 25 | 26 | #: .\VicBikeMap\settings\base.py:50 27 | msgid "Finnish" 28 | msgstr "Finnisch" 29 | 30 | #: .\templates\admin\base_site.html:4 31 | msgid "Django site admin" 32 | msgstr "Django Admin Webseite" 33 | 34 | #: .\templates\admin\base_site.html:7 35 | msgid "BikeMap Administration" 36 | msgstr "BikeMap Administration" 37 | 38 | #: .\templates\admin\index.html:21 39 | msgid "Models in the %(name)s application" 40 | msgstr "Modelle in der Anwendung" 41 | 42 | #: .\templates\admin\index.html:22 43 | msgid "%(name)s" 44 | msgstr "Name" 45 | 46 | #: .\templates\admin\index.html:34 47 | msgid "Add" 48 | msgstr "Hinzufügen" 49 | 50 | #: .\templates\admin\index.html:40 51 | msgid "Change" 52 | msgstr "Ändern" 53 | 54 | #: .\templates\admin\index.html:50 55 | msgid "You don't have permission to edit anything." 56 | msgstr "Sie haben nicht die Berechtigung etwas zu ändern." 57 | 58 | #: .\templates\admin\index.html:58 59 | msgid "Recent Actions" 60 | msgstr "Letzte Aktionen" 61 | 62 | #: .\templates\admin\index.html:59 63 | msgid "My Actions" 64 | msgstr "Meine Aktionen" 65 | 66 | #: .\templates\admin\index.html:63 67 | msgid "None available" 68 | msgstr "Nicht verfügbar" 69 | 70 | #: .\templates\admin\index.html:77 71 | msgid "Unknown content" 72 | msgstr "Unbekannter Inhalt" 73 | 74 | -------------------------------------------------------------------------------- /locale/de/LC_MESSAGES/djangojs.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/locale/de/LC_MESSAGES/djangojs.mo -------------------------------------------------------------------------------- /locale/en/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/locale/en/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /locale/en/LC_MESSAGES/django.po: -------------------------------------------------------------------------------- 1 | # SOME DESCRIPTIVE TITLE. 2 | # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER 3 | # This file is distributed under the same license as the PACKAGE package. 4 | # FIRST AUTHOR , YEAR. 5 | # 6 | #, fuzzy 7 | msgid "" 8 | msgstr "" 9 | "Project-Id-Version: PACKAGE VERSION\n" 10 | "Report-Msgid-Bugs-To: \n" 11 | "POT-Creation-Date: 2015-08-12 14:19-0700\n" 12 | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" 13 | "Last-Translator: FULL NAME \n" 14 | "Language-Team: LANGUAGE \n" 15 | "MIME-Version: 1.0\n" 16 | "Content-Type: text/plain; charset=UTF-8\n" 17 | "Content-Transfer-Encoding: 8bit\n" 18 | 19 | #: .\VicBikeMap\settings\base.py:46 20 | msgid "English" 21 | msgstr "" 22 | 23 | #: .\VicBikeMap\settings\base.py:47 24 | msgid "French" 25 | msgstr "" 26 | 27 | #: .\VicBikeMap\settings\base.py:48 28 | msgid "German" 29 | msgstr "" 30 | 31 | #: .\VicBikeMap\settings\base.py:49 32 | msgid "Dutch" 33 | msgstr "" 34 | 35 | #: .\VicBikeMap\settings\base.py:50 36 | msgid "Finnish" 37 | msgstr "" 38 | 39 | #: .\templates\admin\base_site.html:4 40 | msgid "Django site admin" 41 | msgstr "" 42 | 43 | #: .\templates\admin\base_site.html:7 44 | msgid "BikeMap Administration" 45 | msgstr "" 46 | 47 | #: .\templates\admin\index.html:21 48 | #, python-format 49 | msgid "Models in the %(name)s application" 50 | msgstr "" 51 | 52 | #: .\templates\admin\index.html:22 53 | #, python-format 54 | msgid "%(name)s" 55 | msgstr "" 56 | 57 | #: .\templates\admin\index.html:34 58 | msgid "Add" 59 | msgstr "" 60 | 61 | #: .\templates\admin\index.html:40 62 | msgid "Change" 63 | msgstr "" 64 | 65 | #: .\templates\admin\index.html:50 66 | msgid "You don't have permission to edit anything." 67 | msgstr "" 68 | 69 | #: .\templates\admin\index.html:58 70 | msgid "Recent Actions" 71 | msgstr "" 72 | 73 | #: .\templates\admin\index.html:59 74 | msgid "My Actions" 75 | msgstr "" 76 | 77 | #: .\templates\admin\index.html:63 78 | msgid "None available" 79 | msgstr "" 80 | 81 | #: .\templates\admin\index.html:77 82 | msgid "Unknown content" 83 | msgstr "" 84 | -------------------------------------------------------------------------------- /locale/en/LC_MESSAGES/djangojs.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/locale/en/LC_MESSAGES/djangojs.mo -------------------------------------------------------------------------------- /locale/es/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/locale/es/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /locale/fi/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/locale/fi/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /locale/fr/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/locale/fr/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /locale/is/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/locale/is/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /locale/nl/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/locale/nl/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /locale/nl/LC_MESSAGES/django.po: -------------------------------------------------------------------------------- 1 | # SOME DESCRIPTIVE TITLE. 2 | # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER 3 | # This file is distributed under the same license as the PACKAGE package. 4 | # FIRST AUTHOR , YEAR. 5 | # 6 | #, fuzzy 7 | msgid "" 8 | msgstr "" 9 | "Project-Id-Version: PACKAGE VERSION\n" 10 | "Report-Msgid-Bugs-To: \n" 11 | "POT-Creation-Date: 2015-08-06 11:20-0700\n" 12 | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" 13 | "Last-Translator: FULL NAME \n" 14 | "Language-Team: LANGUAGE \n" 15 | "MIME-Version: 1.0\n" 16 | "Content-Type: text/plain; charset=UTF-8\n" 17 | "Content-Transfer-Encoding: 8bit\n" 18 | "Plural-Forms: nplurals=2; plural=(n != 1);\n" 19 | 20 | #: .\VicBikeMap\settings\base.py:46 21 | msgid "English" 22 | msgstr "" 23 | 24 | #: .\VicBikeMap\settings\base.py:47 25 | msgid "French" 26 | msgstr "" 27 | 28 | #: .\VicBikeMap\settings\base.py:48 29 | msgid "German" 30 | msgstr "" 31 | 32 | #: .\VicBikeMap\settings\base.py:49 33 | msgid "Dutch" 34 | msgstr "" 35 | 36 | #: .\VicBikeMap\settings\base.py:50 37 | msgid "Finnish" 38 | msgstr "" 39 | 40 | #: .\templates\admin\base_site.html:4 41 | msgid "Django site admin" 42 | msgstr "" 43 | 44 | #: .\templates\admin\base_site.html:7 45 | msgid "BikeMap Administration" 46 | msgstr "" 47 | 48 | #: .\templates\admin\index.html:21 49 | #, python-format 50 | msgid "Models in the %(name)s application" 51 | msgstr "" 52 | 53 | #: .\templates\admin\index.html:22 54 | #, python-format 55 | msgid "%(name)s" 56 | msgstr "" 57 | 58 | #: .\templates\admin\index.html:34 59 | msgid "Add" 60 | msgstr "" 61 | 62 | #: .\templates\admin\index.html:40 63 | msgid "Change" 64 | msgstr "" 65 | 66 | #: .\templates\admin\index.html:50 67 | msgid "You don't have permission to edit anything." 68 | msgstr "" 69 | 70 | #: .\templates\admin\index.html:58 71 | msgid "Recent Actions" 72 | msgstr "" 73 | 74 | #: .\templates\admin\index.html:59 75 | msgid "My Actions" 76 | msgstr "" 77 | 78 | #: .\templates\admin\index.html:63 79 | msgid "None available" 80 | msgstr "" 81 | 82 | #: .\templates\admin\index.html:77 83 | msgid "Unknown content" 84 | msgstr "" 85 | -------------------------------------------------------------------------------- /manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import os 3 | import sys 4 | 5 | if __name__ == "__main__": 6 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "VicBikeMap.settings.dev") 7 | 8 | from django.core.management import execute_from_command_line 9 | 10 | execute_from_command_line(sys.argv) 11 | -------------------------------------------------------------------------------- /mapApp/__init__.py: -------------------------------------------------------------------------------- 1 | default_app_config = 'mapApp.apps.MapAppConfig' 2 | -------------------------------------------------------------------------------- /mapApp/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | class MapAppConfig(AppConfig): 4 | name = 'mapApp' 5 | verbose_name = "Map App" 6 | 7 | def ready(self): 8 | import mapApp.signals 9 | -------------------------------------------------------------------------------- /mapApp/fixtures/UKM_official.xml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/mapApp/fixtures/UKM_official.xml -------------------------------------------------------------------------------- /mapApp/forms/__init__.py: -------------------------------------------------------------------------------- 1 | __author__ = 'Admin' 2 | 3 | from .incident import IncidentForm 4 | from .nearmiss import NearmissForm 5 | from .hazard import HazardForm 6 | from .theft import TheftForm 7 | from .newInfrastructure import NewInfrastructureForm 8 | from .geofences import GeofenceForm 9 | from .contact import EmailForm 10 | from .edit_geom import EditForm 11 | from .edit_hazard import UpdateHazardForm 12 | -------------------------------------------------------------------------------- /mapApp/forms/edit_geom.py: -------------------------------------------------------------------------------- 1 | from django import forms 2 | 3 | # Used to send polygon info to view 4 | class EditForm(forms.Form): 5 | editPk = forms.CharField( 6 | label = "editPk", 7 | required = True, 8 | ) 9 | 10 | editType = forms.CharField( 11 | label = "editType", 12 | max_length=10, 13 | required = True, 14 | ) 15 | 16 | editGeom = forms.CharField( 17 | label = "Geom", 18 | required = False, 19 | ) 20 | 21 | objType = forms.CharField( 22 | label = "objType", 23 | required = False, 24 | ) 25 | -------------------------------------------------------------------------------- /mapApp/forms/edit_hazard.py: -------------------------------------------------------------------------------- 1 | from django import forms 2 | 3 | # Used to send polygon info to view 4 | class UpdateHazardForm(forms.Form): 5 | pk = forms.IntegerField() 6 | fixed = forms.BooleanField(required=False) 7 | -------------------------------------------------------------------------------- /mapApp/forms/geofences.py: -------------------------------------------------------------------------------- 1 | from django import forms 2 | from mapApp.models import AlertArea 3 | 4 | class GeofenceForm(forms.ModelForm): 5 | class Meta: 6 | model = AlertArea 7 | fields = ['user', 'geom', 'email'] 8 | -------------------------------------------------------------------------------- /mapApp/forms/newInfrastructure.py: -------------------------------------------------------------------------------- 1 | from django.utils.translation import ugettext_lazy as _ 2 | from django import forms 3 | 4 | from crispy_forms.helper import FormHelper 5 | from crispy_forms.layout import Layout, Field, HTML, Div 6 | from crispy_forms.bootstrap import Accordion, AccordionGroup 7 | 8 | from mapApp.models import NewInfrastructure 9 | 10 | class NewInfrastructureForm(forms.ModelForm): 11 | helper = FormHelper() 12 | helper.form_tag = False # removes auto-inclusion of form tag in template 13 | helper.disable_csrf = True 14 | 15 | helper.layout = Layout( 16 | Accordion( 17 | AccordionGroup( 18 | _('New Infrastructure Details'), 19 | Field('geom', type='hidden', id='newInfraPoint'), 20 | Field('dateAdded', id='newInfrastructure_date', template='mapApp/util/%s_datepicker.html', autocomplete='off'), 21 | Field('infra_type', id=''), 22 | Field('expires_date', id='newInfrastructure_expiresDate', template='mapApp/util/%s_datepicker_future.html', autocomplete='off'), 23 | Field('infraDetails', default='Previous reports at this location were reset.'), 24 | ), 25 | ) 26 | ) 27 | 28 | class Meta: 29 | model = NewInfrastructure 30 | exclude = ['p_type','date','details'] -------------------------------------------------------------------------------- /mapApp/locale/da/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/mapApp/locale/da/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /mapApp/locale/de/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/mapApp/locale/de/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /mapApp/locale/de/LC_MESSAGES/djangojs.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/mapApp/locale/de/LC_MESSAGES/djangojs.mo -------------------------------------------------------------------------------- /mapApp/locale/en/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/mapApp/locale/en/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /mapApp/locale/en/LC_MESSAGES/djangojs.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/mapApp/locale/en/LC_MESSAGES/djangojs.mo -------------------------------------------------------------------------------- /mapApp/locale/en/LC_MESSAGES/djangojs.po: -------------------------------------------------------------------------------- 1 | # SOME DESCRIPTIVE TITLE. 2 | # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER 3 | # This file is distributed under the same license as the PACKAGE package. 4 | # FIRST AUTHOR , YEAR. 5 | # 6 | #, fuzzy 7 | msgid "" 8 | msgstr "" 9 | "Project-Id-Version: PACKAGE VERSION\n" 10 | "Report-Msgid-Bugs-To: \n" 11 | "POT-Creation-Date: 2015-08-12 14:19-0700\n" 12 | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" 13 | "Last-Translator: FULL NAME \n" 14 | "Language-Team: LANGUAGE \n" 15 | "MIME-Version: 1.0\n" 16 | "Content-Type: text/plain; charset=UTF-8\n" 17 | "Content-Transfer-Encoding: 8bit\n" 18 | 19 | #: .\mapApp\static\mapApp\js\index.js:352 20 | msgid "Type" 21 | msgstr "" 22 | 23 | #: .\mapApp\static\mapApp\js\index.js:353 24 | msgid "Incident with" 25 | msgstr "" 26 | 27 | #: .\mapApp\static\mapApp\js\index.js:354 28 | msgid "Due to" 29 | msgstr "" 30 | 31 | #: .\mapApp\static\mapApp\js\index.js:358 32 | msgid "Hazard type" 33 | msgstr "" 34 | 35 | #: .\mapApp\static\mapApp\js\index.js:361 36 | msgid "Theft type" 37 | msgstr "" 38 | 39 | #: .\mapApp\static\mapApp\js\index.js:366 40 | msgid "Date" 41 | msgstr "" 42 | 43 | #: .\mapApp\static\mapApp\js\index.js:370 44 | msgid "Details" 45 | msgstr "" 46 | 47 | #: .\mapApp\static\mapApp\js\vis.js:6 .\mapApp\static\mapApp\js\vis.js.c:102 48 | msgid "Collisions" 49 | msgstr "" 50 | 51 | #: .\mapApp\static\mapApp\js\vis.js:7 .\mapApp\static\mapApp\js\vis.js.c:103 52 | msgid "Nearmisses" 53 | msgstr "" 54 | 55 | #: .\mapApp\static\mapApp\js\vis.js:8 .\mapApp\static\mapApp\js\vis.js.c:104 56 | msgid "Hazards" 57 | msgstr "" 58 | 59 | #: .\mapApp\static\mapApp\js\vis.js:9 .\mapApp\static\mapApp\js\vis.js.c:105 60 | msgid "Thefts" 61 | msgstr "" 62 | 63 | #: .\mapApp\static\mapApp\js\vis.js:79 .\mapApp\static\mapApp\js\vis.js.c:98 64 | #: .\mapApp\static\mapApp\js\vis.js:123 .\mapApp\static\mapApp\js\vis.js:148 65 | msgid "Count" 66 | msgstr "" 67 | -------------------------------------------------------------------------------- /mapApp/locale/es/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/mapApp/locale/es/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /mapApp/locale/es/LC_MESSAGES/djangojs.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/mapApp/locale/es/LC_MESSAGES/djangojs.mo -------------------------------------------------------------------------------- /mapApp/locale/fi/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/mapApp/locale/fi/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /mapApp/locale/fi/LC_MESSAGES/djangojs.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/mapApp/locale/fi/LC_MESSAGES/djangojs.mo -------------------------------------------------------------------------------- /mapApp/locale/fr/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/mapApp/locale/fr/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /mapApp/locale/fr/LC_MESSAGES/djangojs.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/mapApp/locale/fr/LC_MESSAGES/djangojs.mo -------------------------------------------------------------------------------- /mapApp/locale/is/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/mapApp/locale/is/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /mapApp/locale/is/LC_MESSAGES/djangojs.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/mapApp/locale/is/LC_MESSAGES/djangojs.mo -------------------------------------------------------------------------------- /mapApp/locale/nl/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/mapApp/locale/nl/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /mapApp/migrations/0003_add_ebike_fields.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 3.1.7 on 2023-04-09 18:40 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('mapApp', '0002_update_age_fields'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AddField( 14 | model_name='incident', 15 | name='ebike_class', 16 | field=models.CharField(blank=True, choices=[('Pedal assist under 20 mph', 'Pedal assist up to 20 mph (32 km/h)'), ('Throttle assist under 20 mph', 'Throttle assist up to 20 mph (32 km/h)'), ('Pedal or throttle assist over 20mph', 'Pedal or throttle assist over 20 mph (32 km/h)')], max_length=40, null=True, verbose_name='What class of e-bike were you riding?'), 17 | ), 18 | migrations.AddField( 19 | model_name='incident', 20 | name='ebike_speed', 21 | field=models.CharField(blank=True, choices=[('Under 5 mph', 'Under 5 mph (8 km/h)'), ('Between 5-20 mph', 'Between 5-20mph (8-32 km/h)'), ('Over 20 mph', 'Over 20mph (32 km/h)')], max_length=20, null=True, verbose_name='Approximately what speed was your e-bike traveling at the time?'), 22 | ), 23 | ] 24 | -------------------------------------------------------------------------------- /mapApp/migrations/0004_add_gender_fields.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 3.1.7 on 2023-04-22 13:29 2 | 3 | from django.db import migrations, models 4 | 5 | class Migration(migrations.Migration): 6 | 7 | dependencies = [ 8 | ('mapApp', '0003_add_ebike_fields'), 9 | ] 10 | 11 | operations = [ 12 | migrations.CreateModel( 13 | name='Gender', 14 | fields=[ 15 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 16 | ('value', models.CharField(max_length=10)), 17 | ('label', models.CharField(max_length=50)), 18 | ], 19 | ), 20 | migrations.AddField( 21 | model_name='point', 22 | name='gender', 23 | field=models.ManyToManyField(blank=True, to='mapApp.Gender'), 24 | ), 25 | migrations.AddField( 26 | model_name='point', 27 | name='gender_additional', 28 | field=models.TextField(blank=True, default='', max_length=100, null=True, verbose_name="If you selected 'another option', optionally describe here:"), 29 | ), 30 | ] 31 | -------------------------------------------------------------------------------- /mapApp/migrations/0005_add_gender_options.py: -------------------------------------------------------------------------------- 1 | from django.utils.translation import ugettext_lazy as _ 2 | from django.db import migrations, models 3 | from mapApp.models import Gender 4 | 5 | gender_options = [ 6 | ['F', _('Woman')], 7 | ['M', _('Man')], 8 | ['NBY', _('Non-binary')], 9 | ['GNC', _('Genderfluid or Gender nonconforming')], 10 | ['TS', _('Two-Spirit')], 11 | ['T', _('Transgender')], 12 | ['A', _('Agender')], 13 | ['P', _('Prefer not to say')], 14 | ['O', _('Another option not listed here')], 15 | ] 16 | 17 | def populate_gender_options(apps, schema_editor): 18 | for opt in gender_options: 19 | g = Gender(value=opt[0], label=opt[1]) 20 | g.save() 21 | 22 | def remove_gender_options(apps, schema_editor): 23 | for opt in gender_options: 24 | try: 25 | Gender.objects.get(value=opt[0]).delete() 26 | # Allow migration to roll back if option has already been deleted 27 | except Gender.DoesNotExist: 28 | pass 29 | 30 | class Migration(migrations.Migration): 31 | 32 | dependencies = [ 33 | ('mapApp', '0004_add_gender_fields'), 34 | ] 35 | 36 | operations = [ 37 | migrations.RunPython(populate_gender_options, remove_gender_options) 38 | ] 39 | -------------------------------------------------------------------------------- /mapApp/migrations/0006_migrate_sex_to_gender.py: -------------------------------------------------------------------------------- 1 | 2 | from django.db import migrations, models 3 | from mapApp.models import Gender, Point 4 | 5 | def move_sex_to_gender(apps, schema_editor): 6 | gender_f = Gender.objects.get(value='F') 7 | gender_m = Gender.objects.get(value='M') 8 | gender_o = Gender.objects.get(value='O') 9 | 10 | for point in Point.objects.filter(sex='F'): 11 | point.gender.add(gender_f) 12 | for point in Point.objects.filter(sex='M'): 13 | point.gender.add(gender_m) 14 | for point in Point.objects.filter(sex='Other'): 15 | point.gender.add(gender_o) 16 | 17 | class Migration(migrations.Migration): 18 | 19 | dependencies = [ 20 | ('mapApp', '0005_add_gender_options'), 21 | ] 22 | 23 | operations = [ 24 | migrations.RunPython(move_sex_to_gender, migrations.RunPython.noop) 25 | ] 26 | -------------------------------------------------------------------------------- /mapApp/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/mapApp/migrations/__init__.py -------------------------------------------------------------------------------- /mapApp/models/__init__.py: -------------------------------------------------------------------------------- 1 | from .point import Point 2 | from .gender import Gender 3 | from .incident import Incident 4 | from .hazard import Hazard 5 | from .theft import Theft 6 | from .alert_area import AlertArea, AdministrativeArea 7 | from .official import Official 8 | from .alert_notification import IncidentNotification, HazardNotification, TheftNotification 9 | from .weather import Weather 10 | from .newInfrastructure import NewInfrastructure 11 | -------------------------------------------------------------------------------- /mapApp/models/gender.py: -------------------------------------------------------------------------------- 1 | from django.contrib.gis.db import models 2 | 3 | class Gender(models.Model): 4 | value = models.CharField( 5 | blank=False, 6 | max_length=10, 7 | ) 8 | 9 | label = models.CharField( 10 | blank=False, 11 | max_length=50, 12 | ) 13 | 14 | def __str__(self): 15 | return self.value 16 | -------------------------------------------------------------------------------- /mapApp/models/newInfrastructure.py: -------------------------------------------------------------------------------- 1 | from django.utils.translation import ugettext_lazy as _ 2 | from django.conf import settings 3 | from django.contrib.gis.db import models 4 | from .point import Point 5 | 6 | import datetime 7 | 8 | ########## 9 | # New infrastructure class. 10 | # Class for New Infrastructure reports. Contains all required, non-required, and spatial fields. 11 | # Points in this class can only be added by administrators 12 | class NewInfrastructure(Point): 13 | 14 | ############ 15 | # FIELDS 16 | point = models.OneToOneField(Point, on_delete=models.CASCADE, parent_link=True) 17 | 18 | infra_type = models.CharField( 19 | _('What type of new infrastructure is it?'), 20 | max_length=150 21 | ) 22 | 23 | dateAdded = models.DateTimeField( 24 | _('When was the new infrastructure added?'), 25 | default=None 26 | ) 27 | 28 | infraDetails = models.TextField( 29 | _('Please give a brief description of the new infrastructure'), 30 | max_length=300, 31 | blank=True, 32 | null=True, 33 | default="Previously reported incidents and hazards in the area were reset." 34 | ) 35 | 36 | ################ EXPIRES AUTOREMOVE FIELDS 37 | # This field controls if a new infrastructure point should be displayed on the map 38 | expires_date = models.DateTimeField( 39 | _('When should the new infrastructure icon expire?'), 40 | blank=True, 41 | null=True 42 | ) 43 | 44 | def is_expired(self): 45 | if self.expires_date: 46 | return (datetime.datetime.now() > self.expires_date) 47 | else: 48 | return self.infrastructure_changed 49 | is_expired.boolean = True 50 | is_expired.short_description = 'Expired? (Hidden on map)' 51 | 52 | def save(self, *args, **kwargs): 53 | # Set p_type 54 | self.p_type = "newInfrastructure" 55 | self.date = self.dateAdded 56 | self.details = self.infraDetails 57 | 58 | super(NewInfrastructure, self).save(*args, **kwargs) # Call the "real" save() method. 59 | -------------------------------------------------------------------------------- /mapApp/models/official.py: -------------------------------------------------------------------------------- 1 | from django.utils.translation import ugettext_lazy as _ 2 | from django.conf import settings 3 | from django.contrib.gis.db import models 4 | from .point import Point 5 | 6 | import datetime 7 | from time import strftime, gmtime 8 | from django.utils import timezone 9 | from django.db.models import Manager as GeoManager 10 | 11 | 12 | ########## 13 | # Official class. 14 | # Class for storing official data. Contains fields that official data should be modified to fit as best as possible. 15 | class Official(models.Model): 16 | geom = models.PointField(_('Location')) 17 | objects = GeoManager() # Required to conduct geographic queries 18 | 19 | report_date = models.DateTimeField( 20 | auto_now_add=True # Date is set automatically when object created 21 | ) 22 | date = models.DateField( 23 | blank=True, 24 | null=True 25 | ) 26 | time = models.TimeField( 27 | blank=True, 28 | null=True 29 | ) 30 | 31 | p_type = models.CharField( 32 | default="official", 33 | max_length=150, 34 | ) 35 | official_type = models.CharField( 36 | default="Vehicle collision", 37 | max_length=200, 38 | ) 39 | data_source = models.CharField( 40 | max_length=200, 41 | ) 42 | metadata = models.CharField( 43 | max_length=500, 44 | ) 45 | details = models.TextField( 46 | max_length=300, 47 | blank=True, 48 | null=True 49 | ) 50 | -------------------------------------------------------------------------------- /mapApp/models/weather.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | from mapApp.models import Incident 3 | 4 | class Weather(models.Model): 5 | """ Container for all weather associated with an Incident via one-to-one field """ 6 | 7 | incident = models.OneToOneField(Incident, on_delete=models.CASCADE, primary_key=True) 8 | 9 | summary = models.CharField("Summary", max_length=250) 10 | sunrise_time = models.DateTimeField("Sunrise time") 11 | sunset_time = models.DateTimeField("Sunset time") 12 | dawn = models.BooleanField("The accident occurred at dawn") 13 | dusk = models.BooleanField("The accident occurred at dusk") 14 | precip_intensity = models.FloatField("Precipitation intensity (mm/h)") 15 | precip_probability = models.FloatField("Precipitation probability") 16 | precip_type = models.CharField("Type of precipitation", max_length=50) 17 | temperature = models.FloatField("Temperature (C)") 18 | black_ice_risk = models.BooleanField("Black ice risk present") 19 | wind_speed = models.FloatField("Wind speed (km/h)") 20 | wind_bearing = models.FloatField("Wind bearing (deg)") 21 | wind_bearing_str = models.CharField("Wind bearing", max_length=5) 22 | visibility_km = models.FloatField("Visibility (km)") 23 | 24 | # toString() 25 | def __unicode__(self): 26 | return str(self.summary) 27 | 28 | class Meta: 29 | verbose_name = "Weather" 30 | verbose_name_plural = "Weather" 31 | -------------------------------------------------------------------------------- /mapApp/permissions.py: -------------------------------------------------------------------------------- 1 | from rest_framework import permissions 2 | 3 | # Used by AlertAreaList and AlertAreaDetail classes in restApi view 4 | class IsOwnerOrReadOnly(permissions.BasePermission): 5 | """ 6 | Custom permission to only allow owners of an object to edit it. 7 | """ 8 | 9 | def has_object_permission(self, request, view, obj): 10 | # Read permissions are allowed to any request, 11 | # so we'll always allow GET, HEAD or OPTIONS requests. 12 | if request.method in permissions.SAFE_METHODS: 13 | return True 14 | 15 | # Write permissions are only allowed to the owner of the snippet. 16 | return obj.user == request.user 17 | -------------------------------------------------------------------------------- /mapApp/signals.py: -------------------------------------------------------------------------------- 1 | from django.db.models.signals import post_save 2 | from django.dispatch import receiver 3 | from django.conf import settings 4 | 5 | from mapApp.models import Incident, Weather 6 | from mapApp.utils.weather import get_weather 7 | 8 | import threading 9 | 10 | @receiver(post_save, sender=Incident) 11 | def get_weather_data(sender, **kwargs): 12 | if(kwargs.get("created") and settings.FORECAST_IO_API_KEY != 'debug'): 13 | incident = kwargs.get("instance") 14 | 15 | # Create a new Weather instance using a non-blocking thread 16 | thread = WeatherThread(incident) 17 | thread.start() 18 | 19 | class WeatherThread(threading.Thread): 20 | def __init__(self, incident): 21 | self.incident = incident 22 | super(WeatherThread, self).__init__() 23 | 24 | def run(self): 25 | data = get_weather(self.incident.geom, self.incident.date) 26 | Weather( 27 | incident = self.incident, 28 | summary = data['summary'], 29 | sunrise_time = data['sunrise_time'], 30 | sunset_time = data['sunset_time'], 31 | dawn = data['dawn'], 32 | dusk = data['dusk'], 33 | precip_intensity = data['precip_intensity'], 34 | precip_probability = data['precip_probability'], 35 | precip_type = data['precip_type'], 36 | temperature = data['temperature'], 37 | black_ice_risk = data['black_ice_risk'], 38 | wind_speed = data['wind_speed'], 39 | wind_bearing = data['wind_bearing'], 40 | wind_bearing_str = data['wind_bearing_str'], 41 | visibility_km = data['visibility_km'], 42 | ).save() 43 | -------------------------------------------------------------------------------- /mapApp/static/bootstrap/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/mapApp/static/bootstrap/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /mapApp/static/bootstrap/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/mapApp/static/bootstrap/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /mapApp/static/bootstrap/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/mapApp/static/bootstrap/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /mapApp/static/datetimepicker/js/locales/bootstrap-datetimepicker.ar.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Arabic translation for bootstrap-datetimepicker 3 | * Ala' Mohammad 4 | */ 5 | ;(function($){ 6 | $.fn.datetimepicker.dates['ar'] = { 7 | days: ["الأحد", "الاثنين", "الثلاثاء", "الأربعاء", "الخميس", "الجمعة", "السبت", "الأحد"], 8 | daysShort: ["أحد", "اثنين", "ثلاثاء", "أربعاء", "خميس", "جمعة", "سبت", "أحد"], 9 | daysMin: ["أح", "إث", "ث", "أر", "خ", "ج", "س", "أح"], 10 | months: ["يناير", "فبراير", "مارس", "أبريل", "مايو", "يونيو", "يوليو", "أغسطس", "سبتمبر", "أكتوبر", "نوفمبر", "ديسمبر"], 11 | monthsShort: ["يناير", "فبراير", "مارس", "أبريل", "مايو", "يونيو", "يوليو", "أغسطس", "سبتمبر", "أكتوبر", "نوفمبر", "ديسمبر"], 12 | today: "هذا اليوم", 13 | suffix: [], 14 | meridiem: [], 15 | rtl: true 16 | }; 17 | }(jQuery)); 18 | -------------------------------------------------------------------------------- /mapApp/static/datetimepicker/js/locales/bootstrap-datetimepicker.bg.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Bulgarian translation for bootstrap-datetimepicker 3 | * Apostol Apostolov 4 | */ 5 | ;(function($){ 6 | $.fn.datetimepicker.dates['bg'] = { 7 | days: ["Неделя", "Понеделник", "Вторник", "Сряда", "Четвъртък", "Петък", "Събота", "Неделя"], 8 | daysShort: ["Нед", "Пон", "Вто", "Сря", "Чет", "Пет", "Съб", "Нед"], 9 | daysMin: ["Н", "П", "В", "С", "Ч", "П", "С", "Н"], 10 | months: ["Януари", "Февруари", "Март", "Април", "Май", "Юни", "Юли", "Август", "Септември", "Октомври", "Ноември", "Декември"], 11 | monthsShort: ["Ян", "Фев", "Мар", "Апр", "Май", "Юни", "Юли", "Авг", "Сеп", "Окт", "Ное", "Дек"], 12 | today: "днес", 13 | suffix: [], 14 | meridiem: [] 15 | }; 16 | }(jQuery)); 17 | -------------------------------------------------------------------------------- /mapApp/static/datetimepicker/js/locales/bootstrap-datetimepicker.ca.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Catalan translation for bootstrap-datetimepicker 3 | * J. Garcia 4 | */ 5 | ;(function($){ 6 | $.fn.datetimepicker.dates['ca'] = { 7 | days: ["Diumenge", "Dilluns", "Dimarts", "Dimecres", "Dijous", "Divendres", "Dissabte", "Diumenge"], 8 | daysShort: ["Diu", "Dil", "Dmt", "Dmc", "Dij", "Div", "Dis", "Diu"], 9 | daysMin: ["dg", "dl", "dt", "dc", "dj", "dv", "ds", "dg"], 10 | months: ["Gener", "Febrer", "Març", "Abril", "Maig", "Juny", "Juliol", "Agost", "Setembre", "Octubre", "Novembre", "Desembre"], 11 | monthsShort: ["Gen", "Feb", "Mar", "Abr", "Mai", "Jun", "Jul", "Ago", "Set", "Oct", "Nov", "Des"], 12 | today: "Avui", 13 | suffix: [], 14 | meridiem: [] 15 | }; 16 | }(jQuery)); 17 | -------------------------------------------------------------------------------- /mapApp/static/datetimepicker/js/locales/bootstrap-datetimepicker.cs.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Czech translation for bootstrap-datetimepicker 3 | * Matěj Koubík 4 | * Fixes by Michal Remiš 5 | */ 6 | ;(function($){ 7 | $.fn.datetimepicker.dates['cs'] = { 8 | days: ["Neděle", "Pondělí", "Úterý", "Středa", "Čtvrtek", "Pátek", "Sobota", "Neděle"], 9 | daysShort: ["Ned", "Pon", "Úte", "Stř", "Čtv", "Pát", "Sob", "Ned"], 10 | daysMin: ["Ne", "Po", "Út", "St", "Čt", "Pá", "So", "Ne"], 11 | months: ["Leden", "Únor", "Březen", "Duben", "Květen", "Červen", "Červenec", "Srpen", "Září", "Říjen", "Listopad", "Prosinec"], 12 | monthsShort: ["Led", "Úno", "Bře", "Dub", "Kvě", "Čer", "Čnc", "Srp", "Zář", "Říj", "Lis", "Pro"], 13 | today: "Dnes", 14 | suffix: [], 15 | meridiem: [], 16 | weekStart: 1, 17 | format: "dd.mm.yyyy" 18 | }; 19 | }(jQuery)); 20 | -------------------------------------------------------------------------------- /mapApp/static/datetimepicker/js/locales/bootstrap-datetimepicker.da.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Danish translation for bootstrap-datetimepicker 3 | * Christian Pedersen 4 | */ 5 | ;(function($){ 6 | $.fn.datetimepicker.dates['da'] = { 7 | days: ["Søndag", "Mandag", "Tirsdag", "Onsdag", "Torsdag", "Fredag", "Lørdag", "Søndag"], 8 | daysShort: ["Søn", "Man", "Tir", "Ons", "Tor", "Fre", "Lør", "Søn"], 9 | daysMin: ["Sø", "Ma", "Ti", "On", "To", "Fr", "Lø", "Sø"], 10 | months: ["Januar", "Februar", "Marts", "April", "Maj", "Juni", "Juli", "August", "September", "Oktober", "November", "December"], 11 | monthsShort: ["Jan", "Feb", "Mar", "Apr", "Maj", "Jun", "Jul", "Aug", "Sep", "Okt", "Nov", "Dec"], 12 | today: "I Dag", 13 | suffix: [], 14 | meridiem: [] 15 | }; 16 | }(jQuery)); -------------------------------------------------------------------------------- /mapApp/static/datetimepicker/js/locales/bootstrap-datetimepicker.de.js: -------------------------------------------------------------------------------- 1 | /** 2 | * German translation for bootstrap-datetimepicker 3 | * Sam Zurcher 4 | */ 5 | ;(function($){ 6 | $.fn.datetimepicker.dates['de'] = { 7 | days: ["Sonntag", "Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag", "Samstag", "Sonntag"], 8 | daysShort: ["Son", "Mon", "Die", "Mit", "Don", "Fre", "Sam", "Son"], 9 | daysMin: ["So", "Mo", "Di", "Mi", "Do", "Fr", "Sa", "So"], 10 | months: ["Januar", "Februar", "März", "April", "Mai", "Juni", "Juli", "August", "September", "Oktober", "November", "Dezember"], 11 | monthsShort: ["Jan", "Feb", "Mär", "Apr", "Mai", "Jun", "Jul", "Aug", "Sep", "Okt", "Nov", "Dez"], 12 | today: "Heute", 13 | suffix: [], 14 | meridiem: [], 15 | weekStart: 1, 16 | format: "dd.mm.yyyy" 17 | }; 18 | }(jQuery)); 19 | -------------------------------------------------------------------------------- /mapApp/static/datetimepicker/js/locales/bootstrap-datetimepicker.ee.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Estonian translation for bootstrap-datetimepicker 3 | * Rene Korss 4 | */ 5 | ;(function($){ 6 | $.fn.datetimepicker.dates['ee'] = { 7 | days: ["Pühapäev", "Esmaspäev", "Teisipäev", "Kolmapäev", "Neljapäev", "Reede", "Laupäev", "Pühapäev"], 8 | daysShort: ["P", "E", "T", "K", "N", "R", "L", "P"], 9 | daysMin: ["P", "E", "T", "K", "N", "R", "L", "P"], 10 | months: ["Jaanuar", "Veebruar", "Märts", "Aprill", "Mai", "Juuni", "Juuli", "August", "September", "Oktoober", "November", "Detsember"], 11 | monthsShort: ["Jaan", "Veebr", "Märts", "Apr", "Mai", "Juuni", "Juuli", "Aug", "Sept", "Okt", "Nov", "Dets"], 12 | today: "Täna", 13 | suffix: [], 14 | meridiem: [], 15 | weekStart: 1, 16 | format: "dd.mm.yyyy hh:ii" 17 | }; 18 | }(jQuery)); -------------------------------------------------------------------------------- /mapApp/static/datetimepicker/js/locales/bootstrap-datetimepicker.el.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Greek translation for bootstrap-datetimepicker 3 | */ 4 | ;(function($){ 5 | $.fn.datetimepicker.dates['el'] = { 6 | days: ["Κυριακή", "Δευτέρα", "Τρίτη", "Τετάρτη", "Πέμπτη", "Παρασκευή", "Σάββατο", "Κυριακή"], 7 | daysShort: ["Κυρ", "Δευ", "Τρι", "Τετ", "Πεμ", "Παρ", "Σαβ", "Κυρ"], 8 | daysMin: ["Κυ", "Δε", "Τρ", "Τε", "Πε", "Πα", "Σα", "Κυ"], 9 | months: ["Ιανουάριος", "Φεβρουάριος", "Μάρτιος", "Απρίλιος", "Μάιος", "Ιούνιος", "Ιούλιος", "Αύγουστος", "Σεπτέμβριος", "Οκτώβριος", "Νοέμβριος", "Δεκέμβριος"], 10 | monthsShort: ["Ιαν", "Φεβ", "Μαρ", "Απρ", "Μάι", "Ιουν", "Ιουλ", "Αυγ", "Σεπ", "Οκτ", "Νοε", "Δεκ"], 11 | today: "Σήμερα", 12 | suffix: [], 13 | meridiem: [] 14 | }; 15 | }(jQuery)); -------------------------------------------------------------------------------- /mapApp/static/datetimepicker/js/locales/bootstrap-datetimepicker.es.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Spanish translation for bootstrap-datetimepicker 3 | * Bruno Bonamin 4 | */ 5 | ;(function($){ 6 | $.fn.datetimepicker.dates['es'] = { 7 | days: ["Domingo", "Lunes", "Martes", "Miércoles", "Jueves", "Viernes", "Sábado", "Domingo"], 8 | daysShort: ["Dom", "Lun", "Mar", "Mié", "Jue", "Vie", "Sáb", "Dom"], 9 | daysMin: ["Do", "Lu", "Ma", "Mi", "Ju", "Vi", "Sa", "Do"], 10 | months: ["Enero", "Febrero", "Marzo", "Abril", "Mayo", "Junio", "Julio", "Agosto", "Septiembre", "Octubre", "Noviembre", "Diciembre"], 11 | monthsShort: ["Ene", "Feb", "Mar", "Abr", "May", "Jun", "Jul", "Ago", "Sep", "Oct", "Nov", "Dic"], 12 | today: "Hoy", 13 | suffix: [], 14 | meridiem: [] 15 | }; 16 | }(jQuery)); 17 | -------------------------------------------------------------------------------- /mapApp/static/datetimepicker/js/locales/bootstrap-datetimepicker.fi.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Finnish translation for bootstrap-datetimepicker 3 | * Jaakko Salonen 4 | */ 5 | ;(function($){ 6 | $.fn.datetimepicker.dates['fi'] = { 7 | days: ["sunnuntai", "maanantai", "tiistai", "keskiviikko", "torstai", "perjantai", "lauantai", "sunnuntai"], 8 | daysShort: ["sun", "maa", "tii", "kes", "tor", "per", "lau", "sun"], 9 | daysMin: ["su", "ma", "ti", "ke", "to", "pe", "la", "su"], 10 | months: ["tammikuu", "helmikuu", "maaliskuu", "huhtikuu", "toukokuu", "kesäkuu", "heinäkuu", "elokuu", "syyskuu", "lokakuu", "marraskuu", "joulukuu"], 11 | monthsShort: ["tam", "hel", "maa", "huh", "tou", "kes", "hei", "elo", "syy", "lok", "mar", "jou"], 12 | today: "tänään", 13 | suffix: [], 14 | meridiem: [] 15 | }; 16 | }(jQuery)); 17 | -------------------------------------------------------------------------------- /mapApp/static/datetimepicker/js/locales/bootstrap-datetimepicker.fr.js: -------------------------------------------------------------------------------- 1 | /** 2 | * French translation for bootstrap-datetimepicker 3 | * Nico Mollet 4 | */ 5 | ;(function($){ 6 | $.fn.datetimepicker.dates['fr'] = { 7 | days: ["Dimanche", "Lundi", "Mardi", "Mercredi", "Jeudi", "Vendredi", "Samedi", "Dimanche"], 8 | daysShort: ["Dim", "Lun", "Mar", "Mer", "Jeu", "Ven", "Sam", "Dim"], 9 | daysMin: ["D", "L", "Ma", "Me", "J", "V", "S", "D"], 10 | months: ["Janvier", "Février", "Mars", "Avril", "Mai", "Juin", "Juillet", "Août", "Septembre", "Octobre", "Novembre", "Décembre"], 11 | monthsShort: ["Jan", "Fev", "Mar", "Avr", "Mai", "Jui", "Jul", "Aou", "Sep", "Oct", "Nov", "Dec"], 12 | today: "Aujourd'hui", 13 | suffix: [], 14 | meridiem: ["am", "pm"], 15 | weekStart: 1, 16 | format: "dd/mm/yyyy hh:ii" 17 | }; 18 | }(jQuery)); 19 | -------------------------------------------------------------------------------- /mapApp/static/datetimepicker/js/locales/bootstrap-datetimepicker.he.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Hebrew translation for bootstrap-datetimepicker 3 | * Sagie Maoz 4 | */ 5 | ;(function($){ 6 | $.fn.datetimepicker.dates['he'] = { 7 | days: ["ראשון", "שני", "שלישי", "רביעי", "חמישי", "שישי", "שבת", "ראשון"], 8 | daysShort: ["א", "ב", "ג", "ד", "ה", "ו", "ש", "א"], 9 | daysMin: ["א", "ב", "ג", "ד", "ה", "ו", "ש", "א"], 10 | months: ["ינואר", "פברואר", "מרץ", "אפריל", "מאי", "יוני", "יולי", "אוגוסט", "ספטמבר", "אוקטובר", "נובמבר", "דצמבר"], 11 | monthsShort: ["ינו", "פבר", "מרץ", "אפר", "מאי", "יונ", "יול", "אוג", "ספט", "אוק", "נוב", "דצמ"], 12 | today: "היום", 13 | suffix: [], 14 | meridiem: [], 15 | rtl: true 16 | }; 17 | }(jQuery)); 18 | -------------------------------------------------------------------------------- /mapApp/static/datetimepicker/js/locales/bootstrap-datetimepicker.hr.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Croatian localisation 3 | */ 4 | ;(function($){ 5 | $.fn.datetimepicker.dates['hr'] = { 6 | days: ["Nedjelja", "Ponedjelja", "Utorak", "Srijeda", "Četrtak", "Petak", "Subota", "Nedjelja"], 7 | daysShort: ["Ned", "Pon", "Uto", "Srr", "Čet", "Pet", "Sub", "Ned"], 8 | daysMin: ["Ne", "Po", "Ut", "Sr", "Če", "Pe", "Su", "Ne"], 9 | months: ["Siječanj", "Veljača", "Ožujak", "Travanj", "Svibanj", "Lipanj", "Srpanj", "Kolovoz", "Rujan", "Listopad", "Studeni", "Prosinac"], 10 | monthsShort: ["Sije", "Velj", "Ožu", "Tra", "Svi", "Lip", "Jul", "Kol", "Ruj", "Lis", "Stu", "Pro"], 11 | today: "Danas", 12 | suffix: [], 13 | meridiem: [] 14 | }; 15 | }(jQuery)); 16 | -------------------------------------------------------------------------------- /mapApp/static/datetimepicker/js/locales/bootstrap-datetimepicker.hu.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Hungarian translation for bootstrap-datetimepicker 3 | * darevish 4 | */ 5 | ;(function($){ 6 | $.fn.datetimepicker.dates['hu'] = { 7 | days: ["Vasárnap", "Hétfő", "Kedd", "Szerda", "Csütörtök", "Péntek", "Szombat", "Vasárnap"], 8 | daysShort: ["Vas", "Hét", "Ked", "Sze", "Csü", "Pén", "Szo", "Vas"], 9 | daysMin: ["V", "H", "K", "Sze", "Cs", "P", "Szo", "V"], 10 | months: ["Január", "Február", "Március", "Április", "Május", "Június", "Július", "Augusztus", "Szeptember", "Október", "November", "December"], 11 | monthsShort: ["Jan", "Feb", "Már", "Ápr", "Máj", "Jún", "Júl", "Aug", "Sze", "Okt", "Nov", "Dec"], 12 | today: "Ma", 13 | suffix: [], 14 | meridiem: [], 15 | weekStart: 1 16 | }; 17 | }(jQuery)); 18 | -------------------------------------------------------------------------------- /mapApp/static/datetimepicker/js/locales/bootstrap-datetimepicker.id.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Bahasa translation for bootstrap-datetimepicker 3 | * Azwar Akbar 4 | * Addtional by Yulian Sutopo 5 | */ 6 | ;(function($){ 7 | $.fn.datetimepicker.dates['id'] = { 8 | days: ["Minggu", "Senin", "Selasa", "Rabu", "Kamis", "Jumat", "Sabtu", "Minggu"], 9 | daysShort: ["Mng", "Sen", "Sel", "Rab", "Kam", "Jum", "Sab", "Mng"], 10 | daysMin: ["Mg", "Sn", "Sl", "Ra", "Ka", "Ju", "Sa", "Mg"], 11 | months: ["Januari", "Februari", "Maret", "April", "Mei", "Juni", "Juli", "Agustus", "September", "Oktober", "November", "Desember"], 12 | monthsShort: ["Jan", "Feb", "Mar", "Apr", "Mei", "Jun", "Jul", "Ags", "Sep", "Okt", "Nov", "Des"], 13 | today: "Hari Ini", 14 | suffix: [], 15 | meridiem: [], 16 | weekStart: 1, 17 | format: "dd/mm/yyyy hh:ii:ss" 18 | }; 19 | }(jQuery)); 20 | -------------------------------------------------------------------------------- /mapApp/static/datetimepicker/js/locales/bootstrap-datetimepicker.is.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Icelandic translation for bootstrap-datetimepicker 3 | * Hinrik Örn Sigurðsson 4 | */ 5 | ;(function($){ 6 | $.fn.datetimepicker.dates['is'] = { 7 | days: ["Sunnudagur", "Mánudagur", "Þriðjudagur", "Miðvikudagur", "Fimmtudagur", "Föstudagur", "Laugardagur", "Sunnudagur"], 8 | daysShort: ["Sun", "Mán", "Þri", "Mið", "Fim", "Fös", "Lau", "Sun"], 9 | daysMin: ["Su", "Má", "Þr", "Mi", "Fi", "Fö", "La", "Su"], 10 | months: ["Janúar", "Febrúar", "Mars", "Apríl", "Maí", "Júní", "Júlí", "Ágúst", "September", "Október", "Nóvember", "Desember"], 11 | monthsShort: ["Jan", "Feb", "Mar", "Apr", "Maí", "Jún", "Júl", "Ágú", "Sep", "Okt", "Nóv", "Des"], 12 | today: "Í Dag", 13 | suffix: [], 14 | meridiem: [] 15 | }; 16 | }(jQuery)); 17 | -------------------------------------------------------------------------------- /mapApp/static/datetimepicker/js/locales/bootstrap-datetimepicker.it.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Italian translation for bootstrap-datetimepicker 3 | * Enrico Rubboli 4 | */ 5 | ;(function($){ 6 | $.fn.datetimepicker.dates['it'] = { 7 | days: ["Domenica", "Lunedi", "Martedi", "Mercoledi", "Giovedi", "Venerdi", "Sabato", "Domenica"], 8 | daysShort: ["Dom", "Lun", "Mar", "Mer", "Gio", "Ven", "Sab", "Dom"], 9 | daysMin: ["Do", "Lu", "Ma", "Me", "Gi", "Ve", "Sa", "Do"], 10 | months: ["Gennaio", "Febbraio", "Marzo", "Aprile", "Maggio", "Giugno", "Luglio", "Agosto", "Settembre", "Ottobre", "Novembre", "Dicembre"], 11 | monthsShort: ["Gen", "Feb", "Mar", "Apr", "Mag", "Giu", "Lug", "Ago", "Set", "Ott", "Nov", "Dic"], 12 | today: "Oggi", 13 | suffix: [], 14 | meridiem: [], 15 | weekStart: 1, 16 | format: "dd/mm/yyyy hh:ii:ss" 17 | }; 18 | }(jQuery)); 19 | -------------------------------------------------------------------------------- /mapApp/static/datetimepicker/js/locales/bootstrap-datetimepicker.ja.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Japanese translation for bootstrap-datetimepicker 3 | * Norio Suzuki 4 | */ 5 | ;(function($){ 6 | $.fn.datetimepicker.dates['ja'] = { 7 | days: ["日曜", "月曜", "火曜", "水曜", "木曜", "金曜", "土曜", "日曜"], 8 | daysShort: ["日", "月", "火", "水", "木", "金", "土", "日"], 9 | daysMin: ["日", "月", "火", "水", "木", "金", "土", "日"], 10 | months: ["1月", "2月", "3月", "4月", "5月", "6月", "7月", "8月", "9月", "10月", "11月", "12月"], 11 | monthsShort: ["1月", "2月", "3月", "4月", "5月", "6月", "7月", "8月", "9月", "10月", "11月", "12月"], 12 | today: "今日", 13 | suffix: [], 14 | meridiem: [] 15 | }; 16 | }(jQuery)); 17 | -------------------------------------------------------------------------------- /mapApp/static/datetimepicker/js/locales/bootstrap-datetimepicker.ko.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Korean translation for bootstrap-datetimepicker 3 | * Gu Youn 4 | * Baekjoon Choi 5 | */ 6 | ;(function($){ 7 | $.fn.datetimepicker.dates['ko'] = { 8 | days: ["일요일", "월요일", "화요일", "수요일", "목요일", "금요일", "토요일", "일요일"], 9 | daysShort: ["일", "월", "화", "수", "목", "금", "토", "일"], 10 | daysMin: ["일", "월", "화", "수", "목", "금", "토", "일"], 11 | months: ["1월", "2월", "3월", "4월", "5월", "6월", "7월", "8월", "9월", "10월", "11월", "12월"], 12 | monthsShort: ["1월", "2월", "3월", "4월", "5월", "6월", "7월", "8월", "9월", "10월", "11월", "12월"], 13 | suffix: [], 14 | meridiem: ["오전", "오후"], 15 | today: "오늘", 16 | }; 17 | }(jQuery)); 18 | -------------------------------------------------------------------------------- /mapApp/static/datetimepicker/js/locales/bootstrap-datetimepicker.lt.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Lithuanian translation for bootstrap-datetimepicker 3 | * Šarūnas Gliebus 4 | */ 5 | 6 | ;(function($){ 7 | $.fn.datetimepicker.dates['lt'] = { 8 | days: ["Sekmadienis", "Pirmadienis", "Antradienis", "Trečiadienis", "Ketvirtadienis", "Penktadienis", "Šeštadienis", "Sekmadienis"], 9 | daysShort: ["S", "Pr", "A", "T", "K", "Pn", "Š", "S"], 10 | daysMin: ["Sk", "Pr", "An", "Tr", "Ke", "Pn", "Št", "Sk"], 11 | months: ["Sausis", "Vasaris", "Kovas", "Balandis", "Gegužė", "Birželis", "Liepa", "Rugpjūtis", "Rugsėjis", "Spalis", "Lapkritis", "Gruodis"], 12 | monthsShort: ["Sau", "Vas", "Kov", "Bal", "Geg", "Bir", "Lie", "Rugp", "Rugs", "Spa", "Lap", "Gru"], 13 | today: "Šiandien", 14 | suffix: [], 15 | meridiem: [], 16 | weekStart: 1 17 | }; 18 | }(jQuery)); 19 | -------------------------------------------------------------------------------- /mapApp/static/datetimepicker/js/locales/bootstrap-datetimepicker.lv.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Latvian translation for bootstrap-datetimepicker 3 | * Artis Avotins 4 | */ 5 | 6 | ;(function($){ 7 | $.fn.datetimepicker.dates['lv'] = { 8 | days: ["Svētdiena", "Pirmdiena", "Otrdiena", "Trešdiena", "Ceturtdiena", "Piektdiena", "Sestdiena", "Svētdiena"], 9 | daysShort: ["Sv", "P", "O", "T", "C", "Pk", "S", "Sv"], 10 | daysMin: ["Sv", "Pr", "Ot", "Tr", "Ce", "Pk", "St", "Sv"], 11 | months: ["Janvāris", "Februāris", "Marts", "Aprīlis", "Maijs", "Jūnijs", "Jūlijs", "Augusts", "Septembris", "Oktobris", "Novembris", "Decembris"], 12 | monthsShort: ["Jan", "Feb", "Mar", "Apr", "Mai", "Jūn", "Jūl", "Aug", "Sep", "Okt", "Nov", "Dec."], 13 | today: "Šodien", 14 | suffix: [], 15 | meridiem: [], 16 | weekStart: 1 17 | }; 18 | }(jQuery)); -------------------------------------------------------------------------------- /mapApp/static/datetimepicker/js/locales/bootstrap-datetimepicker.ms.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Malay translation for bootstrap-datetimepicker 3 | * Ateman Faiz 4 | */ 5 | ;(function($){ 6 | $.fn.datetimepicker.dates['ms'] = { 7 | days: ["Ahad", "Isnin", "Selasa", "Rabu", "Khamis", "Jumaat", "Sabtu", "Ahad"], 8 | daysShort: ["Aha", "Isn", "Sel", "Rab", "Kha", "Jum", "Sab", "Aha"], 9 | daysMin: ["Ah", "Is", "Se", "Ra", "Kh", "Ju", "Sa", "Ah"], 10 | months: ["Januari", "Februari", "Mac", "April", "Mei", "Jun", "Julai", "Ogos", "September", "Oktober", "November", "Disember"], 11 | monthsShort: ["Jan", "Feb", "Mar", "Apr", "Mei", "Jun", "Jul", "Ogo", "Sep", "Okt", "Nov", "Dis"], 12 | today: "Hari Ini", 13 | suffix: [], 14 | meridiem: [] 15 | }; 16 | }(jQuery)); 17 | -------------------------------------------------------------------------------- /mapApp/static/datetimepicker/js/locales/bootstrap-datetimepicker.nb.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Norwegian (bokmål) translation for bootstrap-datetimepicker 3 | * Fredrik Sundmyhr 4 | */ 5 | ;(function($){ 6 | $.fn.datetimepicker.dates['nb'] = { 7 | days: ["Søndag", "Mandag", "Tirsdag", "Onsdag", "Torsdag", "Fredag", "Lørdag", "Søndag"], 8 | daysShort: ["Søn", "Man", "Tir", "Ons", "Tor", "Fre", "Lør", "Søn"], 9 | daysMin: ["Sø", "Ma", "Ti", "On", "To", "Fr", "Lø", "Sø"], 10 | months: ["Januar", "Februar", "Mars", "April", "Mai", "Juni", "Juli", "August", "September", "Oktober", "November", "Desember"], 11 | monthsShort: ["Jan", "Feb", "Mar", "Apr", "Mai", "Jun", "Jul", "Aug", "Sep", "Okt", "Nov", "Des"], 12 | today: "I Dag", 13 | suffix: [], 14 | meridiem: [] 15 | }; 16 | }(jQuery)); -------------------------------------------------------------------------------- /mapApp/static/datetimepicker/js/locales/bootstrap-datetimepicker.nl.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Dutch translation for bootstrap-datetimepicker 3 | * Reinier Goltstein 4 | */ 5 | ;(function($){ 6 | $.fn.datetimepicker.dates['nl'] = { 7 | days: ["Zondag", "Maandag", "Dinsdag", "Woensdag", "Donderdag", "Vrijdag", "Zaterdag", "Zondag"], 8 | daysShort: ["Zo", "Ma", "Di", "Wo", "Do", "Vr", "Za", "Zo"], 9 | daysMin: ["Zo", "Ma", "Di", "Wo", "Do", "Vr", "Za", "Zo"], 10 | months: ["Januari", "Februari", "Maart", "April", "Mei", "Juni", "Juli", "Augustus", "September", "Oktober", "November", "December"], 11 | monthsShort: ["Jan", "Feb", "Mrt", "Apr", "Mei", "Jun", "Jul", "Aug", "Sep", "Okt", "Nov", "Dec"], 12 | today: "Vandaag", 13 | suffix: [], 14 | meridiem: [] 15 | }; 16 | }(jQuery)); 17 | -------------------------------------------------------------------------------- /mapApp/static/datetimepicker/js/locales/bootstrap-datetimepicker.no.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Norwegian translation for bootstrap-datetimepicker 3 | * Rune Warhuus 4 | */ 5 | ;(function($){ 6 | $.fn.datetimepicker.dates['no'] = { 7 | days: ["Søndag", "Mandag", "Tirsdag", "Onsdag", "Torsdag", "Fredag", "Lørdag", "Søndag"], 8 | daysShort: ["Søn", "Man", "Tir", "Ons", "Tor", "Fre", "Lør", "Søn"], 9 | daysMin: ["Sø", "Ma", "Ti", "On", "To", "Fr", "Lø", "Sø"], 10 | months: ["Januar", "Februar", "Mars", "April", "Mai", "Juni", "Juli", "August", "September", "Oktober", "November", "Desember"], 11 | monthsShort: ["Jan", "Feb", "Mar", "Apr", "Mai", "Jun", "Jul", "Aug", "Sep", "Okt", "Nov", "Des"], 12 | today: "I Dag", 13 | suffix: [], 14 | meridiem: [] 15 | }; 16 | }(jQuery)); 17 | -------------------------------------------------------------------------------- /mapApp/static/datetimepicker/js/locales/bootstrap-datetimepicker.pl.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Polish translation for bootstrap-datetimepicker 3 | * Robert 4 | */ 5 | ;(function($){ 6 | $.fn.datetimepicker.dates['pl'] = { 7 | days: ["Niedziela", "Poniedziałek", "Wtorek", "Środa", "Czwartek", "Piątek", "Sobota", "Niedziela"], 8 | daysShort: ["Nie", "Pn", "Wt", "Śr", "Czw", "Pt", "So", "Nie"], 9 | daysMin: ["N", "Pn", "Wt", "Śr", "Cz", "Pt", "So", "N"], 10 | months: ["Styczeń", "Luty", "Marzec", "Kwiecień", "Maj", "Czerwiec", "Lipiec", "Sierpień", "Wrzesień", "Październik", "Listopad", "Grudzień"], 11 | monthsShort: ["Sty", "Lu", "Mar", "Kw", "Maj", "Cze", "Lip", "Sie", "Wrz", "Pa", "Lis", "Gru"], 12 | today: "Dzisiaj", 13 | suffix: [], 14 | meridiem: [], 15 | weekStart: 1 16 | }; 17 | }(jQuery)); 18 | -------------------------------------------------------------------------------- /mapApp/static/datetimepicker/js/locales/bootstrap-datetimepicker.pt-BR.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Brazilian translation for bootstrap-datetimepicker 3 | * Cauan Cabral 4 | */ 5 | ;(function($){ 6 | $.fn.datetimepicker.dates['pt-BR'] = { 7 | format: 'dd/mm/yyyy', 8 | days: ["Domingo", "Segunda", "Terça", "Quarta", "Quinta", "Sexta", "Sábado", "Domingo"], 9 | daysShort: ["Dom", "Seg", "Ter", "Qua", "Qui", "Sex", "Sáb", "Dom"], 10 | daysMin: ["Do", "Se", "Te", "Qu", "Qu", "Se", "Sa", "Do"], 11 | months: ["Janeiro", "Fevereiro", "Março", "Abril", "Maio", "Junho", "Julho", "Agosto", "Setembro", "Outubro", "Novembro", "Dezembro"], 12 | monthsShort: ["Jan", "Fev", "Mar", "Abr", "Mai", "Jun", "Jul", "Ago", "Set", "Out", "Nov", "Dez"], 13 | today: "Hoje", 14 | suffix: [], 15 | meridiem: [] 16 | }; 17 | }(jQuery)); 18 | -------------------------------------------------------------------------------- /mapApp/static/datetimepicker/js/locales/bootstrap-datetimepicker.pt.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Portuguese translation for bootstrap-datetimepicker 3 | * Original code: Cauan Cabral 4 | * Tiago Melo 5 | */ 6 | ;(function($){ 7 | $.fn.datetimepicker.dates['pt'] = { 8 | days: ["Domingo", "Segunda", "Terça", "Quarta", "Quinta", "Sexta", "Sábado", "Domingo"], 9 | daysShort: ["Dom", "Seg", "Ter", "Qua", "Qui", "Sex", "Sáb", "Dom"], 10 | daysMin: ["Do", "Se", "Te", "Qu", "Qu", "Se", "Sa", "Do"], 11 | months: ["Janeiro", "Fevereiro", "Março", "Abril", "Maio", "Junho", "Julho", "Agosto", "Setembro", "Outubro", "Novembro", "Dezembro"], 12 | monthsShort: ["Jan", "Fev", "Mar", "Abr", "Mai", "Jun", "Jul", "Ago", "Set", "Out", "Nov", "Dez"], 13 | suffix: [], 14 | meridiem: ["am","pm"], 15 | today: "Hoje" 16 | }; 17 | }(jQuery)); 18 | -------------------------------------------------------------------------------- /mapApp/static/datetimepicker/js/locales/bootstrap-datetimepicker.ro.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Romanian translation for bootstrap-datetimepicker 3 | * Cristian Vasile 4 | */ 5 | ;(function($){ 6 | $.fn.datetimepicker.dates['ro'] = { 7 | days: ["Duminică", "Luni", "Marţi", "Miercuri", "Joi", "Vineri", "Sâmbătă", "Duminică"], 8 | daysShort: ["Dum", "Lun", "Mar", "Mie", "Joi", "Vin", "Sâm", "Dum"], 9 | daysMin: ["Du", "Lu", "Ma", "Mi", "Jo", "Vi", "Sâ", "Du"], 10 | months: ["Ianuarie", "Februarie", "Martie", "Aprilie", "Mai", "Iunie", "Iulie", "August", "Septembrie", "Octombrie", "Noiembrie", "Decembrie"], 11 | monthsShort: ["Ian", "Feb", "Mar", "Apr", "Mai", "Iun", "Iul", "Aug", "Sep", "Oct", "Nov", "Dec"], 12 | today: "Astăzi", 13 | suffix: [], 14 | meridiem: [], 15 | weekStart: 1 16 | }; 17 | }(jQuery)); 18 | -------------------------------------------------------------------------------- /mapApp/static/datetimepicker/js/locales/bootstrap-datetimepicker.rs-latin.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Serbian latin translation for bootstrap-datetimepicker 3 | * Bojan Milosavlević 4 | */ 5 | ;(function($){ 6 | $.fn.datetimepicker.dates['rs'] = { 7 | days: ["Nedelja","Ponedeljak", "Utorak", "Sreda", "Četvrtak", "Petak", "Subota", "Nedelja"], 8 | daysShort: ["Ned", "Pon", "Uto", "Sre", "Čet", "Pet", "Sub", "Ned"], 9 | daysMin: ["N", "Po", "U", "Sr", "Č", "Pe", "Su", "N"], 10 | months: ["Januar", "Februar", "Mart", "April", "Maj", "Jun", "Jul", "Avgust", "Septembar", "Oktobar", "Novembar", "Decembar"], 11 | monthsShort: ["Jan", "Feb", "Mar", "Apr", "Maj", "Jun", "Jul", "Avg", "Sep", "Okt", "Nov", "Dec"], 12 | today: "Danas", 13 | suffix: [], 14 | meridiem: [] 15 | }; 16 | }(jQuery)); 17 | -------------------------------------------------------------------------------- /mapApp/static/datetimepicker/js/locales/bootstrap-datetimepicker.rs.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Serbian cyrillic translation for bootstrap-datetimepicker 3 | * Bojan Milosavlević 4 | */ 5 | ;(function($){ 6 | $.fn.datetimepicker.dates['rs'] = { 7 | days: ["Недеља","Понедељак", "Уторак", "Среда", "Четвртак", "Петак", "Субота", "Недеља"], 8 | daysShort: ["Нед", "Пон", "Уто", "Сре", "Чет", "Пет", "Суб", "Нед"], 9 | daysMin: ["Н", "По", "У", "Ср", "Ч", "Пе", "Су", "Н"], 10 | months: ["Јануар", "Фебруар", "Март", "Април", "Мај", "Јун", "Јул", "Август", "Септембар", "Октобар", "Новембар", "Децембар"], 11 | monthsShort: ["Јан", "Феб", "Мар", "Апр", "Мај", "Јун", "Јул", "Авг", "Сеп", "Окт", "Нов", "Дец"], 12 | today: "Данас", 13 | suffix: [], 14 | meridiem: [] 15 | }; 16 | }(jQuery)); 17 | -------------------------------------------------------------------------------- /mapApp/static/datetimepicker/js/locales/bootstrap-datetimepicker.ru.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Russian translation for bootstrap-datetimepicker 3 | * Victor Taranenko 4 | */ 5 | ;(function($){ 6 | $.fn.datetimepicker.dates['ru'] = { 7 | days: ["Воскресенье", "Понедельник", "Вторник", "Среда", "Четверг", "Пятница", "Суббота", "Воскресенье"], 8 | daysShort: ["Вск", "Пнд", "Втр", "Срд", "Чтв", "Птн", "Суб", "Вск"], 9 | daysMin: ["Вс", "Пн", "Вт", "Ср", "Чт", "Пт", "Сб", "Вс"], 10 | months: ["Январь", "Февраль", "Март", "Апрель", "Май", "Июнь", "Июль", "Август", "Сентябрь", "Октябрь", "Ноябрь", "Декабрь"], 11 | monthsShort: ["Янв", "Фев", "Мар", "Апр", "Май", "Июн", "Июл", "Авг", "Сен", "Окт", "Ноя", "Дек"], 12 | today: "Сегодня", 13 | suffix: [], 14 | meridiem: [] 15 | }; 16 | }(jQuery)); -------------------------------------------------------------------------------- /mapApp/static/datetimepicker/js/locales/bootstrap-datetimepicker.sk.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Slovak translation for bootstrap-datetimepicker 3 | * Marek Lichtner 4 | * Fixes by Michal Remiš 5 | */ 6 | ;(function($){ 7 | $.fn.datetimepicker.dates["sk"] = { 8 | days: ["Nedeľa", "Pondelok", "Utorok", "Streda", "Štvrtok", "Piatok", "Sobota", "Nedeľa"], 9 | daysShort: ["Ned", "Pon", "Uto", "Str", "Štv", "Pia", "Sob", "Ned"], 10 | daysMin: ["Ne", "Po", "Ut", "St", "Št", "Pia", "So", "Ne"], 11 | months: ["Január", "Február", "Marec", "Apríl", "Máj", "Jún", "Júl", "August", "September", "Október", "November", "December"], 12 | monthsShort: ["Jan", "Feb", "Mar", "Apr", "Máj", "Jún", "Júl", "Aug", "Sep", "Okt", "Nov", "Dec"], 13 | today: "Dnes", 14 | suffix: [], 15 | meridiem: [] 16 | }; 17 | }(jQuery)); 18 | -------------------------------------------------------------------------------- /mapApp/static/datetimepicker/js/locales/bootstrap-datetimepicker.sl.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Slovene translation for bootstrap-datetimepicker 3 | * Gregor Rudolf 4 | */ 5 | ;(function($){ 6 | $.fn.datetimepicker.dates['sl'] = { 7 | days: ["Nedelja", "Ponedeljek", "Torek", "Sreda", "Četrtek", "Petek", "Sobota", "Nedelja"], 8 | daysShort: ["Ned", "Pon", "Tor", "Sre", "Čet", "Pet", "Sob", "Ned"], 9 | daysMin: ["Ne", "Po", "To", "Sr", "Če", "Pe", "So", "Ne"], 10 | months: ["Januar", "Februar", "Marec", "April", "Maj", "Junij", "Julij", "Avgust", "September", "Oktober", "November", "December"], 11 | monthsShort: ["Jan", "Feb", "Mar", "Apr", "Maj", "Jun", "Jul", "Avg", "Sep", "Okt", "Nov", "Dec"], 12 | today: "Danes", 13 | suffix: [], 14 | meridiem: [] 15 | }; 16 | }(jQuery)); 17 | -------------------------------------------------------------------------------- /mapApp/static/datetimepicker/js/locales/bootstrap-datetimepicker.sv.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Swedish translation for bootstrap-datetimepicker 3 | * Patrik Ragnarsson 4 | */ 5 | ;(function($){ 6 | $.fn.datetimepicker.dates['sv'] = { 7 | days: ["Söndag", "Måndag", "Tisdag", "Onsdag", "Torsdag", "Fredag", "Lördag", "Söndag"], 8 | daysShort: ["Sön", "Mån", "Tis", "Ons", "Tor", "Fre", "Lör", "Sön"], 9 | daysMin: ["Sö", "Må", "Ti", "On", "To", "Fr", "Lö", "Sö"], 10 | months: ["Januari", "Februari", "Mars", "April", "Maj", "Juni", "Juli", "Augusti", "September", "Oktober", "November", "December"], 11 | monthsShort: ["Jan", "Feb", "Mar", "Apr", "Maj", "Jun", "Jul", "Aug", "Sep", "Okt", "Nov", "Dec"], 12 | today: "I Dag", 13 | suffix: [], 14 | meridiem: [] 15 | }; 16 | }(jQuery)); 17 | -------------------------------------------------------------------------------- /mapApp/static/datetimepicker/js/locales/bootstrap-datetimepicker.sw.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Swahili translation for bootstrap-datetimepicker 3 | * Edwin Mugendi 4 | * Source: http://scriptsource.org/cms/scripts/page.php?item_id=entry_detail&uid=xnfaqyzcku 5 | */ 6 | ;(function($){ 7 | $.fn.datetimepicker.dates['sw'] = { 8 | days: ["Jumapili", "Jumatatu", "Jumanne", "Jumatano", "Alhamisi", "Ijumaa", "Jumamosi", "Jumapili"], 9 | daysShort: ["J2", "J3", "J4", "J5", "Alh", "Ij", "J1", "J2"], 10 | daysMin: ["2", "3", "4", "5", "A", "I", "1", "2"], 11 | months: ["Januari", "Februari", "Machi", "Aprili", "Mei", "Juni", "Julai", "Agosti", "Septemba", "Oktoba", "Novemba", "Desemba"], 12 | monthsShort: ["Jan", "Feb", "Mac", "Apr", "Mei", "Jun", "Jul", "Ago", "Sep", "Okt", "Nov", "Des"], 13 | today: "Leo", 14 | suffix: [], 15 | meridiem: [] 16 | }; 17 | }(jQuery)); 18 | -------------------------------------------------------------------------------- /mapApp/static/datetimepicker/js/locales/bootstrap-datetimepicker.th.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Thai translation for bootstrap-datetimepicker 3 | * Suchau Jiraprapot 4 | */ 5 | ;(function($){ 6 | $.fn.datetimepicker.dates['th'] = { 7 | days: ["อาทิตย์", "จันทร์", "อังคาร", "พุธ", "พฤหัส", "ศุกร์", "เสาร์", "อาทิตย์"], 8 | daysShort: ["อา", "จ", "อ", "พ", "พฤ", "ศ", "ส", "อา"], 9 | daysMin: ["อา", "จ", "อ", "พ", "พฤ", "ศ", "ส", "อา"], 10 | months: ["มกราคม", "กุมภาพันธ์", "มีนาคม", "เมษายน", "พฤษภาคม", "มิถุนายน", "กรกฎาคม", "สิงหาคม", "กันยายน", "ตุลาคม", "พฤศจิกายน", "ธันวาคม"], 11 | monthsShort: ["ม.ค.", "ก.พ.", "มี.ค.", "เม.ย.", "พ.ค.", "มิ.ย.", "ก.ค.", "ส.ค.", "ก.ย.", "ต.ค.", "พ.ย.", "ธ.ค."], 12 | today: "วันนี้", 13 | suffix: [], 14 | meridiem: [] 15 | }; 16 | }(jQuery)); 17 | -------------------------------------------------------------------------------- /mapApp/static/datetimepicker/js/locales/bootstrap-datetimepicker.tr.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Turkish translation for bootstrap-datetimepicker 3 | * Serkan Algur 4 | */ 5 | ;(function($){ 6 | $.fn.datetimepicker.dates['tr'] = { 7 | days: ["Pazar", "Pazartesi", "Salı", "Çarşamba", "Perşembe", "Cuma", "Cumartesi", "Pazar"], 8 | daysShort: ["Pz", "Pzt", "Sal", "Çrş", "Prş", "Cu", "Cts", "Pz"], 9 | daysMin: ["Pz", "Pzt", "Sa", "Çr", "Pr", "Cu", "Ct", "Pz"], 10 | months: ["Ocak", "Şubat", "Mart", "Nisan", "Mayıs", "Haziran", "Temmuz", "Ağustos", "Eylül", "Ekim", "Kasım", "Aralık"], 11 | monthsShort: ["Oca", "Şub", "Mar", "Nis", "May", "Haz", "Tem", "Ağu", "Eyl", "Eki", "Kas", "Ara"], 12 | today: "Bugün", 13 | suffix: [], 14 | meridiem: [] 15 | }; 16 | }(jQuery)); 17 | 18 | -------------------------------------------------------------------------------- /mapApp/static/datetimepicker/js/locales/bootstrap-datetimepicker.ua.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Ukrainian translation for bootstrap-datepicker 3 | * Igor Polynets 4 | */ 5 | ;(function($){ 6 | $.fn.datetimepicker.dates['ua'] = { 7 | days: ["Неділя", "Понеділок", "Вівторок", "Середа", "Четверг", "П'ятниця", "Субота", "Неділя"], 8 | daysShort: ["Нед", "Пнд", "Втр", "Срд", "Чтв", "Птн", "Суб", "Нед"], 9 | daysMin: ["Нд", "Пн", "Вт", "Ср", "Чт", "Пт", "Сб", "Нд"], 10 | months: ["Cічень", "Лютий", "Березень", "Квітень", "Травень", "Червень", "Липень", "Серпень", "Вересень", "Жовтень", "Листопад", "Грудень"], 11 | monthsShort: ["Січ", "Лют", "Бер", "Квт", "Трв", "Чер", "Лип", "Сер", "Вер", "Жов", "Лис", "Грд"], 12 | today: "Сьогодні", 13 | weekStart: 1 14 | }; 15 | }(jQuery)); 16 | -------------------------------------------------------------------------------- /mapApp/static/datetimepicker/js/locales/bootstrap-datetimepicker.uk.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Ukrainian translation for bootstrap-datetimepicker 3 | * Andrey Vityuk 4 | */ 5 | ;(function($){ 6 | $.fn.datetimepicker.dates['uk'] = { 7 | days: ["Неділя", "Понеділок", "Вівторок", "Середа", "Четвер", "П'ятниця", "Субота", "Неділя"], 8 | daysShort: ["Нед", "Пнд", "Втр", "Срд", "Чтв", "Птн", "Суб", "Нед"], 9 | daysMin: ["Нд", "Пн", "Вт", "Ср", "Чт", "Пт", "Сб", "Нд"], 10 | months: ["Січень", "Лютий", "Березень", "Квітень", "Травень", "Червень", "Липень", "Серпень", "Вересень", "Жовтень", "Листопад", "Грудень"], 11 | monthsShort: ["Січ", "Лют", "Бер", "Кві", "Тра", "Чер", "Лип", "Сер", "Вер", "Жов", "Лис", "Гру"], 12 | today: "Сьогодні", 13 | suffix: [], 14 | meridiem: [] 15 | }; 16 | }(jQuery)); -------------------------------------------------------------------------------- /mapApp/static/datetimepicker/js/locales/bootstrap-datetimepicker.zh-CN.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Simplified Chinese translation for bootstrap-datetimepicker 3 | * Yuan Cheung 4 | */ 5 | ;(function($){ 6 | $.fn.datetimepicker.dates['zh-CN'] = { 7 | days: ["星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六", "星期日"], 8 | daysShort: ["周日", "周一", "周二", "周三", "周四", "周五", "周六", "周日"], 9 | daysMin: ["日", "一", "二", "三", "四", "五", "六", "日"], 10 | months: ["一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月"], 11 | monthsShort: ["一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月"], 12 | today: "今天", 13 | suffix: [], 14 | meridiem: ["上午", "下午"] 15 | }; 16 | }(jQuery)); 17 | -------------------------------------------------------------------------------- /mapApp/static/datetimepicker/js/locales/bootstrap-datetimepicker.zh-TW.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Traditional Chinese translation for bootstrap-datetimepicker 3 | * Rung-Sheng Jang 4 | */ 5 | ;(function($){ 6 | $.fn.datetimepicker.dates['zh-TW'] = { 7 | days: ["星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六", "星期日"], 8 | daysShort: ["周日", "周一", "周二", "周三", "周四", "周五", "周六", "周日"], 9 | daysMin: ["日", "一", "二", "三", "四", "五", "六", "日"], 10 | months: ["一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月"], 11 | monthsShort: ["一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月"], 12 | today: "今天", 13 | suffix: [], 14 | meridiem: ["上午", "下午"] 15 | }; 16 | }(jQuery)); 17 | -------------------------------------------------------------------------------- /mapApp/static/files/Carta de consentimiento informado.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/mapApp/static/files/Carta de consentimiento informado.pdf -------------------------------------------------------------------------------- /mapApp/static/files/Letter of informed consent.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/mapApp/static/files/Letter of informed consent.pdf -------------------------------------------------------------------------------- /mapApp/static/leaflet/plugins/extra-markers/img/markers_default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/mapApp/static/leaflet/plugins/extra-markers/img/markers_default.png -------------------------------------------------------------------------------- /mapApp/static/leaflet/plugins/extra-markers/img/markers_default@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/mapApp/static/leaflet/plugins/extra-markers/img/markers_default@2x.png -------------------------------------------------------------------------------- /mapApp/static/leaflet/plugins/extra-markers/img/markers_shadow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/mapApp/static/leaflet/plugins/extra-markers/img/markers_shadow.png -------------------------------------------------------------------------------- /mapApp/static/leaflet/plugins/extra-markers/img/markers_shadow@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/mapApp/static/leaflet/plugins/extra-markers/img/markers_shadow@2x.png -------------------------------------------------------------------------------- /mapApp/static/leaflet/plugins/usermarker/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013 Jonatan Heyman 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /mapApp/static/leaflet/plugins/usermarker/img/bluedot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/mapApp/static/leaflet/plugins/usermarker/img/bluedot.png -------------------------------------------------------------------------------- /mapApp/static/mapApp/css/about.css: -------------------------------------------------------------------------------- 1 | .vcenter { 2 | /*border: 1px solid red;*/ 3 | display: inline-block; 4 | vertical-align: middle; 5 | float: none; 6 | } 7 | 8 | #sponsors img, #supporters img{ 9 | max-height: 100px; 10 | margin-left: auto; 11 | margin-right: auto; 12 | } 13 | .frame{ 14 | max-width: 200px; 15 | margin-left: auto; 16 | margin-right: auto; 17 | margin-bottom: 20px; 18 | } 19 | 20 | @media (min-width: 992px){ 21 | .col-md-offset-1p5 { 22 | margin-left: 12.5%; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /mapApp/static/mapApp/css/barchart.css: -------------------------------------------------------------------------------- 1 | #barchart text { 2 | fill: white; 3 | font: 10px sans-serif; 4 | text-anchor: start; 5 | } 6 | 7 | #barchart .axis text { 8 | fill: black; 9 | font: 10px sans-serif; 10 | } 11 | 12 | .axis path, 13 | .axis line { 14 | fill: none; 15 | stroke: #000; 16 | shape-rendering: crispEdges; 17 | } 18 | .x.axis path { 19 | display: none; 20 | } -------------------------------------------------------------------------------- /mapApp/static/mapApp/css/edit_hazards.css: -------------------------------------------------------------------------------- 1 | .map-col{ 2 | height: 100%; 3 | padding: 0 !important; 4 | } 5 | #map { 6 | height: 100%; 7 | margin-top: 0px; 8 | } 9 | .center-chart{ 10 | width: 100%; 11 | display: block; 12 | margin-left: auto; 13 | margin-right: auto; 14 | padding: 8px; 15 | } 16 | #i-type-bar g.axis.x text{ 17 | text-anchor: start !important; 18 | transform: rotate(45deg) translate(7px, -8px); 19 | } 20 | -------------------------------------------------------------------------------- /mapApp/static/mapApp/css/forms.css: -------------------------------------------------------------------------------- 1 | #div_id_ebike_class { 2 | margin-left: 20px 3 | } 4 | 5 | #div_id_ebike_speed { 6 | margin-left: 20px 7 | } 8 | -------------------------------------------------------------------------------- /mapApp/static/mapApp/css/recentReports.css: -------------------------------------------------------------------------------- 1 | .map-col{ 2 | height: 100%; 3 | padding: 0 !important; 4 | } 5 | 6 | #map { 7 | height: 100%; 8 | margin-top: 0px; 9 | } 10 | 11 | #data li{ 12 | padding-top: 5px; 13 | } 14 | 15 | .highlight{ 16 | background: #ddd; 17 | } 18 | -------------------------------------------------------------------------------- /mapApp/static/mapApp/css/vis.css: -------------------------------------------------------------------------------- 1 | #map{ 2 | height: 100%; 3 | } 4 | 5 | /* https://medium.com/ge-design/iot-cool-gray-is-a-great-background-color-for-data-visualization-ebf18c318418 */ 6 | body { 7 | background: #EBEFF2; 8 | padding-bottom: 200px; 9 | } 10 | 11 | .vis-title{ 12 | font-family: 'Carrois Gothic SC', sans-serif; 13 | font-weight: 700; 14 | color: #2c3e50; 15 | } 16 | 17 | .row{ 18 | margin: 15px; 19 | } 20 | 21 | /* axis */ 22 | .dc-chart .axis path { 23 | stroke: #59717F; 24 | } 25 | 26 | /* ticks */ 27 | .dc-chart .axis line { 28 | stroke: #59717F; 29 | } 30 | 31 | /* axis label */ 32 | .dc-chart .axis { 33 | color: #59717F; 34 | } 35 | 36 | /* Hide y axis on monthly colume chart */ 37 | #monthly-volume-chart g.y { 38 | display: none; 39 | } 40 | 41 | 42 | .chart-title { 43 | padding: 12px; 44 | text-align: left; 45 | margin-bottom: 12px; 46 | border-bottom: 2px solid #EBEFF2; 47 | } 48 | .center-chart{ 49 | width: 100%; 50 | display: block; 51 | margin-left: auto; 52 | margin-right: auto; 53 | padding: 8px; 54 | background: #fff; 55 | border: 1px solid #c5d1d8; 56 | border-radius: 5px; 57 | } 58 | .panel { 59 | border: 1px solid #c5d1d8; 60 | } 61 | 62 | #barTypes .x.axis path { 63 | display: none; 64 | } 65 | 66 | #barTypes .x.axis text:lang(de) { 67 | font-size: 8.5px; 68 | } 69 | -------------------------------------------------------------------------------- /mapApp/static/mapApp/data/toolkit.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/mapApp/static/mapApp/data/toolkit.zip -------------------------------------------------------------------------------- /mapApp/static/mapApp/font/faktos.regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/mapApp/static/mapApp/font/faktos.regular.ttf -------------------------------------------------------------------------------- /mapApp/static/mapApp/font/faktos.regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/mapApp/static/mapApp/font/faktos.regular.woff -------------------------------------------------------------------------------- /mapApp/static/mapApp/font/timeburner_regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/mapApp/static/mapApp/font/timeburner_regular.ttf -------------------------------------------------------------------------------- /mapApp/static/mapApp/images/5788_TIRF_BikeMapsORG_Logo_ART_OL.PDF: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/mapApp/static/mapApp/images/5788_TIRF_BikeMapsORG_Logo_ART_OL.PDF -------------------------------------------------------------------------------- /mapApp/static/mapApp/images/App Store Badge/App Store Marketing Getting Started Guide.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/mapApp/static/mapApp/images/App Store Badge/App Store Marketing Getting Started Guide.pdf -------------------------------------------------------------------------------- /mapApp/static/mapApp/images/App Store Badge/Print EPS/Download_on_the_App_Store_Badge_US-UK_135x40.eps: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/mapApp/static/mapApp/images/App Store Badge/Print EPS/Download_on_the_App_Store_Badge_US-UK_135x40.eps -------------------------------------------------------------------------------- /mapApp/static/mapApp/images/BikeMapsORG_Logo.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/mapApp/static/mapApp/images/BikeMapsORG_Logo.ico -------------------------------------------------------------------------------- /mapApp/static/mapApp/images/BikeMapsORG_Logo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/mapApp/static/mapApp/images/BikeMapsORG_Logo.jpg -------------------------------------------------------------------------------- /mapApp/static/mapApp/images/BikeMapsORG_Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/mapApp/static/mapApp/images/BikeMapsORG_Logo.png -------------------------------------------------------------------------------- /mapApp/static/mapApp/images/BikeMapsORG_Logo.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/mapApp/static/mapApp/images/BikeMapsORG_Logo.xcf -------------------------------------------------------------------------------- /mapApp/static/mapApp/images/BikeMapsORG_Logo_notxt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/mapApp/static/mapApp/images/BikeMapsORG_Logo_notxt.png -------------------------------------------------------------------------------- /mapApp/static/mapApp/images/BikeMapsORG_Logo_notxt_sm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/mapApp/static/mapApp/images/BikeMapsORG_Logo_notxt_sm.png -------------------------------------------------------------------------------- /mapApp/static/mapApp/images/BikeMapsSocialMediaLogo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/mapApp/static/mapApp/images/BikeMapsSocialMediaLogo.jpg -------------------------------------------------------------------------------- /mapApp/static/mapApp/images/BikeMapsSocialMediaLogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/mapApp/static/mapApp/images/BikeMapsSocialMediaLogo.png -------------------------------------------------------------------------------- /mapApp/static/mapApp/images/BikeMapsSocialMediaLogoFB.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/mapApp/static/mapApp/images/BikeMapsSocialMediaLogoFB.jpg -------------------------------------------------------------------------------- /mapApp/static/mapApp/images/BikeMapsTwitterLogo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/mapApp/static/mapApp/images/BikeMapsTwitterLogo.jpg -------------------------------------------------------------------------------- /mapApp/static/mapApp/images/BikeMapsTwitterLogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/mapApp/static/mapApp/images/BikeMapsTwitterLogo.png -------------------------------------------------------------------------------- /mapApp/static/mapApp/images/BikeMaps_French_crop_sm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/mapApp/static/mapApp/images/BikeMaps_French_crop_sm.png -------------------------------------------------------------------------------- /mapApp/static/mapApp/images/WalkRollMapLogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/mapApp/static/mapApp/images/WalkRollMapLogo.png -------------------------------------------------------------------------------- /mapApp/static/mapApp/images/bespoke_logo_215.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/mapApp/static/mapApp/images/bespoke_logo_215.png -------------------------------------------------------------------------------- /mapApp/static/mapApp/images/bike near miss.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/mapApp/static/mapApp/images/bike near miss.png -------------------------------------------------------------------------------- /mapApp/static/mapApp/images/bike_crash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/mapApp/static/mapApp/images/bike_crash.png -------------------------------------------------------------------------------- /mapApp/static/mapApp/images/bikemaps.org.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/mapApp/static/mapApp/images/bikemaps.org.pdf -------------------------------------------------------------------------------- /mapApp/static/mapApp/images/custom_icons/collision_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/mapApp/static/mapApp/images/custom_icons/collision_icon.png -------------------------------------------------------------------------------- /mapApp/static/mapApp/images/custom_icons/nearmiss_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/mapApp/static/mapApp/images/custom_icons/nearmiss_icon.png -------------------------------------------------------------------------------- /mapApp/static/mapApp/images/geocoder_alt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/mapApp/static/mapApp/images/geocoder_alt.png -------------------------------------------------------------------------------- /mapApp/static/mapApp/images/googleButton.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/mapApp/static/mapApp/images/googleButton.png -------------------------------------------------------------------------------- /mapApp/static/mapApp/images/sponsorLogos/BCCC.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/mapApp/static/mapApp/images/sponsorLogos/BCCC.png -------------------------------------------------------------------------------- /mapApp/static/mapApp/images/sponsorLogos/BikeBridge-Logo-03-left-e1281156539228.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/mapApp/static/mapApp/images/sponsorLogos/BikeBridge-Logo-03-left-e1281156539228.png -------------------------------------------------------------------------------- /mapApp/static/mapApp/images/sponsorLogos/CRDlogo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/mapApp/static/mapApp/images/sponsorLogos/CRDlogo.jpg -------------------------------------------------------------------------------- /mapApp/static/mapApp/images/sponsorLogos/Capital-Bike.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/mapApp/static/mapApp/images/sponsorLogos/Capital-Bike.png -------------------------------------------------------------------------------- /mapApp/static/mapApp/images/sponsorLogos/HUB.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/mapApp/static/mapApp/images/sponsorLogos/HUB.png -------------------------------------------------------------------------------- /mapApp/static/mapApp/images/sponsorLogos/Mitacs.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/mapApp/static/mapApp/images/sponsorLogos/Mitacs.jpg -------------------------------------------------------------------------------- /mapApp/static/mapApp/images/sponsorLogos/NSERC.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/mapApp/static/mapApp/images/sponsorLogos/NSERC.png -------------------------------------------------------------------------------- /mapApp/static/mapApp/images/sponsorLogos/PHAC.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/mapApp/static/mapApp/images/sponsorLogos/PHAC.png -------------------------------------------------------------------------------- /mapApp/static/mapApp/images/sponsorLogos/Pedalheads-logo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/mapApp/static/mapApp/images/sponsorLogos/Pedalheads-logo.jpg -------------------------------------------------------------------------------- /mapApp/static/mapApp/images/sponsorLogos/SPAR_logo2_transparent.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/mapApp/static/mapApp/images/sponsorLogos/SPAR_logo2_transparent.png -------------------------------------------------------------------------------- /mapApp/static/mapApp/images/sponsorLogos/SPAR_logo_transparent.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/mapApp/static/mapApp/images/sponsorLogos/SPAR_logo_transparent.png -------------------------------------------------------------------------------- /mapApp/static/mapApp/images/sponsorLogos/Saanich_Police_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/mapApp/static/mapApp/images/sponsorLogos/Saanich_Police_logo.png -------------------------------------------------------------------------------- /mapApp/static/mapApp/images/sponsorLogos/TIRF.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/mapApp/static/mapApp/images/sponsorLogos/TIRF.jpg -------------------------------------------------------------------------------- /mapApp/static/mapApp/images/sponsorLogos/UC_Santa_Barbara_Wordmark_Navy_RGB.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/mapApp/static/mapApp/images/sponsorLogos/UC_Santa_Barbara_Wordmark_Navy_RGB.png -------------------------------------------------------------------------------- /mapApp/static/mapApp/images/sponsorLogos/UKM.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/mapApp/static/mapApp/images/sponsorLogos/UKM.jpg -------------------------------------------------------------------------------- /mapApp/static/mapApp/images/sponsorLogos/affinity_bridge.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/mapApp/static/mapApp/images/sponsorLogos/affinity_bridge.png -------------------------------------------------------------------------------- /mapApp/static/mapApp/images/sponsorLogos/bunt.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/mapApp/static/mapApp/images/sponsorLogos/bunt.jpg -------------------------------------------------------------------------------- /mapApp/static/mapApp/images/sponsorLogos/kidical_mass1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/mapApp/static/mapApp/images/sponsorLogos/kidical_mass1.gif -------------------------------------------------------------------------------- /mapApp/static/mapApp/images/sponsorLogos/saanich_logo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/mapApp/static/mapApp/images/sponsorLogos/saanich_logo.jpg -------------------------------------------------------------------------------- /mapApp/static/mapApp/images/sponsorLogos/saferroadsOttawa.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/mapApp/static/mapApp/images/sponsorLogos/saferroadsOttawa.png -------------------------------------------------------------------------------- /mapApp/static/mapApp/images/sponsorLogos/strava.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/mapApp/static/mapApp/images/sponsorLogos/strava.jpg -------------------------------------------------------------------------------- /mapApp/static/mapApp/images/sponsorLogos/uvic-logo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/mapApp/static/mapApp/images/sponsorLogos/uvic-logo.jpg -------------------------------------------------------------------------------- /mapApp/static/mapApp/images/sponsorLogos/victoria.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/mapApp/static/mapApp/images/sponsorLogos/victoria.gif -------------------------------------------------------------------------------- /mapApp/static/mapApp/images/team_photos/Colin.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/mapApp/static/mapApp/images/team_photos/Colin.jpg -------------------------------------------------------------------------------- /mapApp/static/mapApp/images/team_photos/Jeneva.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/mapApp/static/mapApp/images/team_photos/Jeneva.jpg -------------------------------------------------------------------------------- /mapApp/static/mapApp/images/team_photos/Thumbs.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/mapApp/static/mapApp/images/team_photos/Thumbs.db -------------------------------------------------------------------------------- /mapApp/static/mapApp/images/team_photos/ben.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/mapApp/static/mapApp/images/team_photos/ben.jpg -------------------------------------------------------------------------------- /mapApp/static/mapApp/images/team_photos/dan.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/mapApp/static/mapApp/images/team_photos/dan.jpg -------------------------------------------------------------------------------- /mapApp/static/mapApp/images/team_photos/darren.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/mapApp/static/mapApp/images/team_photos/darren.jpg -------------------------------------------------------------------------------- /mapApp/static/mapApp/images/team_photos/finn.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/mapApp/static/mapApp/images/team_photos/finn.jpg -------------------------------------------------------------------------------- /mapApp/static/mapApp/images/team_photos/heather.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/mapApp/static/mapApp/images/team_photos/heather.jpg -------------------------------------------------------------------------------- /mapApp/static/mapApp/images/team_photos/jaimy.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/mapApp/static/mapApp/images/team_photos/jaimy.jpg -------------------------------------------------------------------------------- /mapApp/static/mapApp/images/team_photos/karen.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/mapApp/static/mapApp/images/team_photos/karen.jpg -------------------------------------------------------------------------------- /mapApp/static/mapApp/images/team_photos/meghan.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/mapApp/static/mapApp/images/team_photos/meghan.jpg -------------------------------------------------------------------------------- /mapApp/static/mapApp/images/team_photos/michael.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/mapApp/static/mapApp/images/team_photos/michael.jpg -------------------------------------------------------------------------------- /mapApp/static/mapApp/images/team_photos/moreno.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/mapApp/static/mapApp/images/team_photos/moreno.jpg -------------------------------------------------------------------------------- /mapApp/static/mapApp/images/team_photos/taylor.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/mapApp/static/mapApp/images/team_photos/taylor.jpg -------------------------------------------------------------------------------- /mapApp/static/mapApp/images/team_photos/trisalyn.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/mapApp/static/mapApp/images/team_photos/trisalyn.jpg -------------------------------------------------------------------------------- /mapApp/static/mapApp/images/updates/Piechartnov14.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/mapApp/static/mapApp/images/updates/Piechartnov14.jpg -------------------------------------------------------------------------------- /mapApp/static/mapApp/images/updates/countries.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/mapApp/static/mapApp/images/updates/countries.jpg -------------------------------------------------------------------------------- /mapApp/static/mapApp/images/updates/fatalityrates.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/mapApp/static/mapApp/images/updates/fatalityrates.jpg -------------------------------------------------------------------------------- /mapApp/static/mapApp/images/updates/hotspots.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/mapApp/static/mapApp/images/updates/hotspots.jpg -------------------------------------------------------------------------------- /mapApp/static/mapApp/images/url_logo.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/mapApp/static/mapApp/images/url_logo.xcf -------------------------------------------------------------------------------- /mapApp/static/mapApp/js/csrfheader.js: -------------------------------------------------------------------------------- 1 | // This code adds the X-CSRFHeader to all ajax requests. This code is taken directly from the Django documentation under the AJAX section of the CSRF protection. Jquery must be included before this script. 2 | 3 | function getCookie(name) { 4 | var cookieValue = null; 5 | if (document.cookie && document.cookie != '') { 6 | var cookies = document.cookie.split(';'); 7 | for (var i = 0; i < cookies.length; i++) { 8 | var cookie = jQuery.trim(cookies[i]); 9 | // Does this cookie string begin with the name we want? 10 | if (cookie.substring(0, name.length + 1) == (name + '=')) { 11 | cookieValue = decodeURIComponent(cookie.substring(name.length + 1)); 12 | break; 13 | } 14 | } 15 | } 16 | return cookieValue; 17 | } 18 | 19 | function csrfSafeMethod(method) { 20 | // these HTTP methods do not require CSRF protection 21 | return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method)); 22 | } 23 | function sameOrigin(url) { 24 | // test that a given url is a same-origin URL 25 | // url could be relative or scheme relative or absolute 26 | var host = document.location.host; // host + port 27 | var protocol = document.location.protocol; 28 | var sr_origin = '//' + host; 29 | var origin = protocol + sr_origin; 30 | // Allow absolute or scheme relative URLs to same origin 31 | return (url == origin || url.slice(0, origin.length + 1) == origin + '/') || 32 | (url == sr_origin || url.slice(0, sr_origin.length + 1) == sr_origin + '/') || 33 | // or any other URL that isn't scheme relative or absolute i.e relative. 34 | !(/^(\/\/|http:|https:).*/.test(url)); 35 | } 36 | 37 | $(function(){ 38 | var csrftoken = getCookie('csrftoken'); 39 | $.ajaxSetup({ 40 | beforeSend: function(xhr, settings) { 41 | if (!csrfSafeMethod(settings.type) && sameOrigin(settings.url)) { 42 | // Send the token to same-origin, relative URLs only. 43 | // Send the token only if the method warrants CSRF protection 44 | // Using the CSRFToken value acquired earlier 45 | xhr.setRequestHeader("X-CSRFToken", csrftoken); 46 | } 47 | } 48 | }); 49 | }) 50 | -------------------------------------------------------------------------------- /mapApp/static/mapApp/js/legend_collapse.js: -------------------------------------------------------------------------------- 1 | $(document).ready(function(){ 2 | // Control sublegend collapsing 3 | $("input.layer-toggle").click(function(e) { 4 | layerClicked = window[e.target.value]; 5 | checked = e.target.checked; 6 | subLegend = $(e.target).siblings(".legend-subtext"); 7 | if(checked){ 8 | map.addLayer(layerClicked); 9 | subLegend.collapse("show"); 10 | } 11 | else if (map.hasLayer(layerClicked) && !checked) { 12 | map.removeLayer(layerClicked); 13 | subLegend.collapse("hide"); 14 | } 15 | }); 16 | 17 | 18 | // Control legend collapsing (modified code from leaflet/src/L.control.layers) 19 | var container = $('#legend .leaflet-control-layers'); 20 | 21 | $(window).resize( function(e){ 22 | if( $(window).width() < 700 ){ 23 | var link = $('#legend .leaflet-control-layers-toggle'), 24 | map = $('#map'); 25 | 26 | if (!L.Browser.android) { 27 | container.mouseenter(expand); 28 | container.mouseleave(collapse); 29 | } 30 | 31 | if (L.Browser.touch) { 32 | link.click(function(e){ 33 | e.stopPropagation(); 34 | expand(); 35 | }); 36 | } else { 37 | link.focus(expand); 38 | } 39 | 40 | map.click(collapse); 41 | } 42 | 43 | else { 44 | expand(); 45 | } 46 | }); 47 | $(window).trigger('resize'); //Call event handler on load 48 | 49 | function expand() { 50 | container.addClass('leaflet-control-layers-expanded'); 51 | }; 52 | 53 | function collapse() { 54 | container.removeClass('leaflet-control-layers-expanded'); 55 | }; 56 | }); 57 | -------------------------------------------------------------------------------- /mapApp/static/mapApp/js/map.js: -------------------------------------------------------------------------------- 1 | // Define tile layers 2 | var MapQuestOpen_OSM = L.tileLayer('http://otile{s}.mqcdn.com/tiles/1.0.0/map/{z}/{x}/{y}.jpeg', { 3 | attribution: 'Tiles Courtesy of MapQuest — Map data © OpenStreetMap', 4 | subdomains: '1234' 5 | }), 6 | OpenStreetMap = L.tileLayer('https://{s}.tile.osm.org/{z}/{x}/{y}.png', { 7 | minZoom: 15, 8 | attribution: '© OpenStreetMap contributors' 9 | }), 10 | OpenStreetMapNoZoom = L.tileLayer('https://{s}.tile.osm.org/{z}/{x}/{y}.png', { 11 | attribution: '© OpenStreetMap contributors' 12 | }), 13 | CyclOSM = L.tileLayer('https://{s}.tile-cyclosm.openstreetmap.fr/cyclosm/{z}/{x}/{y}.png', { 14 | minZoom: 15, 15 | attribution: '© OpenStreetMap contributors' 16 | }), 17 | // http://leaflet-extras.github.io/leaflet-providers/preview/ 18 | HOTOSM = L.tileLayer('https://{s}.tile.openstreetmap.fr/hot/{z}/{x}/{y}.png', { 19 | maxZoom: 14, 20 | attribution: '© OpenStreetMap contributors' 21 | }), 22 | Mapnik_BW = L.tileLayer('http://{s}.www.toolserver.org/tiles/bw-mapnik/{z}/{x}/{y}.png', { 23 | attribution: '© OpenStreetMap contributors, CC-BY-SA', 24 | subdomains: '1234' 25 | }), 26 | stravaHM = L.tileLayer('https://heatmap-external-{s}.strava.com/tiles/ride/gray/{z}/{x}/{y}.png', { 27 | minZoom: 3, 28 | maxZoom: 13, 29 | maxNativeZoom: 11, 30 | opacity: 0.8, 31 | attribution: 'http://labs.strava.com/heatmap/' 32 | }); 33 | 34 | var osmUrl = 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png'; 35 | var osmAttrib = 'Map data � OpenStreetMap'; 36 | var osm = new L.TileLayer(osmUrl); 37 | -------------------------------------------------------------------------------- /mapApp/static/mapApp/js/override.js: -------------------------------------------------------------------------------- 1 | // Overrides the default leaflet layer control to allow for checkboxes that control sublayers 2 | L.Control.Layers = L.Control.Layers.extend({ 3 | _onInputClick: function () { 4 | var inputs = this._form.getElementsByClassName('leaflet-control-layers-selector'), //this is the line changed from the source code, selects by class rather than selecting all input tags 5 | input, layer, hasLayer; 6 | var addedLayers = [], 7 | removedLayers = []; 8 | 9 | this._handlingClick = true; 10 | 11 | for (var i = 0, len = inputs.length; i < len; i++) { 12 | input = inputs[i]; 13 | layer = this._layers[input.layerId].layer; 14 | hasLayer = this._map.hasLayer(layer); 15 | 16 | if (input.checked && !hasLayer) { 17 | addedLayers.push(layer); 18 | 19 | } else if (!input.checked && hasLayer) { 20 | removedLayers.push(layer); 21 | } 22 | } 23 | 24 | // Bugfix issue 2318: Should remove all old layers before readding new ones 25 | for (i = 0; i < removedLayers.length; i++) { 26 | this._map.removeLayer(removedLayers[i]); 27 | } 28 | for (i = 0; i < addedLayers.length; i++) { 29 | this._map.addLayer(addedLayers[i]); 30 | } 31 | 32 | this._handlingClick = false; 33 | 34 | this._refocusOnMap(); 35 | }, 36 | 37 | 38 | _addItem: function (obj) { 39 | var label = document.createElement('label'), 40 | checked = this._map.hasLayer(obj.layer), 41 | input; 42 | 43 | if (obj.overlay) { 44 | input = document.createElement('input'); 45 | input.type = 'checkbox'; 46 | input.className = 'leaflet-control-layers-selector'; 47 | input.defaultChecked = checked; 48 | } else { 49 | input = this._createRadioElement('leaflet-base-layers', checked); 50 | } 51 | input.layerId = L.stamp(obj.layer); 52 | 53 | L.DomEvent.on(input, 'click', this._onInputClick, this); 54 | 55 | var name = document.createElement('span'); 56 | name.innerHTML = ' ' + obj.name; 57 | 58 | label.appendChild(input); 59 | label.appendChild(name); 60 | 61 | var container = obj.overlay ? this._overlaysList : this._baseLayersList; 62 | container.appendChild(label); 63 | 64 | return label; 65 | }, 66 | 67 | 68 | }); 69 | -------------------------------------------------------------------------------- /mapApp/static/mapApp/js/vis/map.js: -------------------------------------------------------------------------------- 1 | // Leaflet heatmap 2 | var heatLayer = new HeatmapOverlay({ "radius": 20, "maxOpacity": 0.3 }); 3 | var heat_data; 4 | 5 | var map = L.map('map', { 6 | center: [15,6], 7 | zoom: 1, 8 | minZoom: 1, 9 | zoomControl: false, 10 | scrollWheelZoom: true, 11 | worldCopyJump: true, 12 | layers: [OpenStreetMapNoZoom, heatLayer] 13 | }).on('load', changeMap()) 14 | .on('moveend', mapFilter); 15 | 16 | // Add i18n zoom control 17 | L.control.zoom({ 18 | zoomInTitle: gettext('Zoom in'), 19 | zoomOutTitle: gettext('Zoom out'), 20 | }).addTo(map); 21 | 22 | /* If coordinates have been passed in through the URL, go to that location 23 | ** If not, go to the last known location for a smooth transition between 24 | ** homepage and vis page 25 | ** Default view is global (zoom of 1) 26 | */ 27 | if (typeof zoom !== 'undefined') { 28 | map.setView(L.latLng(lat, lng), zoom); 29 | } else if (localStorage.getItem('lastKnownLat') !== null) { 30 | let lastKnownLat = localStorage.getItem('lastKnownLat'); 31 | let lastKnownLng = localStorage.getItem('lastKnownLng'); 32 | let lastKnownZoom = localStorage.getItem('lastKnownZoom'); 33 | map.setView(L.latLng(lastKnownLat, lastKnownLng), lastKnownZoom); 34 | } 35 | 36 | /** Add geocoder control */ 37 | var geocodeMarker; 38 | var geocoder = L.Control.geocoder({ 39 | defaultMarkGeocode: false, 40 | position: "topleft", 41 | placeholder: gettext('Search...'), 42 | errorMessage: gettext('Nothing found.') 43 | }).on('markgeocode', function(result) { 44 | map.fitBounds(result.geocode.bbox); 45 | geocodeMarker && map.removeLayer(geocodeMarker); //remove old marker if it exists 46 | geocodeMarker = new L.Marker(result.geocode.center, { 47 | icon: icons["geocodeIcon"] 48 | }).bindPopup(result.geocode.name).addTo(map).openPopup(); 49 | }).addTo(map); 50 | -------------------------------------------------------------------------------- /mapApp/templates/mapApp/disclaimer.html: -------------------------------------------------------------------------------- 1 | {% extends "mapApp/base.html" %} 2 | {% load i18n cache %} 3 | 4 | {% get_current_language as LANGUAGE_CODE %} 5 | {% cache 3600 terms_and_conditions LANGUAGE_CODE %} 6 | 7 | {% block title %}{% trans "Disclaimer" %}{% endblock %} 8 | {% block body %} 9 |
10 |
11 |

{% trans "Disclaimer" %}

12 | 13 |

{% blocktrans %}BikeMaps.org makes no representations, express or implied, as to the accuracy, completeness and timeliness of the information, maps, and data contained herein. Conclusions drawn or decisions made from the information provided on BikeMaps.org are the responsibility of the user. BikeMaps.org assumes no responsibility for its use.{% endblocktrans %}

14 | 15 | 16 |
17 |
18 | {% endblock %} 19 | 20 | {% endcache %} 21 | -------------------------------------------------------------------------------- /mapApp/templates/mapApp/overlays.html: -------------------------------------------------------------------------------- 1 | {% load i18n cache %} 2 | {% load user_agents %} 3 | {% get_current_language as LANGUAGE_CODE %} 4 | {% cache 500 overlays LANGUAGE_CODE %} 5 | 6 | 7 | {% if not request.user_agent.is_mobile %} 8 |
9 | 13 | 16 |
17 | 18 | 19 | 20 | 23 | {% endif %} 24 | 25 | {% endcache %} 26 | -------------------------------------------------------------------------------- /mapApp/templates/mapApp/recent_reports.html: -------------------------------------------------------------------------------- 1 | {% extends "mapApp/base.html" %} 2 | {% load static geojson_tags i18n %} 3 | 4 | {% block title %} 5 | {% trans "BikeMaps Recent Reports" %} 6 | {% endblock %} 7 | 8 | {% block headerCSS %} 9 | 10 | {% endblock %} 11 | 12 | {% block body %} 13 | 14 | 15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 | 26 | 27 | {% endblock %} 28 | 29 | {% block footerJS %} 30 | 31 | 32 | 42 | 56 | 57 | 58 | 59 | {% endblock %} 60 | -------------------------------------------------------------------------------- /mapApp/templates/mapApp/util/bootstrap3_datepicker.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 9 | 10 | {% load crispy_forms_field i18n %} 11 |
12 | {% if field.label %} 13 | 16 | {% endif %} 17 | 18 | 19 |
20 |
21 | {% crispy_field field %} 22 | 23 | 24 | {{ crispy_appended_text|safe }} 25 | 26 |
27 |
28 | {% include 'bootstrap3/layout/help_text_and_errors.html' %} 29 |
30 | 31 | {% get_current_language as LANGUAGE_CODE %} 32 | -------------------------------------------------------------------------------- /mapApp/templates/mapApp/util/bootstrap3_datepicker_future.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 9 | 10 | {% load crispy_forms_field i18n %} 11 |
12 | {% if field.label %} 13 | 16 | {% endif %} 17 | 18 | 19 |
20 |
21 | {% crispy_field field %} 22 | 23 | 24 | {{ crispy_appended_text|safe }} 25 | 26 |
27 |
28 | {% include 'bootstrap3/layout/help_text_and_errors.html' %} 29 |
30 | 31 | {% get_current_language as LANGUAGE_CODE %} 32 | -------------------------------------------------------------------------------- /mapApp/templatetags/__init__.py: -------------------------------------------------------------------------------- 1 | from .bikemaps_tags import * 2 | -------------------------------------------------------------------------------- /mapApp/templatetags/bikemaps_tags.py: -------------------------------------------------------------------------------- 1 | from django import template 2 | register = template.Library() 3 | 4 | from mapApp.models import IncidentNotification, HazardNotification, TheftNotification, Point, AlertArea 5 | import datetime 6 | 7 | import logging 8 | logger = logging.getLogger(__name__) 9 | 10 | 11 | @register.simple_tag() 12 | def has_alerts(user): 13 | return ( 14 | IncidentNotification.objects.filter(user=user).filter(is_read=False).exists()\ 15 | or \ 16 | HazardNotification.objects.filter(user=user).filter(is_read=False).exists()\ 17 | or \ 18 | TheftNotification.objects.filter(user=user).filter(is_read=False).exists() 19 | ) 20 | 21 | 22 | @register.simple_tag() 23 | def reports_this_week(user): 24 | now = datetime.datetime.now() 25 | lastweek = now - datetime.timedelta(days=7) 26 | 27 | polys = AlertArea.objects.filter(user=user) 28 | points = Point.objects.filter(date__range=[lastweek, now]) 29 | 30 | if not points.exists(): 31 | return False 32 | 33 | for poly in polys: 34 | if points.filter(geom__intersects=poly.geom).exists(): 35 | return True 36 | return False 37 | -------------------------------------------------------------------------------- /mapApp/utils/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/mapApp/utils/__init__.py -------------------------------------------------------------------------------- /mapApp/utils/weather4all.py: -------------------------------------------------------------------------------- 1 | from mapApp.models import Incident, Weather 2 | from mapApp.utils.weather import get_weather 3 | import threading 4 | import time 5 | 6 | maxconnections = 1 7 | maxthreads = 100 8 | db_semaphore = threading.Semaphore(maxconnections) 9 | thread_create = threading.Semaphore(maxthreads) 10 | 11 | def run(): 12 | """ Create Weather instances for all Incidents in the application database if they do not already exist 13 | """ 14 | start_t = time.time() 15 | processed = 0 16 | 17 | for incident in Incident.objects.all(): 18 | # Create a new Weather instance using a non-blocking thread 19 | processed += 1 20 | 21 | thread_create.acquire() 22 | thread = WeatherThread(incident) 23 | thread.start() 24 | thread.join() 25 | thread_create.release() 26 | 27 | end_t = time.time() 28 | print(processed, "Incidents processed in", end_t - start_t, "s") 29 | 30 | class WeatherThread(threading.Thread): 31 | def __init__(self, incident): 32 | self.incident = incident 33 | super(WeatherThread, self).__init__() 34 | 35 | def run(self): 36 | data = get_weather(self.incident.geom, self.incident.date) 37 | db_semaphore.acquire() 38 | Weather( 39 | incident = self.incident, 40 | summary = data['summary'], 41 | sunrise_time = data['sunrise_time'], 42 | sunset_time = data['sunset_time'], 43 | dawn = data['dawn'], 44 | dusk = data['dusk'], 45 | precip_intensity = data['precip_intensity'], 46 | precip_probability = data['precip_probability'], 47 | precip_type = data['precip_type'], 48 | temperature = data['temperature'], 49 | black_ice_risk = data['black_ice_risk'], 50 | wind_speed = data['wind_speed'], 51 | wind_bearing = data['wind_bearing'], 52 | wind_bearing_str = data['wind_bearing_str'], 53 | visibility_km = data['visibility_km'], 54 | ).save() 55 | db_semaphore.release() 56 | -------------------------------------------------------------------------------- /mapApp/views/__init__.py: -------------------------------------------------------------------------------- 1 | from .about import about, contact 2 | from .alerts import alertUsers, postAlertPolygon, readAlertPoint 3 | from .disclaimer import disclaimer 4 | from .edit import editHazards, editShape, updateHazard 5 | from .index import index 6 | from .postPoint import (postHazard, postIncident, postNearmiss, 7 | postNewInfrastructure, postTheft) 8 | from .pushNotification import pushNotification 9 | from .recentReports import recentReports 10 | from .restApi import (AlertAreaDetail, AlertAreaList, APNSDeviceDetail, 11 | APNSDeviceList, CollisionList, FilteredHazardList, 12 | FilteredTheftList, GCMDeviceDetail, GCMDeviceList, 13 | HazardList, IncidentOnlyList, IncidentList, IncidentWeatherList, NearmissList, OfficialList, 14 | TheftList, TinyCollisionList, TinyHazardList, 15 | TinyNearMissList, TinyNewInfrastructureList, 16 | TinyTheftList, UserDetail, UserList, XHRCollisionInfo, 17 | XHRHazardInfo, XHRNearMissInfo, XHRNewInfrastructureInfo, 18 | XHRTheftInfo) 19 | from .termsAndConditions import termsAndConditions 20 | from .vis import vis 21 | -------------------------------------------------------------------------------- /mapApp/views/about.py: -------------------------------------------------------------------------------- 1 | from django.utils.translation import ugettext as _, get_language 2 | from django.shortcuts import render 3 | 4 | from django.views.decorators.http import require_POST 5 | from django.contrib import messages 6 | from django.core.mail import BadHeaderError, EmailMessage 7 | 8 | from django.http import HttpResponse 9 | from django.views.decorators.clickjacking import xframe_options_exempt 10 | 11 | from mapApp.forms import EmailForm 12 | 13 | # default language is 'en-ca' (see VicBikeMap/settings/base.py) but want to be able to capture other english language codes (such as en-us, en-gb, en-au) 14 | def isCurrLangEnglish(currLang): 15 | return currLang.startswith('en') 16 | 17 | # @cache_page(60 * 60) 18 | @xframe_options_exempt 19 | def about(request): 20 | return render(request, 'mapApp/about.html', {"emailForm": EmailForm(), "currLangEnglish": isCurrLangEnglish(get_language())}) 21 | 22 | @require_POST 23 | def contact(request): 24 | emailForm = EmailForm(request.POST) 25 | 26 | if emailForm.is_valid(): 27 | subject = '[BikeMaps] '+ emailForm.cleaned_data['subject'] 28 | message = emailForm.cleaned_data['message'] 29 | sender = emailForm.cleaned_data['sender'] 30 | cc_myself = emailForm.cleaned_data['cc_myself'] 31 | 32 | recipients = ['admin@bikemaps.org','tech-support@bikemaps.org'] 33 | cc = [sender] if cc_myself else [] 34 | 35 | email = EmailMessage(subject, message, 'admin@bikemaps.org', recipients, headers = {'Reply-To': sender}, cc = cc) 36 | 37 | try: 38 | email.send() 39 | messages.success(request, '' + _('Thank you!') + '
' + _('We\'ll do our best to get back to you soon.')) 40 | emailForm = EmailForm() # Clear the form 41 | except BadHeaderError: 42 | messages.error(request, ''+ _('Invalid Header.') + '' + _('Illegal characters found.')) 43 | 44 | return render(request, 'mapApp/about.html', {"emailForm": emailForm, "currLangEnglish": isCurrLangEnglish(get_language())}) 45 | -------------------------------------------------------------------------------- /mapApp/views/disclaimer.py: -------------------------------------------------------------------------------- 1 | from django.shortcuts import render 2 | from django.http import HttpResponse 3 | from django.views.decorators.clickjacking import xframe_options_exempt 4 | 5 | @xframe_options_exempt 6 | def disclaimer(request): 7 | return render(request, 'mapApp/disclaimer.html') 8 | -------------------------------------------------------------------------------- /mapApp/views/index.py: -------------------------------------------------------------------------------- 1 | from django.contrib.gis.geos import Polygon 2 | from django.shortcuts import render 3 | 4 | 5 | from django.http import HttpResponse 6 | from django.views.decorators.clickjacking import xframe_options_exempt 7 | 8 | from mapApp.models import Incident, Theft, Hazard, Official, AlertArea, NewInfrastructure 9 | from mapApp.forms import IncidentForm, NearmissForm, HazardForm, TheftForm, NewInfrastructureForm, GeofenceForm, EditForm 10 | import datetime 11 | 12 | import logging 13 | logger = logging.getLogger(__name__) 14 | 15 | @xframe_options_exempt 16 | def index(request, lat=None, lng=None, zoom=None): 17 | context = { 18 | # Model data used by map 19 | 'officials': Official.objects.filter(geom__within=(Polygon.from_bbox((5,47,15,55)))), 20 | "geofences": AlertArea.objects.filter(user=request.user.id), 21 | 22 | # Form data used by map 23 | "incidentForm": IncidentForm(), 24 | "nearmissForm": NearmissForm(), 25 | "hazardForm": HazardForm(), 26 | "theftForm": TheftForm(), 27 | "newInfrastructureForm": NewInfrastructureForm(), 28 | "geofenceForm": GeofenceForm(), 29 | "editForm": EditForm() 30 | } 31 | 32 | # Add zoom and center data if present 33 | if not None in [lat, lng, zoom]: 34 | context['lat']= float(lat) 35 | context['lng']= float(lng) 36 | context['zoom']= int(zoom) 37 | 38 | return render(request, 'mapApp/index.html', context) 39 | -------------------------------------------------------------------------------- /mapApp/views/recentReports.py: -------------------------------------------------------------------------------- 1 | from django.shortcuts import render 2 | from django.http import HttpResponse 3 | from django.contrib.auth.decorators import login_required 4 | import datetime 5 | 6 | from mapApp.models import Incident, Hazard, Theft, AlertArea 7 | 8 | @login_required 9 | def recentReports(request): 10 | user = request.user 11 | 12 | # Get the user's alertable points in the last month 13 | collisions = Incident.objects.filter(p_type__exact="collision") | Incident.objects.filter(p_type__exact="fall") 14 | nearmisses = Incident.objects.filter(p_type__exact="nearmiss") 15 | hazards = Hazard.objects.all() 16 | thefts = Theft.objects.all() 17 | 18 | # Get only points that intersect user alert areas 19 | rois = AlertArea.objects.filter(user=user.id) 20 | # recent sets = points that intersect an rois as defined by user and are reported in last month 21 | collisionsInPoly = Incident.objects.none() 22 | nearmissesInPoly = Incident.objects.none() 23 | hazardsInPoly = Hazard.objects.none() 24 | theftsInPoly = Theft.objects.none() 25 | # Find intersecting points 26 | for g in rois: 27 | collisionsInPoly = collisionsInPoly | collisions.filter(geom__intersects=g.geom) 28 | nearmissesInPoly = nearmissesInPoly | nearmisses.filter(geom__intersects=g.geom) 29 | hazardsInPoly = hazardsInPoly | hazards.filter(geom__intersects=g.geom) 30 | theftsInPoly = theftsInPoly | thefts.filter(geom__intersects=g.geom) 31 | 32 | now = datetime.datetime.now() 33 | lastweek = now - datetime.timedelta(days=7) 34 | 35 | context = { 36 | 'collisions': collisionsInPoly.filter(date__range=[lastweek, now]).order_by('-date'), 37 | 'nearmisses': nearmissesInPoly.filter(date__range=[lastweek, now]).order_by('-date'), 38 | 'hazards': hazardsInPoly.filter(date__range=[lastweek, now]).order_by('-date'), 39 | 'thefts': theftsInPoly.filter(date__range=[lastweek, now]).order_by('-date'), 40 | 41 | 'geofences': rois 42 | } 43 | 44 | return render(request, 'mapApp/recent_reports.html', context) 45 | -------------------------------------------------------------------------------- /mapApp/views/termsAndConditions.py: -------------------------------------------------------------------------------- 1 | from django.shortcuts import render 2 | 3 | from django.http import HttpResponse 4 | from django.views.decorators.clickjacking import xframe_options_exempt 5 | 6 | @xframe_options_exempt 7 | def termsAndConditions(request): 8 | return render(request, 'mapApp/ethics.html') 9 | -------------------------------------------------------------------------------- /mapApp/views/vis.py: -------------------------------------------------------------------------------- 1 | from django.shortcuts import render 2 | from django.http import HttpResponse 3 | from django.views.decorators.clickjacking import xframe_options_exempt 4 | 5 | from mapApp.models import AlertArea, Point 6 | 7 | @xframe_options_exempt 8 | def vis(request, lat=None, lng=None, zoom=None): 9 | context = { 10 | 'alertAreas': AlertArea.objects.filter(user=request.user.id), 11 | 'points': Point.objects.all().exclude(infrastructure_changed=True).exclude(p_type = "newInfrastructure") 12 | } 13 | 14 | # Add zoom and center data if present 15 | if not None in [lat, lng, zoom]: 16 | context['lat']= float(lat) 17 | context['lng']= float(lng) 18 | context['zoom']= int(zoom) 19 | 20 | return render(request, 'mapApp/vis.html', context) 21 | -------------------------------------------------------------------------------- /media/mapApp/collision_teardrop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/media/mapApp/collision_teardrop.png -------------------------------------------------------------------------------- /media/mapApp/nearmiss_teardrop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/media/mapApp/nearmiss_teardrop.png -------------------------------------------------------------------------------- /middlewares/__init__.py: -------------------------------------------------------------------------------- 1 | from .force_default_middleware import * 2 | -------------------------------------------------------------------------------- /middlewares/force_default_middleware.py: -------------------------------------------------------------------------------- 1 | """Created by github user vstoykov to force the default language defined in LANGUAGE_CODE instead of accepting the http header language""" 2 | 3 | class ForceDefaultLanguageMiddleware(object): 4 | """ 5 | Ignore Accept-Language HTTP headers 6 | 7 | This will force the I18N machinery to always choose settings.LANGUAGE_CODE 8 | as the default initial language, unless another one is set via sessions or cookies 9 | 10 | Should be installed *before* any middleware that checks request.META['HTTP_ACCEPT_LANGUAGE'], 11 | namely django.middleware.locale.LocaleMiddleware 12 | """ 13 | def process_request(self, request): 14 | if 'HTTP_ACCEPT_LANGUAGE' in request.META: 15 | del request.META['HTTP_ACCEPT_LANGUAGE'] 16 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | apns2==0.7.2 2 | asymmetric-jwt-auth==0.5.0 3 | certbot-django==0.2.0 4 | certifi==2020.12.5 5 | cffi==1.14.4 6 | chardet==3.0.4 7 | cryptography==3.2.1 8 | Django==3.1.7 9 | django-allauth==0.44.0 10 | django-common-helpers==0.9.1 11 | django-cors-headers==3.7.0 12 | django-crispy-forms==1.11.1 13 | django-debug-toolbar==3.2 14 | django-geojson==3.1.0 15 | django-leaflet==0.22.0 16 | django-markdown-deux==1.0.5 17 | django-push-notifications==2.0.0 18 | django-ratelimit==1.0.1 19 | django-rest-auth==0.9.1 20 | django-uuidfield==0.5.0 21 | djangorestframework==3.12.2 22 | djangorestframework-gis==0.16.0 23 | enum34==1.1.10 24 | h2==2.6.2 25 | hpack==3.0.0 26 | hyper==0.7.0 27 | hyperframe==3.2.0 28 | idna==2.5 29 | ipaddress==1.0.23 30 | Markdown==2.6.2 31 | markdown2==2.3.0 32 | user-agents==2.2.0 33 | django-user-agents==0.4.0 34 | oauthlib==2.0.2 35 | olefile==0.46 36 | Pillow==8.1.0 37 | psycopg2==2.8.6 38 | pycparser==2.20 39 | PyJWT==1.7.1 40 | python-openid==2.2.5 41 | pytz==2020.4 42 | requests==2.18.3 43 | requests-oauthlib==0.8.0 44 | six==1.15.0 45 | solid-i18n==1.4.2 46 | sqlparse==0.2.3 47 | urllib3==1.22 48 | django-reset-migrations===0.4.0 49 | -------------------------------------------------------------------------------- /spirit/__init__.py: -------------------------------------------------------------------------------- 1 | __version__ = '0.1.1' -------------------------------------------------------------------------------- /spirit/locale/da/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/spirit/locale/da/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /spirit/locale/de/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/spirit/locale/de/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /spirit/locale/en/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/spirit/locale/en/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /spirit/locale/es/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/spirit/locale/es/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /spirit/locale/fi/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/spirit/locale/fi/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /spirit/locale/fr/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/spirit/locale/fr/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /spirit/locale/is/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/spirit/locale/is/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /spirit/locale/nl/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/spirit/locale/nl/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /spirit/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/spirit/migrations/__init__.py -------------------------------------------------------------------------------- /spirit/models/__init__.py: -------------------------------------------------------------------------------- 1 | from .user import User 2 | -------------------------------------------------------------------------------- /spirit/utils/__init__.py: -------------------------------------------------------------------------------- 1 | #-*- coding: utf-8 -*- 2 | 3 | import os 4 | import json 5 | 6 | from django.template.loader import render_to_string 7 | from django.http import HttpResponse 8 | 9 | 10 | def render_form_errors(form): 11 | return render_to_string('spirit/utils/_form_errors.html', {'form': form, }) 12 | 13 | 14 | def json_response(data=None, status=200): 15 | # TODO: Use JsonResponse on Django 1.7 16 | data = data or {} 17 | return HttpResponse(json.dumps(data), content_type='application/json', status=status) 18 | 19 | 20 | def mkdir_p(path): 21 | try: 22 | os.makedirs(path) 23 | except OSError: 24 | if not os.path.isdir(path): 25 | raise -------------------------------------------------------------------------------- /spirit/utils/decorators.py: -------------------------------------------------------------------------------- 1 | #-*- coding: utf-8 -*- 2 | 3 | from functools import wraps 4 | 5 | from django.core.exceptions import PermissionDenied 6 | from django.contrib.auth import redirect_to_login 7 | from django.conf import settings 8 | 9 | 10 | def moderator_required(view_func): 11 | @wraps(view_func) 12 | def wrapper(request, *args, **kwargs): 13 | user = request.user 14 | 15 | if not user.is_authenticated(): 16 | return redirect_to_login(next=request.get_full_path(), 17 | login_url=settings.LOGIN_URL) 18 | 19 | if not user.is_moderator: 20 | raise PermissionDenied 21 | 22 | return view_func(request, *args, **kwargs) 23 | 24 | return wrapper 25 | 26 | 27 | def administrator_required(view_func): 28 | @wraps(view_func) 29 | def wrapper(request, *args, **kwargs): 30 | user = request.user 31 | 32 | if not user.is_authenticated(): 33 | return redirect_to_login(next=request.get_full_path(), 34 | login_url=settings.LOGIN_URL) 35 | 36 | if not user.is_administrator: 37 | raise PermissionDenied 38 | 39 | return view_func(request, *args, **kwargs) 40 | 41 | return wrapper -------------------------------------------------------------------------------- /spirit/utils/forms.py: -------------------------------------------------------------------------------- 1 | #-*- coding: utf-8 -*- 2 | 3 | from django import forms 4 | from django.utils.html import conditional_escape, mark_safe 5 | from six import smart_text 6 | 7 | 8 | class NestedModelChoiceField(forms.ModelChoiceField): 9 | """A ModelChoiceField that groups parents and childrens""" 10 | # TODO: subclass ModelChoiceIterator, remove _populate_choices() 11 | def __init__(self, related_name, parent_field, label_field, *args, **kwargs): 12 | """ 13 | @related_name: related_name or "FOO_set" 14 | @parent_field: ForeignKey('self') field, use 'name_id' to save some queries 15 | @label_field: field for obj representation 16 | """ 17 | super(NestedModelChoiceField, self).__init__(*args, **kwargs) 18 | self.related_name = related_name 19 | self.parent_field = parent_field 20 | self.label_field = label_field 21 | self._populate_choices() 22 | 23 | def _populate_choices(self): 24 | # This is *hackish* but simpler than subclassing ModelChoiceIterator 25 | choices = [("", self.empty_label), ] 26 | kwargs = {self.parent_field: None, } 27 | queryset = self.queryset.filter(**kwargs)\ 28 | .prefetch_related(self.related_name) 29 | 30 | for parent in queryset: 31 | choices.append((self.prepare_value(parent), self.label_from_instance(parent))) 32 | choices.extend([(self.prepare_value(children), self.label_from_instance(children)) 33 | for children in getattr(parent, self.related_name).all()]) 34 | 35 | self.choices = choices 36 | 37 | def label_from_instance(self, obj): 38 | level_indicator = "" 39 | 40 | if getattr(obj, self.parent_field): 41 | level_indicator = "--- " 42 | 43 | return mark_safe(level_indicator + conditional_escape(smart_text(getattr(obj, self.label_field)))) 44 | -------------------------------------------------------------------------------- /spirit/utils/markdown/__init__.py: -------------------------------------------------------------------------------- 1 | #-*- coding: utf-8 -*- 2 | 3 | from .quote import quotify -------------------------------------------------------------------------------- /spirit/utils/markdown/audio.py: -------------------------------------------------------------------------------- 1 | #-*- coding: utf-8 -*- 2 | 3 | import re 4 | 5 | from markdown.extensions import Extension 6 | from markdown.preprocessors import Preprocessor 7 | 8 | from django.utils.html import escape as html_escape 9 | 10 | 11 | PATTERN_RE = r'^https?://[^\s]+\.(mp3|ogg|wav)(\?[^\s]+)?$' 12 | 13 | 14 | class AudiofyExtension(Extension): 15 | 16 | def extendMarkdown(self, md, md_globals): 17 | md.registerExtension(self) 18 | md.preprocessors.add('audiofy', 19 | AudiofyPreprocessor(md), 20 | '_end') 21 | 22 | 23 | class AudiofyPreprocessor(Preprocessor): 24 | 25 | def run(self, lines): 26 | new_lines = [] 27 | 28 | def audiofy(match): 29 | url = match.group(0) 30 | url = html_escape(url) 31 | html = ''.format(url=url) 32 | return self.markdown.htmlStash.store(html, safe=True) 33 | 34 | for line in lines: 35 | if line.strip(): 36 | line = re.sub(PATTERN_RE, audiofy, line, flags=re.UNICODE) 37 | 38 | new_lines.append(line) 39 | 40 | return new_lines 41 | 42 | 43 | def makeExtension(configs=None): 44 | return AudiofyExtension(configs=configs) -------------------------------------------------------------------------------- /spirit/utils/markdown/image.py: -------------------------------------------------------------------------------- 1 | #-*- coding: utf-8 -*- 2 | 3 | import re 4 | 5 | from markdown.extensions import Extension 6 | from markdown.preprocessors import Preprocessor 7 | 8 | 9 | class ImagifyExtension(Extension): 10 | 11 | def extendMarkdown(self, md, md_globals): 12 | md.registerExtension(self) 13 | md.preprocessors.add('imagify', 14 | ImagifyPreprocessor(md), 15 | '_end') 16 | 17 | 18 | class ImagifyPreprocessor(Preprocessor): 19 | 20 | def run(self, lines): 21 | new_lines = [] 22 | 23 | def imagify(match): 24 | return '![image](%s)' % match.group(0) 25 | 26 | for line in lines: 27 | if line.strip(): 28 | line = re.sub(r'^https?://[^\s]+/(?P[^\s]+)\.' 29 | r'(?Ppng|jpg|jpeg|gif|bmp|tif|tiff)' 30 | r'(\?[^\s]+)?$', imagify, line, flags=re.UNICODE) 31 | 32 | new_lines.append(line) 33 | 34 | return new_lines 35 | 36 | 37 | def makeExtension(configs=None): 38 | return ImagifyExtension(configs=configs) -------------------------------------------------------------------------------- /spirit/utils/markdown/mention.py: -------------------------------------------------------------------------------- 1 | #-*- coding: utf-8 -*- 2 | 3 | import re 4 | 5 | from markdown.extensions import Extension 6 | from markdown.preprocessors import Preprocessor 7 | 8 | from django.contrib.auth import get_user_model 9 | from django.conf import settings 10 | 11 | 12 | User = get_user_model() 13 | 14 | 15 | class MentionifyExtension(Extension): 16 | 17 | def extendMarkdown(self, md, md_globals): 18 | md.registerExtension(self) 19 | md.preprocessors.add('mentionify', 20 | MentionifyPreprocessor(md), 21 | '_end') 22 | 23 | 24 | class MentionifyPreprocessor(Preprocessor): 25 | 26 | def run(self, lines): 27 | new_lines = [] 28 | matches = set() 29 | mentions = {} 30 | 31 | def mentionify(match): 32 | username = match.group(2) 33 | 34 | if len(matches) >= settings.ST_MENTIONS_PER_COMMENT: 35 | return match.group(0) 36 | 37 | if username in matches: 38 | return match.group(0) 39 | 40 | matches.add(username) 41 | 42 | try: 43 | user = User.objects.get(username=username) 44 | except User.DoesNotExist: 45 | return match.group(0) 46 | 47 | mentions[username] = user 48 | 49 | return '%s[@%s](%s)' % (match.group(1), username, user.get_absolute_url()) 50 | 51 | for line in lines: 52 | if line.strip() and not line.startswith('>'): # exclude code/quote 53 | line = re.sub(r'([^\w]?)@(?P[\w.@+-]+)', mentionify, line, flags=re.UNICODE) 54 | 55 | new_lines.append(line) 56 | 57 | # markdown_instance 58 | self.markdown.mentions = mentions 59 | 60 | return new_lines 61 | 62 | 63 | def makeExtension(configs=None): 64 | return MentionifyExtension(configs=configs) -------------------------------------------------------------------------------- /spirit/utils/markdown/quote.py: -------------------------------------------------------------------------------- 1 | #-*- coding: utf-8 -*- 2 | 3 | 4 | def quotify(comment, username): 5 | """ 6 | Converts 'Foo\nbar' to: 7 | @username 8 | > Foo 9 | > bar 10 | \n\n 11 | """ 12 | header = "@%s" % username 13 | lines = comment.splitlines() 14 | quote = "\n> ".join(lines) 15 | quote = "%(header)s\n> %(quote)s\n\n" % ({'header': header, 'quote': quote}) 16 | return quote -------------------------------------------------------------------------------- /spirit/utils/markdown/video.py: -------------------------------------------------------------------------------- 1 | #-*- coding: utf-8 -*- 2 | 3 | import re 4 | 5 | from markdown import Extension 6 | from markdown.preprocessors import Preprocessor 7 | 8 | from django.utils.html import escape as html_escape 9 | 10 | 11 | PATTERN_RE = r'^https?://[^\s]+\.(mov|mp4|webm|ogv)(\?[^\s]+)?$' 12 | 13 | 14 | class VideofyExtension(Extension): 15 | 16 | def extendMarkdown(self, md, md_globals): 17 | md.registerExtension(self) 18 | md.preprocessors.add('videofy', 19 | VideofyPreprocessor(md), 20 | '_end') 21 | 22 | 23 | class VideofyPreprocessor(Preprocessor): 24 | 25 | def run(self, lines): 26 | new_lines = [] 27 | 28 | def videofy(match): 29 | url = match.group(0) 30 | url = html_escape(url) 31 | html = ''.format(url=url) 32 | return self.markdown.htmlStash.store(html, safe=True) 33 | 34 | for line in lines: 35 | if line.strip(): 36 | line = re.sub(PATTERN_RE, videofy, line, flags=re.UNICODE) 37 | 38 | new_lines.append(line) 39 | 40 | return new_lines 41 | 42 | 43 | def makeExtension(configs=None): 44 | return VideofyExtension(configs=configs) -------------------------------------------------------------------------------- /spirit/utils/markdown/vimeo.py: -------------------------------------------------------------------------------- 1 | #-*- coding: utf-8 -*- 2 | 3 | import re 4 | 5 | from markdown import Extension 6 | from markdown.preprocessors import Preprocessor 7 | 8 | 9 | # Try to get the video ID. Works for URLs of the form: 10 | # * https://vimeo.com/11111111 11 | # * https://www.vimeo.com/11111111 12 | # * https://player.vimeo.com/video/11111111 13 | # * https://vimeo.com/channels/11111111 14 | # * https://vimeo.com/groups/name/videos/11111111 15 | # * https://vimeo.com/album/2222222/video/11111111 16 | # * https://vimeo.com/11111111?param=value 17 | PATTERN_RE = r'^https?://(www\.|player\.)?vimeo\.com/(channels/|groups/[^/]+/videos/|album/(\d+)/video/|video/)?' \ 18 | r'(?P\d+)(\?[^\s]+)?$' 19 | 20 | 21 | class VimeofyExtension(Extension): 22 | 23 | def extendMarkdown(self, md, md_globals): 24 | md.registerExtension(self) 25 | md.preprocessors.add('vimeofy', 26 | VimeofyPreprocessor(md), 27 | '_end') 28 | 29 | 30 | class VimeofyPreprocessor(Preprocessor): 31 | 32 | def run(self, lines): 33 | new_lines = [] 34 | 35 | def vimeofy(match): 36 | video_id = match.group("id") 37 | html = ''.format(video_id=video_id) 39 | return self.markdown.htmlStash.store(html, safe=True) 40 | 41 | for line in lines: 42 | if line.strip(): 43 | line = re.sub(PATTERN_RE, vimeofy, line, flags=re.UNICODE) 44 | 45 | new_lines.append(line) 46 | 47 | return new_lines 48 | 49 | 50 | def makeExtension(configs=None): 51 | return VimeofyExtension(configs=configs) -------------------------------------------------------------------------------- /spirit/utils/markdown/youtube.py: -------------------------------------------------------------------------------- 1 | #-*- coding: utf-8 -*- 2 | 3 | import re 4 | 5 | from markdown.extensions import Extension 6 | from markdown.preprocessors import Preprocessor 7 | 8 | 9 | # Try to get the video ID. Works for URLs of the form: 10 | # * https://www.youtube.com/watch?v=Z0UISCEe52Y 11 | # * http://youtu.be/afyK1HSFfgw 12 | # * https://www.youtube.com/embed/vsF0K3Ou1v0 13 | PATTERN_RE = r'^https?://(www\.)?(youtube\.com/watch\?v=|youtu\.be/|youtube\.com/embed/)(?P[a-zA-Z0-9_\-]{11})$' 14 | 15 | 16 | class YouTubefyExtension(Extension): 17 | 18 | def extendMarkdown(self, md, md_globals): 19 | md.registerExtension(self) 20 | md.preprocessors.add('youtubefy', 21 | YouTubefyPreprocessor(md), 22 | '_end') 23 | 24 | 25 | class YouTubefyPreprocessor(Preprocessor): 26 | 27 | def run(self, lines): 28 | new_lines = [] 29 | 30 | def youtubefy(match): 31 | video_id = match.group("id") 32 | html = ''.format(video_id=video_id) 34 | return self.markdown.htmlStash.store(html, safe=True) 35 | 36 | for line in lines: 37 | if line.strip(): 38 | line = re.sub(PATTERN_RE, youtubefy, line, flags=re.UNICODE) 39 | 40 | new_lines.append(line) 41 | 42 | return new_lines 43 | 44 | 45 | def makeExtension(configs=None): 46 | return YouTubefyExtension(configs=configs) -------------------------------------------------------------------------------- /spirit/utils/models.py: -------------------------------------------------------------------------------- 1 | #-*- coding: utf-8 -*- 2 | 3 | from django.db.models.fields import SlugField 4 | from django.utils.text import slugify 5 | from six import smart_text 6 | 7 | 8 | class AutoSlugField(SlugField): 9 | """ 10 | Auto populates itself from another field. 11 | 12 | It behaves like a regular SlugField. 13 | When populate_from is provided it'll populate itself on creation 14 | only if a slug was not provided. 15 | """ 16 | def __init__(self, *args, **kwargs): 17 | self.populate_from = kwargs.pop('populate_from', None) 18 | super(AutoSlugField, self).__init__(*args, **kwargs) 19 | 20 | def pre_save(self, instance, add): 21 | default = super(AutoSlugField, self).pre_save(instance, add) 22 | 23 | if default or not add or not self.populate_from: 24 | return default 25 | 26 | value = getattr(instance, self.populate_from) 27 | 28 | if value is None: 29 | return default 30 | 31 | slug = slugify(smart_text(value))[:self.max_length].strip('-') 32 | 33 | # Update the model’s attribute 34 | setattr(instance, self.attname, slug) 35 | 36 | return slug 37 | 38 | # def deconstruct(self): 39 | # TODO: django 1.7 requires this 40 | -------------------------------------------------------------------------------- /spirit/utils/paginator/__init__.py: -------------------------------------------------------------------------------- 1 | #-*- coding: utf-8 -*- 2 | 3 | import urllib.parse 4 | 5 | def get_page_number(obj_number, per_page): 6 | if obj_number < per_page: 7 | return 1 8 | elif obj_number % per_page: 9 | return obj_number / per_page + 1 10 | else: 11 | return obj_number / per_page 12 | 13 | 14 | def get_url(url, obj_number, per_page, page_var): 15 | page = get_page_number(obj_number, per_page) 16 | data = urllib.parse.urlencode({page_var: page, }) 17 | 18 | if page == 1: 19 | return "".join((url, '#c', str(obj_number))) 20 | 21 | return "".join((url, '?', data, '#c', str(obj_number))) -------------------------------------------------------------------------------- /spirit/utils/paginator/infinite_paginator.py: -------------------------------------------------------------------------------- 1 | #-*- coding: utf-8 -*- 2 | 3 | from django.http import Http404 4 | 5 | from infinite_scroll_pagination.paginator import SeekPaginator, EmptyPage 6 | 7 | 8 | def paginate(request, query_set, lookup_field, per_page=15, page_var='value'): 9 | page_pk = request.GET.get(page_var, None) 10 | paginator = SeekPaginator(query_set, per_page=per_page, lookup_field=lookup_field) 11 | 12 | # First page 13 | if page_pk is None: 14 | return paginator.page() 15 | 16 | try: 17 | obj = query_set.model.objects.get(pk=page_pk) 18 | except query_set.model.DoesNotExist: 19 | raise Http404() 20 | 21 | value = getattr(obj, lookup_field) 22 | 23 | try: 24 | page = paginator.page(value=value, pk=page_pk) 25 | except EmptyPage: 26 | raise Http404() 27 | 28 | return page -------------------------------------------------------------------------------- /spirit/utils/ratelimit/__init__.py: -------------------------------------------------------------------------------- 1 | from .ratelimit import RateLimit -------------------------------------------------------------------------------- /spirit/utils/ratelimit/decorators.py: -------------------------------------------------------------------------------- 1 | #-*- coding: utf-8 -*- 2 | 3 | import functools 4 | 5 | from django.contrib import messages 6 | from django.utils.translation import ugettext as _ 7 | 8 | from .ratelimit import RateLimit 9 | 10 | 11 | __all__ = ['ratelimit', ] 12 | 13 | 14 | def ratelimit(method=None, field=None, rate='5/5m'): 15 | def decorator(func): 16 | @functools.wraps(func) 17 | def wrapper(request, *args, **kwargs): 18 | rl = RateLimit(request, func.__name__, method=method, field=field, rate=rate) 19 | request.is_limited = rl.is_limited() 20 | 21 | if request.is_limited: 22 | messages.error(request, _('Too many submissions, wait %(time)s.') % {'time': rate.split('/')[1], }) 23 | 24 | return func(request, *args, **kwargs) 25 | 26 | return wrapper 27 | 28 | return decorator 29 | -------------------------------------------------------------------------------- /spirit/utils/timezone.py: -------------------------------------------------------------------------------- 1 | #-*- coding: utf-8 -*- 2 | 3 | from django.utils.translation import ugettext as _ 4 | 5 | 6 | TIMEZONE_CHOICES = [ 7 | ('Etc/GMT+12', _("(GMT -12:00) Eniwetok, Kwajalein")), 8 | ('Etc/GMT+11', _("(GMT -11:00) Midway Island, Samoa")), 9 | ('Etc/GMT+10', _("(GMT -10:00) Hawaii")), 10 | ('Etc/GMT+9', _("(GMT -9:00) Alaska")), 11 | ('Etc/GMT+8', _("(GMT -8:00) Pacific Time (US & Canada)")), 12 | ('Etc/GMT+7', _("(GMT -7:00) Mountain Time (US & Canada)")), 13 | ('Etc/GMT+6', _("(GMT -6:00) Central Time (US & Canada), Mexico City")), 14 | ('Etc/GMT+5', _("(GMT -5:00) Eastern Time (US & Canada), Bogota, Lima")), 15 | ('Etc/GMT+4', _("(GMT -4:00) Atlantic Time (Canada), Caracas, La Paz")), 16 | ('Etc/GMT+3', _("(GMT -3:00) Brazil, Buenos Aires, Georgetown")), 17 | ('Etc/GMT+2', _("(GMT -2:00) Mid-Atlantic")), 18 | ('Etc/GMT+1', _("(GMT -1:00) Azores, Cape Verde Islands")), 19 | ('UTC', _("(GMT) Western Europe Time, London, Lisbon, Casablanca")), 20 | ('Etc/GMT-1', _("(GMT +1:00) Brussels, Copenhagen, Madrid, Paris")), 21 | ('Etc/GMT-2', _("(GMT +2:00) Kaliningrad, South Africa")), 22 | ('Etc/GMT-3', _("(GMT +3:00) Baghdad, Riyadh, Moscow, St. Petersburg")), 23 | ('Etc/GMT-4', _("(GMT +4:00) Abu Dhabi, Muscat, Baku, Tbilisi")), 24 | ('Etc/GMT-5', _("(GMT +5:00) Ekaterinburg, Islamabad, Karachi, Tashkent")), 25 | ('Etc/GMT-6', _("(GMT +6:00) Almaty, Dhaka, Colombo")), 26 | ('Etc/GMT-7', _("(GMT +7:00) Bangkok, Hanoi, Jakarta")), 27 | ('Etc/GMT-8', _("(GMT +8:00) Beijing, Perth, Singapore, Hong Kong")), 28 | ('Etc/GMT-9', _("(GMT +9:00) Tokyo, Seoul, Osaka, Sapporo, Yakutsk")), 29 | ('Etc/GMT-10', _("(GMT +10:00) Eastern Australia, Guam, Vladivostok")), 30 | ('Etc/GMT-11', _("(GMT +11:00) Magadan, Solomon Islands, New Caledonia")), 31 | ('Etc/GMT-12', _("(GMT +12:00) Auckland, Wellington, Fiji, Kamchatka")), 32 | ] -------------------------------------------------------------------------------- /spirit/utils/user/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/spirit/utils/user/__init__.py -------------------------------------------------------------------------------- /spirit/utils/user/tokens.py: -------------------------------------------------------------------------------- 1 | #-*- coding: utf-8 -*- 2 | 3 | from django.core import signing 4 | from six import smart_text 5 | 6 | 7 | class TokenGenerator(object): 8 | 9 | def _uid(self, user): 10 | raise NotImplementedError 11 | 12 | def generate(self, user, data=None): 13 | """ 14 | Django signer uses colon (:) for components separation 15 | JSON_object:hash_first_component:hash_secret, all base64 encoded 16 | that aint so url-safe, so Im replacing them by dots (.) 17 | 18 | base64 encode characters ref: 0-9, A-Z, a-z, _, - 19 | """ 20 | data = data or {} 21 | data.update({'uid': self._uid(user), }) 22 | return signing.dumps(data, salt=__name__).replace(":", ".") 23 | 24 | def is_valid(self, user, signed_value): 25 | try: 26 | self.data = signing.loads(signed_value.replace(".", ":"), salt=__name__) 27 | except signing.BadSignature: 28 | return False 29 | 30 | if self.data['uid'] != self._uid(user): 31 | return False 32 | 33 | return True 34 | 35 | 36 | class UserActivationTokenGenerator(TokenGenerator): 37 | 38 | def _uid(self, user): 39 | return smart_text(user.pk) + smart_text(user.last_login) 40 | 41 | 42 | class UserEmailChangeTokenGenerator(TokenGenerator): 43 | 44 | def _uid(self, user): 45 | return ";".join((smart_text(user.pk), smart_text(user.email))) 46 | 47 | def generate(self, user, new_email): 48 | return super(UserEmailChangeTokenGenerator, self).generate(user, {'new_email': new_email, }) 49 | 50 | def get_email(self): 51 | return self.data['new_email'] 52 | -------------------------------------------------------------------------------- /spirit/utils/widgets.py: -------------------------------------------------------------------------------- 1 | #-*- coding: utf-8 -*- 2 | 3 | from django import forms 4 | from six import force_text 5 | 6 | 7 | class MultipleInput(forms.TextInput): 8 | """ 9 | TextInput widget for input multiple *raw* choices 10 | """ 11 | def __init__(self, attrs=None, choices=()): 12 | # choices is some iterable we do not need, since this is a TextInput 13 | super(MultipleInput, self).__init__(attrs) 14 | 15 | def render(self, name, value, attrs=None, choices=()): 16 | if value: 17 | value = ','.join([force_text(v) for v in value]) 18 | else: 19 | value = '' 20 | 21 | return super(MultipleInput, self).render(name, value, attrs=attrs) 22 | 23 | def value_from_datadict(self, data, files, name): 24 | value = data.get(name) 25 | 26 | if value: 27 | return [v.strip() for v in value.split(',')] 28 | -------------------------------------------------------------------------------- /templates/admin/base_site.html: -------------------------------------------------------------------------------- 1 | {% extends "admin/base.html" %} 2 | {% load i18n %} 3 | 4 | {% block title %}{{ title }} | {% trans 'Django site admin' %}{% endblock %} 5 | 6 | {% block branding %} 7 |

{% trans 'BikeMap Administration' %}

8 | 9 | {% endblock %} 10 | 11 | {% block nav-global %}{% endblock %} 12 | -------------------------------------------------------------------------------- /templates/admin/login.html: -------------------------------------------------------------------------------- 1 | {% extends 'mapApp/base.html' %} 2 | 3 | {% load static crispy_forms_tags %} 4 | 5 | {% block body %} 6 |
7 |
8 |
9 | 12 |
13 |
14 | 15 |
16 |
17 |
18 | {% csrf_token %} 19 | {{ form|crispy }} 20 | 21 |
22 |

Create an account

23 |

I don't know my password

24 |
25 |
26 | 27 |
28 | {% endblock %} 29 | -------------------------------------------------------------------------------- /templates/robots.txt: -------------------------------------------------------------------------------- 1 | User-agent: * 2 | Disallow: /admin/ 3 | Disallow: /forum/ 4 | 5 | Disallow: /incident_submit/ 6 | Disallow: /nearmiss_submit/ 7 | Disallow: /hazard_submit/ 8 | Disallow: /newInfrastructure_submit/ 9 | Disallow: /theft_submit/ 10 | Disallow: /poly_submit/ 11 | 12 | Disallow: /read_alert/ 13 | Disallow: /contact/ 14 | Disallow: /edit/ 15 | 16 | Disallow: /points.json 17 | Disallow: /incidents.json 18 | Disallow: /hazards.json 19 | Disallow: /thefts.json 20 | -------------------------------------------------------------------------------- /userApp/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/userApp/__init__.py -------------------------------------------------------------------------------- /userApp/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | 3 | from mapApp.admin import HazardAdminsInline 4 | from django.contrib.auth import get_user_model 5 | User = get_user_model() 6 | 7 | @admin.register(User) 8 | class UserAdmin(admin.ModelAdmin): 9 | list_filter = ['is_staff'] 10 | list_display = ['username', 'email', 'is_staff', 'is_superuser'] 11 | search_fields = ['username', 'email', 'first_name', 'last_name'] 12 | inlines = [ 13 | HazardAdminsInline, 14 | ] 15 | -------------------------------------------------------------------------------- /userApp/forms.py: -------------------------------------------------------------------------------- 1 | from django.contrib.auth.forms import UserCreationForm 2 | # from django.contrib.auth.admin import UserAdmin 3 | from django import forms 4 | from django.contrib.auth import get_user_model 5 | User = get_user_model() 6 | 7 | class MyUserCreationForm(UserCreationForm): 8 | def clean_username(self): 9 | # Since User.username is unique, this check is redundant, 10 | # but it sets a nicer error message than the ORM. See #13147. 11 | username = self.cleaned_data["username"] 12 | try: 13 | User._default_manager.get(username=username) 14 | except User.DoesNotExist: 15 | return username 16 | raise forms.ValidationError(self.error_messages['duplicate_username']) 17 | 18 | class Meta(UserCreationForm.Meta): 19 | model = User 20 | fields = ['username', 'email',] 21 | 22 | 23 | class UserProfileForm(forms.ModelForm): 24 | class Meta: 25 | model = User 26 | fields = ['email', 'first_name', 'last_name'] 27 | -------------------------------------------------------------------------------- /userApp/locale/da/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/userApp/locale/da/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /userApp/locale/de/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/userApp/locale/de/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /userApp/locale/en/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/userApp/locale/en/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /userApp/locale/es/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/userApp/locale/es/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /userApp/locale/fi/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/userApp/locale/fi/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /userApp/locale/fr/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/userApp/locale/fr/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /userApp/locale/is/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/userApp/locale/is/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /userApp/locale/nl/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/userApp/locale/nl/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /userApp/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/userApp/migrations/__init__.py -------------------------------------------------------------------------------- /userApp/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | 3 | # Create your models here. 4 | -------------------------------------------------------------------------------- /userApp/static/userApp/css/profile.css: -------------------------------------------------------------------------------- 1 | .edit-link{ 2 | margin-left: 10px; 3 | } 4 | -------------------------------------------------------------------------------- /userApp/templates/userApp/logged_out.html: -------------------------------------------------------------------------------- 1 | {% extends 'mapApp/base.html' %} 2 | 3 | {% load static crispy_forms_tags i18n %} 4 | 5 | {% block body %} 6 |
7 |
8 |
9 | 15 |
16 |
17 | 18 |
19 | {% endblock %} 20 | -------------------------------------------------------------------------------- /userApp/templates/userApp/login.html: -------------------------------------------------------------------------------- 1 | {% extends 'mapApp/base.html' %} 2 | 3 | {% load static crispy_forms_tags i18n %} 4 | 5 | {% block body %} 6 |
7 |
8 |
9 | 12 |
13 |
14 | 15 |
16 |
17 |
18 | {% csrf_token %} 19 | {{ form|crispy }} 20 | 21 |
22 |

{% trans "Create an account" %}

23 |

{% trans "I don't know my password" %}

24 |
25 |
26 | 27 |
28 | {% endblock %} 29 | -------------------------------------------------------------------------------- /userApp/templates/userApp/password_change_done.html: -------------------------------------------------------------------------------- 1 | {% extends 'mapApp/base.html' %} 2 | 3 | {% load static crispy_forms_tags i18n %} 4 | 5 | {% block body %} 6 |
7 |
8 |
9 | 13 |
14 |
15 | 16 |
17 | {% endblock %} 18 | -------------------------------------------------------------------------------- /userApp/templates/userApp/password_change_form.html: -------------------------------------------------------------------------------- 1 | {% extends 'mapApp/base.html' %} 2 | 3 | {% load static crispy_forms_tags i18n %} 4 | 5 | {% block body %} 6 |
7 |
8 |
9 | 14 |
15 |
16 | 17 |
18 |
19 |
20 | {% csrf_token %} 21 | {{ form|crispy }} 22 | {# Translators: This is a button to submit the password change form #} 23 | 24 |
25 |
26 |
27 | 28 |
29 | {% endblock %} 30 | -------------------------------------------------------------------------------- /userApp/templates/userApp/password_reset_complete.html: -------------------------------------------------------------------------------- 1 | {% extends 'mapApp/base.html' %} 2 | 3 | {% load static crispy_forms_tags i18n %} 4 | 5 | {% block body %} 6 |
7 |
8 |
9 | 13 |
14 |
15 | 16 |
17 | {% endblock %} 18 | -------------------------------------------------------------------------------- /userApp/templates/userApp/password_reset_confirm.html: -------------------------------------------------------------------------------- 1 | {% extends 'mapApp/base.html' %} 2 | 3 | {% load static crispy_forms_tags i18n %} 4 | 5 | {% block body %} 6 |
7 |
8 |
9 | 13 |
14 |
15 | 16 |
17 |
18 |
19 | {% csrf_token %} 20 | {{ form|crispy }} 21 | 22 |
23 |
24 |
25 | 26 |
27 | {% endblock %} 28 | -------------------------------------------------------------------------------- /userApp/templates/userApp/password_reset_done.html: -------------------------------------------------------------------------------- 1 | {% extends 'mapApp/base.html' %} 2 | 3 | {% load static crispy_forms_tags i18n %} 4 | 5 | {% block body %} 6 |
7 |
8 |
9 | 14 |
15 |
16 | 17 |
18 | {% endblock %} 19 | -------------------------------------------------------------------------------- /userApp/templates/userApp/password_reset_email.html: -------------------------------------------------------------------------------- 1 | {% load i18n %}{% autoescape off %} 2 | {% blocktrans %}You're receiving this email because you requested a password reset for your user account at {{ site_name }}.{% endblocktrans %} 3 | 4 | {% trans "Please go to the following page and choose a new password:" %} 5 | {% block reset_link %} 6 | {{ protocol }}://{{ domain }}{% url 'userApp:password_reset_confirm' uidb64=uid token=token %} 7 | {% endblock %} 8 | {% trans "Your username, in case you've forgotten:" %} {{ user.get_username }} 9 | 10 | {% trans "Thanks for using our site!" %} 11 | 12 | {% blocktrans %}The {{ site_name }} team{% endblocktrans %} 13 | 14 | {% endautoescape %} 15 | -------------------------------------------------------------------------------- /userApp/templates/userApp/password_reset_form.html: -------------------------------------------------------------------------------- 1 | {% extends 'mapApp/base.html' %} 2 | 3 | {% load static crispy_forms_tags i18n %} 4 | 5 | {% block body %} 6 |
7 |
8 |
9 | 13 |
14 |
15 | 16 |
17 |
18 |
19 | {% csrf_token %} 20 | {{ form|crispy }} 21 | 22 |
23 |
24 |
25 | 26 |
27 | {% endblock %} 28 | -------------------------------------------------------------------------------- /userApp/templates/userApp/profile.html: -------------------------------------------------------------------------------- 1 | {% extends 'mapApp/base.html' %} 2 | 3 | {% load static crispy_forms_tags i18n %} 4 | 5 | {% block headerCSS %} 6 | 7 | {% endblock %} 8 | 9 | {% block body %} 10 |
11 |
12 |
13 | 16 |
17 |
18 | 19 |
20 |
21 |
22 | 23 | 24 | {% trans "Change password" %} 25 | 26 |
27 | 28 |
29 | {% csrf_token %} 30 | {{ form|crispy }} 31 | 32 |
33 | 34 |
35 |
36 |
37 | 38 | {% endblock %} 39 | -------------------------------------------------------------------------------- /userApp/templates/userApp/rate_limited.html: -------------------------------------------------------------------------------- 1 | {% extends 'mapApp/base.html' %} 2 | {% load i18n %} 3 | 4 | {% block body %} 5 |
6 |
7 |
8 | 12 |
13 |
14 | 15 | 20 | 21 |
22 | {% endblock %} 23 | -------------------------------------------------------------------------------- /userApp/templates/userApp/register.html: -------------------------------------------------------------------------------- 1 | {% extends 'mapApp/base.html' %} 2 | {% load static crispy_forms_tags i18n %} 3 | 4 | {% block headerCSS %} 5 | 6 | {% endblock %} 7 | 8 | {% block body %} 9 |
10 |
11 |
12 | 15 |
16 |
17 | 18 |
19 |
20 |
21 | {% csrf_token %} 22 | {{ form|crispy }} 23 |
24 | 25 |
26 |
27 |
28 | 29 |
30 | {% endblock %} 31 | -------------------------------------------------------------------------------- /userApp/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | from django.contrib.auth import get_user_model 4 | User = get_user_model() 5 | 6 | # Create your tests here. 7 | class TestUserFunction(TestCase): 8 | """Test getting various urls for user app""" 9 | def setUp(self): 10 | self.test_user = create_user() 11 | 12 | def test_getting_login(self): 13 | self.assertEqual(self.client.get('/user/login/').status_code, 200) 14 | 15 | def test_getting_register(self): 16 | self.assertEqual(self.client.get('/user/register/').status_code, 200) 17 | 18 | def test_login(self): 19 | self.assertFalse(self.client.login(username="test_user", password="wrong_password")) 20 | self.assertFalse(self.client.login(username="nonexistant_user", password="password")) 21 | self.assertTrue(self.client.login(username="test_user", password="password")) 22 | 23 | def create_user(): 24 | return User.objects.create_user("test_user", email="user@bikemaps.org", password="password") 25 | 26 | def create_superuser(): 27 | return User.objects.create_superuser("test_superuser", email="super_user@bikemaps.org", password="password") 28 | -------------------------------------------------------------------------------- /userApp/urls.py: -------------------------------------------------------------------------------- 1 | from django.conf.urls import include, url 2 | from django.contrib.auth import views as django_contrib_auth_views 3 | from django.urls import path, reverse_lazy 4 | 5 | from userApp import views 6 | 7 | urlpatterns = [ 8 | url(r'^register/$', views.register, name='register'), 9 | url(r'^profile/$', views.profile, name='profile'), 10 | url(r'^login/$', views.rate_limit_login, name='login'), 11 | url(r'^rate_limited/$', views.rate_limited, name='rate_limited'), 12 | url(r'^logout/$', django_contrib_auth_views.LogoutView.as_view( template_name='userApp/logged_out.html', next_page= '/' ), name='logout'), 13 | url(r'^password_change/$', django_contrib_auth_views.PasswordChangeView.as_view(template_name='userApp/password_change_form.html', success_url=reverse_lazy('userApp:password_change_done')), name='password_change'), 14 | url(r'^password_change/done/$', django_contrib_auth_views.PasswordChangeDoneView.as_view(template_name='userApp/password_change_done.html'), name='password_change_done'), 15 | url(r'^password_reset/$', django_contrib_auth_views.PasswordResetView.as_view(template_name='userApp/password_reset_form.html', email_template_name='userApp/password_reset_email.html', success_url=reverse_lazy('userApp:password_reset_done')), name='password_reset'), 16 | url(r'^password_reset/done/$', django_contrib_auth_views.PasswordResetDoneView.as_view(template_name='userApp/password_reset_done.html'), name='password_reset_done'), 17 | url(r'^reset/(?P[0-9A-Za-z_\-]+)/(?P[0-9A-Za-z]{1,13}-[0-9A-Za-z]{1,40})/$', django_contrib_auth_views.PasswordResetConfirmView.as_view(template_name='userApp/password_reset_confirm.html', success_url= reverse_lazy('userApp:password_reset_complete')), name='password_reset_confirm'), 18 | url(r'^reset/done/$', django_contrib_auth_views.PasswordResetCompleteView.as_view(template_name= 'userApp/password_reset_complete.html'), name='password_reset_complete'), 19 | path('accounts/', include('allauth.urls')), 20 | ] 21 | -------------------------------------------------------------------------------- /userApp/utils/__init__.py: -------------------------------------------------------------------------------- 1 | from .recaptcha import ReCaptcha 2 | -------------------------------------------------------------------------------- /userApp/utils/recaptcha.py: -------------------------------------------------------------------------------- 1 | from django.conf import settings 2 | import requests 3 | 4 | class ReCaptcha: 5 | def __init__(self, request): 6 | params = { 7 | 'secret': settings.RECAPTCHA_SECRET, 8 | 'response': request.POST.get('g-recaptcha-response'), 9 | 'remoteip': request.META['REMOTE_ADDR'] 10 | } 11 | self.response = requests.get('https://www.google.com/recaptcha/api/siteverify', params=params).json() 12 | 13 | def is_valid(self): 14 | return self.response['success'] 15 | -------------------------------------------------------------------------------- /utils/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/utils/__init__.py -------------------------------------------------------------------------------- /utils/management/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/utils/management/__init__.py -------------------------------------------------------------------------------- /utils/management/commands/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPARLab/BikeMaps/77b4349054b20928b3fd1e5cd5320ffe26f6abda/utils/management/commands/__init__.py -------------------------------------------------------------------------------- /utils/management/commands/clearcache.py: -------------------------------------------------------------------------------- 1 | from django.core.management.base import BaseCommand 2 | from django.core.cache import cache 3 | 4 | class Command(BaseCommand): 5 | def handle(self, *args, **kwargs): 6 | cache.clear() 7 | self.stdout.write('Cleared cache\n') 8 | --------------------------------------------------------------------------------