├── .coveragerc
├── .editorconfig
├── .gitignore
├── .jshintrc
├── .travis.yml
├── Dockerfile
├── GeoKey_updated_documentation.pdf
├── Gruntfile.js
├── LICENSE
├── MANIFEST.in
├── README.rst
├── db
├── Dockerfile
└── initdb-hstore.sh
├── docker-compose.yml
├── geokey
├── __init__.py
├── applications
│ ├── __init__.py
│ ├── base.py
│ ├── forms.py
│ ├── managers.py
│ ├── migrations
│ │ ├── 0001_initial.py
│ │ ├── 0002_auto_20150112_1700.py
│ │ ├── 0002_auto_20150112_1807.py
│ │ ├── 0003_auto_20171024_1400.py
│ │ └── __init__.py
│ ├── models.py
│ ├── tests
│ │ ├── __init__.py
│ │ ├── model_factories.py
│ │ ├── test_managers.py
│ │ ├── test_models.py
│ │ └── test_views.py
│ └── views.py
├── categories
│ ├── __init__.py
│ ├── base.py
│ ├── forms.py
│ ├── managers.py
│ ├── migrations
│ │ ├── 0001_initial.py
│ │ ├── 0002_auto_20150106_1338.py
│ │ ├── 0003_datefield.py
│ │ ├── 0004_timefield.py
│ │ ├── 0005_auto_20150112_1731.py
│ │ ├── 0006_category_display_field.py
│ │ ├── 0007_auto_20150130_1155.py
│ │ ├── 0008_auto_20150130_1216.py
│ │ ├── 0010_auto_20150202_1023.py
│ │ ├── 0011_auto_20150220_1413.py
│ │ ├── 0012_auto_20150223_1311.py
│ │ ├── 0013_auto_20150130_1440.py
│ │ ├── 0014_auto_20160104_1409.py
│ │ ├── 0015_lookupvalue_symbol.py
│ │ ├── 0016_multiplelookupvalue_symbol.py
│ │ ├── 0017_category_expiry_field.py
│ │ ├── 0018_historicalcategory.py
│ │ ├── 0019_auto_20181028_1638.py
│ │ └── __init__.py
│ ├── mixins.py
│ ├── models.py
│ ├── serializers.py
│ ├── templatetags
│ │ ├── __init__.py
│ │ └── filter_fields.py
│ ├── tests
│ │ ├── __init__.py
│ │ ├── model_factories.py
│ │ ├── test_managers.py
│ │ ├── test_models.py
│ │ ├── test_templatetags.py
│ │ └── test_views.py
│ └── views.py
├── context_processors.py
├── contributions
│ ├── __init__.py
│ ├── base.py
│ ├── managers.py
│ ├── migrations
│ │ ├── 0001_initial.py
│ │ ├── 0002_auto_20150106_1338.py
│ │ ├── 0003_auto_20150121_1544.py
│ │ ├── 0004_auto_20150121_1455.py
│ │ ├── 0005_auto_20150202_1135.py
│ │ ├── 0006_auto_20150312_1247.py
│ │ ├── 0007_auto_20150312_1249.py
│ │ ├── 0008_auto_20150312_1508.py
│ │ ├── 0009_auto_20150420_1549.py
│ │ ├── 0010_auto_20150511_1132.py
│ │ ├── 0011_auto_20150527_1255.py
│ │ ├── 0012_auto_20150807_0854.py
│ │ ├── 0013_auto_20150907_1345.py
│ │ ├── 0014_auto_20150907_1345.py
│ │ ├── 0015_auto_20150907_1345.py
│ │ ├── 0016_audiofile.py
│ │ ├── 0017_auto_20160531_1434.py
│ │ ├── 0018_historicalcomment.py
│ │ ├── 0019_auto_20181020_1915.py
│ │ ├── 0020_update_media_and_comments_count.py
│ │ └── __init__.py
│ ├── models.py
│ ├── parsers
│ │ ├── __init__.py
│ │ └── geojson.py
│ ├── renderers
│ │ ├── __init__.py
│ │ ├── geojson.py
│ │ └── kml.py
│ ├── serializers.py
│ ├── templatetags
│ │ ├── __init__.py
│ │ └── kml_tags.py
│ ├── tests
│ │ ├── __init__.py
│ │ ├── comments
│ │ │ ├── __init__.py
│ │ │ ├── test_managers.py
│ │ │ ├── test_models.py
│ │ │ └── test_views.py
│ │ ├── locations
│ │ │ ├── __init__.py
│ │ │ ├── test_managers.py
│ │ │ └── test_views.py
│ │ ├── media
│ │ │ ├── __init__.py
│ │ │ ├── files
│ │ │ │ ├── audio_1.mp3
│ │ │ │ ├── audio_10.flac
│ │ │ │ ├── audio_12.wma
│ │ │ │ ├── audio_2.3gp
│ │ │ │ ├── audio_3.opus
│ │ │ │ ├── audio_4.m4a
│ │ │ │ ├── audio_5.amr
│ │ │ │ ├── audio_6.aiff
│ │ │ │ ├── audio_7.wav
│ │ │ │ ├── audio_8
│ │ │ │ ├── audio_8.opus
│ │ │ │ ├── audio_9.aac
│ │ │ │ ├── document_1.pdf
│ │ │ │ ├── document_2.doc
│ │ │ │ ├── image_01.png
│ │ │ │ ├── image_02.jpg
│ │ │ │ ├── image_03.gif
│ │ │ │ ├── image_04.svg
│ │ │ │ ├── image_05.tiff
│ │ │ │ ├── text_1.txt
│ │ │ │ └── video.MOV
│ │ │ ├── helpers
│ │ │ │ ├── __init__.py
│ │ │ │ └── document_helpers.py
│ │ │ ├── model_factories.py
│ │ │ ├── test_managers.py
│ │ │ ├── test_models.py
│ │ │ ├── test_serializers.py
│ │ │ └── test_views.py
│ │ ├── model_factories.py
│ │ ├── observations
│ │ │ ├── __init__.py
│ │ │ ├── test_managers.py
│ │ │ ├── test_models.py
│ │ │ ├── test_parsers.py
│ │ │ ├── test_renderers.py
│ │ │ ├── test_templatetags.py
│ │ │ └── test_views.py
│ │ ├── test_serializers.py
│ │ └── test_utils.py
│ ├── utils.py
│ └── views
│ │ ├── __init__.py
│ │ ├── base.py
│ │ ├── comments.py
│ │ ├── locations.py
│ │ ├── media.py
│ │ └── observations.py
├── core
│ ├── __init__.py
│ ├── adapters.py
│ ├── base.py
│ ├── context_processors.py
│ ├── decorators.py
│ ├── exceptions.py
│ ├── middleware.py
│ ├── migrations
│ │ ├── 0001_initial.py
│ │ └── __init__.py
│ ├── mixins.py
│ ├── models.py
│ ├── serializers.py
│ ├── settings
│ │ ├── __init__.py
│ │ ├── base.py
│ │ ├── dev.py
│ │ └── prod.py
│ ├── signals.py
│ ├── templatetags
│ │ ├── __init__.py
│ │ └── logger.py
│ ├── tests
│ │ ├── __init__.py
│ │ ├── helpers
│ │ │ ├── __init__.py
│ │ │ ├── image_helpers.py
│ │ │ └── render_helpers.py
│ │ ├── logger
│ │ │ ├── __init__.py
│ │ │ ├── test_log_audiofile.py
│ │ │ ├── test_log_category.py
│ │ │ ├── test_log_comment.py
│ │ │ ├── test_log_datefield.py
│ │ │ ├── test_log_datetimefield.py
│ │ │ ├── test_log_documentfile.py
│ │ │ ├── test_log_imagefile.py
│ │ │ ├── test_log_location.py
│ │ │ ├── test_log_lookupfield.py
│ │ │ ├── test_log_multiplelookupfield.py
│ │ │ ├── test_log_numericfield.py
│ │ │ ├── test_log_observation.py
│ │ │ ├── test_log_project.py
│ │ │ ├── test_log_subset.py
│ │ │ ├── test_log_textfield.py
│ │ │ ├── test_log_timefield.py
│ │ │ ├── test_log_user.py
│ │ │ ├── test_log_usergroup.py
│ │ │ └── test_log_videofile.py
│ │ ├── test_templatetags.py
│ │ ├── test_urls.py
│ │ └── test_views.py
│ ├── url
│ │ ├── __init__.py
│ │ ├── admin.py
│ │ ├── ajax.py
│ │ └── api.py
│ ├── urls.py
│ └── views.py
├── extensions
│ ├── __init__.py
│ ├── base.py
│ ├── exceptions.py
│ ├── mixins.py
│ ├── tests
│ │ ├── __init__.py
│ │ ├── test_base.py
│ │ └── test_mixins.py
│ └── urls.py
├── projects
│ ├── __init__.py
│ ├── base.py
│ ├── forms.py
│ ├── managers.py
│ ├── migrations
│ │ ├── 0001_initial.py
│ │ ├── 0002_auto_20150106_1338.py
│ │ ├── 0003_auto_20150123_1148.py
│ │ ├── 0004_auto_20150123_1507.py
│ │ ├── 0005_auto_20150202_1041.py
│ │ ├── 0006_remove_admins_contact.py
│ │ ├── 0007_auto_20160122_1409.py
│ │ ├── 0008_historicalproject.py
│ │ └── __init__.py
│ ├── models.py
│ ├── serializers.py
│ ├── templatetags
│ │ ├── __init__.py
│ │ ├── count.py
│ │ └── project_attributes.py
│ ├── tests
│ │ ├── __init__.py
│ │ ├── model_factories.py
│ │ ├── test_managers.py
│ │ ├── test_models.py
│ │ ├── test_serializers.py
│ │ ├── test_templatetags.py
│ │ └── test_views.py
│ └── views.py
├── socialinteractions
│ ├── __init__.py
│ ├── base.py
│ ├── migrations
│ │ ├── 0001_initial.py
│ │ └── __init__.py
│ ├── models.py
│ ├── templatetags
│ │ ├── __init__.py
│ │ └── placeholder_filters.py
│ ├── tests
│ │ ├── __init__.py
│ │ ├── model_factories.py
│ │ ├── test_utils.py
│ │ └── test_views.py
│ ├── utils.py
│ └── views.py
├── static
│ ├── css
│ │ └── admin.css
│ ├── img
│ │ ├── ajax-loader-blue.gif
│ │ ├── ajax-loader.gif
│ │ ├── blurry.jpg
│ │ ├── play.png
│ │ ├── providers
│ │ │ ├── facebook.svg
│ │ │ └── twitter.svg
│ │ └── success.png
│ ├── js
│ │ ├── admin.control.ajax.js
│ │ ├── admin.ui.category.display.js
│ │ ├── admin.ui.field.create.js
│ │ ├── admin.ui.field.js
│ │ ├── admin.ui.field.lookup.js
│ │ ├── admin.ui.fileinput.js
│ │ ├── admin.ui.filters.data.js
│ │ ├── admin.ui.forms.validate.js
│ │ ├── admin.ui.project.geographicextent.js
│ │ ├── admin.ui.project.js
│ │ ├── admin.ui.socialinteractions.twittervalidator.js
│ │ ├── admin.ui.sort.js
│ │ ├── admin.ui.updater.js
│ │ ├── admin.ui.usergroup.permissions.js
│ │ ├── admin.ui.usergroup.users.js
│ │ └── templates.js
│ └── lib
│ │ ├── bootstrap-colorpicker
│ │ ├── LICENSE
│ │ ├── css
│ │ │ └── bootstrap-colorpicker.min.css
│ │ ├── img
│ │ │ └── bootstrap-colorpicker
│ │ │ │ ├── alpha-horizontal.png
│ │ │ │ ├── alpha.png
│ │ │ │ ├── hue-horizontal.png
│ │ │ │ ├── hue.png
│ │ │ │ └── saturation.png
│ │ └── js
│ │ │ └── bootstrap-colorpicker.min.js
│ │ ├── bootstrap-datetimepicker
│ │ ├── LICENSE
│ │ ├── css
│ │ │ └── bootstrap-datetimepicker.min.css
│ │ └── js
│ │ │ └── bootstrap-datetimepicker.min.js
│ │ ├── bootstrap-fileinput
│ │ ├── LICENSE
│ │ ├── css
│ │ │ └── bootstrap-fileinput.min.css
│ │ ├── img
│ │ │ ├── loading-sm.gif
│ │ │ └── loading.gif
│ │ └── js
│ │ │ └── bootstrap-fileinput.min.js
│ │ ├── bootstrap
│ │ ├── LICENSE
│ │ ├── css
│ │ │ ├── bootstrap-theme.css
│ │ │ ├── bootstrap-theme.css.map
│ │ │ ├── bootstrap-theme.min.css
│ │ │ ├── bootstrap-theme.min.css.map
│ │ │ ├── bootstrap.css
│ │ │ ├── bootstrap.css.map
│ │ │ ├── bootstrap.min.css
│ │ │ └── bootstrap.min.css.map
│ │ ├── fonts
│ │ │ ├── glyphicons-halflings-regular.eot
│ │ │ ├── glyphicons-halflings-regular.svg
│ │ │ ├── glyphicons-halflings-regular.ttf
│ │ │ ├── glyphicons-halflings-regular.woff
│ │ │ └── glyphicons-halflings-regular.woff2
│ │ └── js
│ │ │ ├── bootstrap.js
│ │ │ └── bootstrap.min.js
│ │ ├── handlebars
│ │ ├── LICENSE
│ │ └── handlebars.js
│ │ ├── jquery
│ │ ├── LICENSE
│ │ ├── jquery-1.12.0.min.js
│ │ └── jquery-ui.min.js
│ │ ├── modernizr
│ │ ├── LICENSE
│ │ └── modernizr-2.6.2-respond-1.1.0.min.js
│ │ └── moment
│ │ ├── LICENSE
│ │ └── moment.min.js
├── subsets
│ ├── __init__.py
│ ├── migrations
│ │ ├── 0001_initial.py
│ │ ├── 0002_historicalsubset.py
│ │ └── __init__.py
│ ├── models.py
│ ├── serializers.py
│ ├── tests
│ │ ├── __init__.py
│ │ ├── model_factories.py
│ │ ├── test_urls.py
│ │ └── test_views.py
│ └── views.py
├── superusertools
│ ├── __init__.py
│ ├── base.py
│ ├── mixins.py
│ ├── tests
│ │ ├── __init__.py
│ │ └── test_views.py
│ └── views.py
├── templates
│ ├── 404.html
│ ├── account
│ │ ├── account_inactive.html
│ │ ├── delete_account.html
│ │ ├── email
│ │ │ ├── email_confirmation_message.txt
│ │ │ ├── email_confirmation_signup_message.txt
│ │ │ ├── email_confirmation_signup_subject.txt
│ │ │ ├── email_confirmation_subject.txt
│ │ │ ├── password_reset_key_message.txt
│ │ │ └── password_reset_key_subject.txt
│ │ ├── email_confirm.html
│ │ ├── login.html
│ │ ├── password_change.html
│ │ ├── password_reset.html
│ │ ├── password_reset_done.html
│ │ ├── password_reset_from_key.html
│ │ ├── password_reset_from_key_done.html
│ │ ├── password_set.html
│ │ ├── signup.html
│ │ └── verification_sent.html
│ ├── applications
│ │ ├── application_connected.html
│ │ ├── application_create.html
│ │ ├── application_overview.html
│ │ └── application_settings.html
│ ├── base.html
│ ├── categories
│ │ ├── category_create.html
│ │ ├── category_display.html
│ │ ├── category_list.html
│ │ ├── category_navigation.html
│ │ ├── category_overview.html
│ │ ├── category_settings.html
│ │ ├── field_create.html
│ │ └── field_settings.html
│ ├── dashboard.html
│ ├── geometries
│ │ └── placemarks.kml
│ ├── handlebars
│ │ ├── _created-field.hbs
│ │ ├── _datefield.hbs
│ │ ├── _datetimefield.hbs
│ │ ├── _lookupfield.hbs
│ │ ├── _multiplelookupfield.hbs
│ │ ├── _numericfield.hbs
│ │ ├── _textfield.hbs
│ │ ├── _timefield.hbs
│ │ ├── createdfield.hbs
│ │ ├── field.hbs
│ │ ├── fields.hbs
│ │ ├── fieldselect.hbs
│ │ ├── helpers.js
│ │ ├── lookupvalues.hbs
│ │ ├── usergroupusers.hbs
│ │ └── userstypeaway.hbs
│ ├── index.html
│ ├── logger
│ │ └── logger_list.html
│ ├── oauth2_provider
│ │ └── authorize.html
│ ├── projects
│ │ ├── navigation.html
│ │ ├── project_attributes.html
│ │ ├── project_create.html
│ │ ├── project_geographic_extent.html
│ │ ├── project_overview.html
│ │ ├── project_settings.html
│ │ └── projects_involved.html
│ ├── snippets
│ │ ├── data_fields_rules.html
│ │ ├── error.html
│ │ ├── footer.html
│ │ ├── google_analytics.html
│ │ ├── lookup_values.html
│ │ ├── messages.html
│ │ ├── project_help.html
│ │ ├── social_apps.html
│ │ └── usergroup_editor.html
│ ├── socialaccount
│ │ ├── authentication_error.html
│ │ ├── login_cancelled.html
│ │ └── signup.html
│ ├── socialinteractions
│ │ ├── socialinteraction_list.html
│ │ ├── socialinteraction_post_create.html
│ │ ├── socialinteraction_post_settings.html
│ │ ├── socialinteraction_pull.html
│ │ └── socialinteraction_pull_create.html
│ ├── subsets
│ │ ├── subset_create.html
│ │ ├── subset_data.html
│ │ ├── subset_list.html
│ │ ├── subset_navigation.html
│ │ └── subset_settings.html
│ ├── superusertools
│ │ ├── manage_inactive_users.html
│ │ ├── manage_projects.html
│ │ ├── manage_superusers.html
│ │ ├── navigation.html
│ │ ├── platform_settings.html
│ │ ├── provider_list.html
│ │ └── provider_overview.html
│ ├── templates.js
│ └── users
│ │ ├── profile.html
│ │ ├── usergroup_admins.html
│ │ ├── usergroup_create.html
│ │ ├── usergroup_data.html
│ │ ├── usergroup_list.html
│ │ ├── usergroup_navigation.html
│ │ ├── usergroup_overview.html
│ │ ├── usergroup_permissions.html
│ │ └── usergroup_settings.html
├── users
│ ├── __init__.py
│ ├── forms.py
│ ├── management
│ │ ├── __init__.py
│ │ └── commands
│ │ │ ├── __init__.py
│ │ │ └── check_confirm.py
│ ├── managers.py
│ ├── migrations
│ │ ├── 0001_initial.py
│ │ ├── 0002_auto_20150106_1420.py
│ │ ├── 0002_auto_20150824_1603.py
│ │ ├── 0002_auto_20150904_1113.py
│ │ ├── 0003_auto_20150611_1307.py
│ │ ├── 0004_auto_20150617_0902.py
│ │ ├── 0005_auto_20150825_0933.py
│ │ ├── 0006_merge.py
│ │ ├── 0007_auto_20151006_1110.py
│ │ ├── 0008_historicalusergroup.py
│ │ ├── 0009_auto_20180502_1258.py
│ │ └── __init__.py
│ ├── models.py
│ ├── serializers.py
│ ├── templatetags
│ │ ├── __init__.py
│ │ ├── filter_tags.py
│ │ └── social.py
│ ├── tests
│ │ ├── __init__.py
│ │ ├── model_factories.py
│ │ ├── test_admin_views.py
│ │ ├── test_ajax_views.py
│ │ ├── test_commands.py
│ │ ├── test_managers.py
│ │ ├── test_models.py
│ │ ├── test_serializers.py
│ │ └── test_templatetags.py
│ └── views.py
└── version.py
├── local_settings.example
├── __init__.py
├── settings.py
└── wsgi.py
├── manage.py
├── package.json
├── requirements-dev.txt
├── requirements.txt
└── setup.py
/.coveragerc:
--------------------------------------------------------------------------------
1 | [run]
2 | omit =
3 | geokey/*/tests/*
4 | geokey/*/migrations/*
5 | geokey/*/__init__.py
6 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | charset = utf-8
5 | indent_style = space
6 | indent_size = 4
7 | end_of_line = lf
8 | trim_trailing_whitespace = true
9 | insert_final_newline = true
10 |
11 | [*.md]
12 | trim_trailing_whitespace = false
13 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # GeoKey
2 | assets
3 | local_settings
4 |
5 | # Python folders and files
6 | .cache
7 | *.pyc
8 | *.egg-info
9 |
10 | # Coverage reports
11 | htmlcov
12 | .coverage
13 | coverage.xml
14 |
15 | # npm modules
16 | node_modules
17 |
18 | # Folder view configuration files
19 | .DS_Store
20 | Desktop.ini
21 |
22 | # Thumbnail cache files
23 | ._*
24 | Thumbs.db
25 |
26 | # Files that might appear on external disks
27 | .Spotlight-V100
28 | .Trashes
29 |
--------------------------------------------------------------------------------
/.jshintrc:
--------------------------------------------------------------------------------
1 | {
2 | "indent": 4,
3 | "browser": true,
4 | "globals": {
5 | "console": false,
6 | "L": false
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | dist: trusty
2 | language: python
3 |
4 | services:
5 | - postgresql
6 |
7 | python:
8 | - '2.7_with_system_site_packages'
9 | - '3.6'
10 |
11 | addons:
12 | postgresql: '9.4'
13 | apt:
14 | packages:
15 | - postgresql-9.4-postgis-2.3
16 |
17 | env:
18 | - DJANGO='>=1.8.19,<1.12'
19 |
20 | install:
21 | - sudo -E apt-get -yq update &>> ~/apt-get-update.log
22 | - sudo apt-get install binutils libav-tools
23 | - sudo apt-get -yq install libgdal-dev
24 | - gdal-config --version
25 | - export C_INCLUDE_PATH=/usr/include/gdal
26 | - export CPLUS_INCLUDE_PATH=/usr/include/gdal
27 |
28 | before_script:
29 | - psql template1 postgres -c "CREATE EXTENSION hstore;"
30 | - psql -c "CREATE USER django WITH PASSWORD 'django123';" -U postgres
31 | - psql -c "ALTER ROLE django WITH superuser;" -U postgres
32 | - psql -c "CREATE DATABASE geokey OWNER django;" -U postgres
33 | - psql -d geokey -c "CREATE EXTENSION postgis;" -U postgres
34 | - cp -r local_settings.example local_settings
35 | - pip install --upgrade pip
36 | - pip install coveralls
37 | - pip install -r requirements-dev.txt
38 | - pip install -e .
39 | - pip install django$DJANGO
40 | - python -c "import django; print('DJANGO %s' % django.get_version())"
41 | - python -c "from geokey.version import get_version; print('GEOKEY %s' % get_version())"
42 | - python manage.py migrate
43 |
44 | script:
45 | - coverage run --source=geokey.core,geokey.applications,geokey.extensions,geokey.users,geokey.superusertools,geokey.projects,geokey.categories,geokey.contributions,geokey.subsets,geokey.socialinteractions manage.py test
46 |
47 | after_success:
48 | - coveralls
49 |
50 | deploy:
51 | provider: pypi
52 | user: excites
53 | password:
54 | secure: EPsnf69HqWA8nT9ncgVuyhIJGZnR3Nrg8NUEzG4t1B1CTJfmwODC0Fb8Hybq25/0y6Fq3mBWE482xhscVHYvNh/7UnehU+y2riIj5iP+VYrfEuLzBN6ZkjYXOezafq6pzotwsj6JCDWKGmBE6Jy++FDsOFSzLK/R2p3HqnrnRpc=
55 | on:
56 | tags: true
57 | python: '3.6'
58 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM ubuntu:14.04
2 |
3 | RUN apt-get update && \
4 | apt-get install -y \
5 | binutils \
6 | g++ \
7 | libav-tools \
8 | python \
9 | libpython-dev \
10 | libgdal-dev \
11 | imagemagick \
12 | libmagickcore-dev \
13 | libmagickwand-dev \
14 | curl \
15 | wget && \
16 | apt-get clean
17 |
18 | RUN sed -i 's/\( \)/\1"read|write"\2/g' /etc/ImageMagick/policy.xml
19 |
20 | RUN python --version
21 | RUN curl "https://bootstrap.pypa.io/get-pip.py" -o "get-pip.py" && \
22 | python get-pip.py && \
23 | rm get-pip.py && \
24 | pip --version
25 |
26 | RUN gdal-config --version && \
27 | export C_INCLUDE_PATH=/usr/include/gdal && \
28 | export CPLUS_INCLUDE_PATH=/usr/include/gdal && \
29 | pip install gdal==1.10
30 |
31 | RUN curl -sL https://deb.nodesource.com/setup_8.x | bash - && \
32 | apt-get install -y nodejs && \
33 | node -v && npm -v
34 |
35 | ENV DOCKERIZE_VERSION v0.6.1
36 | RUN wget https://github.com/jwilder/dockerize/releases/download/$DOCKERIZE_VERSION/dockerize-linux-amd64-$DOCKERIZE_VERSION.tar.gz && \
37 | tar -C /usr/local/bin -xzvf dockerize-linux-amd64-$DOCKERIZE_VERSION.tar.gz && \
38 | rm dockerize-linux-amd64-$DOCKERIZE_VERSION.tar.gz
39 |
40 | ADD /geokey /app
41 |
42 | WORKDIR /app
43 | RUN \
44 | pip install --upgrade pip && \
45 | pip install -r requirements.txt && \
46 | pip install -r requirements-dev.txt && \
47 | pip install -e /app
48 | RUN npm install
49 |
--------------------------------------------------------------------------------
/GeoKey_updated_documentation.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ExCiteS/geokey/53b0bf85ffd30c9e958f028bf9ece5f6ef8d600f/GeoKey_updated_documentation.pdf
--------------------------------------------------------------------------------
/Gruntfile.js:
--------------------------------------------------------------------------------
1 | module.exports = function(grunt) {
2 | grunt.initConfig({
3 | pkg: grunt.file.readJSON('package.json'),
4 |
5 | handlebars: {
6 | options: {
7 | namespace: 'Templates',
8 | processName: function(filePath) {
9 | var file = filePath.split('/')[3];
10 | return file.substring(0, file.indexOf('.hbs'));
11 | },
12 | processPartialName: function(filePath) {
13 | var file = filePath.split('/')[3];
14 | return file.substring(1, file.indexOf('.hbs'));
15 | }
16 | },
17 |
18 | compile: {
19 | files: {
20 | 'geokey/templates/templates.js': 'geokey/templates/handlebars/**/*.hbs'
21 | }
22 | }
23 | },
24 |
25 | concat: {
26 | options: {
27 | separator: ';'
28 | },
29 |
30 | handlebars: {
31 | src: ['geokey/templates/handlebars/helpers.js', 'geokey/templates/templates.js'],
32 | dest: 'geokey/static/js/templates.js'
33 | }
34 | },
35 |
36 | uglify: {
37 | handlebars: {
38 | src: ['geokey/static/js/templates.js'],
39 | dest: 'geokey/static/js/templates.js'
40 | }
41 | },
42 |
43 | watch: {
44 | options: {
45 | livereload: true,
46 | },
47 |
48 | templates: {
49 | files: ['geokey/templates/handlebars/helpers.js', 'geokey/templates/handlebars/**/*.hbs'],
50 | tasks: ['handlebars', 'concat', 'uglify'],
51 | options: {
52 | spawn: false,
53 | }
54 | }
55 | }
56 | });
57 |
58 | grunt.loadNpmTasks('grunt-contrib-handlebars');
59 | grunt.loadNpmTasks('grunt-contrib-concat');
60 | grunt.loadNpmTasks('grunt-contrib-watch');
61 | grunt.loadNpmTasks('grunt-contrib-uglify');
62 |
63 | grunt.registerTask('default', ['handlebars', 'concat', 'uglify', 'watch']);
64 | };
65 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright 2017 Extreme Citizen Science research group
2 |
3 | Licensed under the Apache License, Version 2.0 (the "License");
4 | you may not use this file except in compliance with the License.
5 | You may obtain a copy of the License at
6 |
7 | http://www.apache.org/licenses/LICENSE-2.0
8 |
9 | Unless required by applicable law or agreed to in writing, software
10 | distributed under the License is distributed on an "AS IS" BASIS,
11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | See the License for the specific language governing permissions and
13 | limitations under the License.
14 |
--------------------------------------------------------------------------------
/MANIFEST.in:
--------------------------------------------------------------------------------
1 | include LICENSE
2 | include *.md
3 | include *.txt
4 | recursive-include geokey/static *
5 | recursive-include geokey/templates *
6 | recursive-exclude * *.pyc
7 |
--------------------------------------------------------------------------------
/db/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM mdillon/postgis
2 |
3 | COPY ./initdb-hstore.sh /docker-entrypoint-initdb.d/hstore.sh
4 |
--------------------------------------------------------------------------------
/db/initdb-hstore.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | set -e
4 |
5 | export PGUSER="$POSTGRES_USER"
6 |
7 | "${psql[@]}" --dbname="template1" <<-'EOSQL'
8 | CREATE EXTENSION IF NOT EXISTS hstore;
9 | EOSQL
10 |
11 | "${psql[@]}" --dbname="$POSTGRES_DB" <<-'EOSQL'
12 | CREATE EXTENSION IF NOT EXISTS hstore;
13 | EOSQL
14 |
--------------------------------------------------------------------------------
/docker-compose.yml:
--------------------------------------------------------------------------------
1 | version: "3"
2 |
3 | services:
4 | geokey:
5 | build:
6 | context: ../
7 | dockerfile: ./geokey/Dockerfile
8 | links:
9 | - db
10 | entrypoint: dockerize -wait tcp://db:5432 -timeout 20s
11 | command: tail -f /dev/null
12 | ports:
13 | - "9000:8000"
14 | environment:
15 | DJANGO_DATABASE_HOST: db
16 | volumes:
17 | - ./geokey:/app/geokey
18 | - ./local_settings:/app/local_settings
19 | - ./assets:/app/assets
20 | db:
21 | build:
22 | context: ./db
23 | dockerfile: ./Dockerfile
24 | environment:
25 | POSTGRES_USER: django
26 | POSTGRES_PASSWORD: django123
27 | POSTGRES_DB: geokey
28 |
--------------------------------------------------------------------------------
/geokey/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ExCiteS/geokey/53b0bf85ffd30c9e958f028bf9ece5f6ef8d600f/geokey/__init__.py
--------------------------------------------------------------------------------
/geokey/applications/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ExCiteS/geokey/53b0bf85ffd30c9e958f028bf9ece5f6ef8d600f/geokey/applications/__init__.py
--------------------------------------------------------------------------------
/geokey/applications/base.py:
--------------------------------------------------------------------------------
1 | """Base for applications."""
2 |
3 | from model_utils import Choices
4 |
5 |
6 | STATUS = Choices('active', 'deleted')
7 |
--------------------------------------------------------------------------------
/geokey/applications/forms.py:
--------------------------------------------------------------------------------
1 | """Forms for applications."""
2 |
3 | from django import forms
4 |
5 | from .models import Application
6 | from django.utils.html import strip_tags
7 |
8 |
9 | class AppCreateForm(forms.ModelForm):
10 | """
11 | Validates the inputs against the model definition.
12 | Used in .views.AppCreateView
13 | """
14 | class Meta:
15 | model = Application
16 | fields = ('name', 'description', 'download_url', 'redirect_uris',
17 | 'authorization_grant_type', 'skip_authorization')
18 |
19 | def clean(self):
20 | """
21 | Overwrites ModelForm's clean method to strip HTML Tags from name and
22 | description
23 |
24 | Returns
25 | -------
26 | dict
27 | Cleaned form data including HTML free name and description
28 | """
29 | cleaned_data = super(AppCreateForm, self).clean()
30 | cleaned_data['name'] = strip_tags(cleaned_data['name'])
31 | cleaned_data['description'] = strip_tags(cleaned_data['description'])
32 |
33 | return cleaned_data
34 |
--------------------------------------------------------------------------------
/geokey/applications/migrations/0001_initial.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals
3 |
4 | from django.db import migrations
5 | from django.conf import settings
6 |
7 |
8 | class Migration(migrations.Migration):
9 |
10 | dependencies = [
11 | migrations.swappable_dependency(settings.AUTH_USER_MODEL),
12 | ]
13 |
14 | operations = [
15 | migrations.RunSQL('DROP TABLE IF EXISTS applications_application CASCADE;'),
16 | migrations.RunSQL("DELETE FROM django_migrations WHERE app = 'applications';")
17 | ]
18 |
--------------------------------------------------------------------------------
/geokey/applications/migrations/0002_auto_20150112_1807.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals
3 |
4 | from django.db import models, migrations
5 | from django.conf import settings
6 |
7 |
8 | class Migration(migrations.Migration):
9 |
10 | dependencies = [
11 | ('applications', '0002_auto_20150112_1700'),
12 | ]
13 |
14 | operations = [
15 | migrations.AddField(
16 | model_name='application',
17 | name='skip_authorization',
18 | field=models.BooleanField(default=False),
19 | preserve_default=True,
20 | ),
21 | migrations.AlterField(
22 | model_name='application',
23 | name='user',
24 | field=models.ForeignKey(related_name='applications_application', to=settings.AUTH_USER_MODEL),
25 | preserve_default=True,
26 | ),
27 | ]
28 |
--------------------------------------------------------------------------------
/geokey/applications/migrations/0003_auto_20171024_1400.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals
3 |
4 | from django.db import migrations, models
5 | from django.conf import settings
6 |
7 |
8 | class Migration(migrations.Migration):
9 |
10 | dependencies = [
11 | ('applications', '0002_auto_20150112_1807'),
12 | ]
13 |
14 | operations = [
15 | migrations.AlterField(
16 | model_name='application',
17 | name='user',
18 | field=models.ForeignKey(related_name='applications_application', blank=True, to=settings.AUTH_USER_MODEL, null=True),
19 | ),
20 | ]
21 |
--------------------------------------------------------------------------------
/geokey/applications/migrations/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ExCiteS/geokey/53b0bf85ffd30c9e958f028bf9ece5f6ef8d600f/geokey/applications/migrations/__init__.py
--------------------------------------------------------------------------------
/geokey/applications/models.py:
--------------------------------------------------------------------------------
1 | """Models for applications."""
2 |
3 | try:
4 | # Python 3
5 | from re import fullmatch
6 | except ImportError:
7 | # Python 2
8 | def fullmatch(regex, string, flags=0):
9 | from re import match
10 | return match('(?:' + regex + r')\Z', string, flags=flags)
11 |
12 | try:
13 | # Python 3
14 | from urllib.parse import urlparse, parse_qsl
15 | except ImportError:
16 | # Python 2
17 | from urlparse import urlparse, parse_qsl
18 |
19 | from django.db import models
20 |
21 | from oauth2_provider.models import AbstractApplication
22 |
23 | from .base import STATUS
24 | from .managers import ApplicationManager
25 |
26 |
27 | class Application(AbstractApplication):
28 | """
29 | Represents an application, that is registered in order to interact with
30 | GeoKey platform.
31 | """
32 |
33 | description = models.TextField(null=True, blank=True)
34 | created_at = models.DateTimeField(auto_now_add=True)
35 | status = models.CharField(
36 | choices=STATUS,
37 | default=STATUS.active,
38 | max_length=20
39 | )
40 | download_url = models.URLField(blank=False)
41 |
42 | objects = ApplicationManager()
43 |
44 | def redirect_uri_allowed(self, uri):
45 | """
46 | Check if redirect URI is allowed, it can now be a regular expression,
47 | e.g: `https://(.*).example.com` will match all subdomains.
48 | """
49 | for allowed_uri in self.redirect_uris.split():
50 | parsed_allowed_uri = urlparse(allowed_uri)
51 | parsed_uri = urlparse(uri)
52 |
53 | if all([
54 | parsed_allowed_uri.scheme == parsed_uri.scheme,
55 | fullmatch(parsed_allowed_uri.netloc, parsed_uri.netloc),
56 | parsed_allowed_uri.path == parsed_uri.path,
57 | ]):
58 | aqs_set = set(parse_qsl(parsed_allowed_uri.query))
59 | uqs_set = set(parse_qsl(parsed_uri.query))
60 |
61 | if aqs_set.issubset(uqs_set):
62 | return True
63 |
64 | return False
65 |
--------------------------------------------------------------------------------
/geokey/applications/tests/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ExCiteS/geokey/53b0bf85ffd30c9e958f028bf9ece5f6ef8d600f/geokey/applications/tests/__init__.py
--------------------------------------------------------------------------------
/geokey/applications/tests/model_factories.py:
--------------------------------------------------------------------------------
1 | """Model factories used for tests of applications."""
2 |
3 | import datetime
4 | import factory
5 |
6 | from geokey.users.tests.model_factories import UserFactory
7 |
8 | from ..models import Application
9 |
10 |
11 | class ApplicationFactory(factory.django.DjangoModelFactory):
12 | class Meta:
13 | model = Application
14 |
15 | name = factory.Sequence(lambda n: 'name_%d' % n)
16 | description = factory.LazyAttribute(lambda o: '%s description' % o.name)
17 | created_at = datetime.date(2014, 11, 11)
18 | user = factory.SubFactory(UserFactory)
19 | download_url = 'http://example.com'
20 | redirect_uris = ['http://example.com/app']
21 | skip_authorization = False
22 | status = 'active'
23 |
--------------------------------------------------------------------------------
/geokey/applications/tests/test_managers.py:
--------------------------------------------------------------------------------
1 | """Tests for managers of applications."""
2 |
3 | from django.test import TestCase
4 | from django.core.exceptions import PermissionDenied
5 |
6 | from nose.tools import raises
7 |
8 | from geokey.projects.tests.model_factories import UserFactory
9 |
10 | from .model_factories import ApplicationFactory
11 |
12 | from ..models import Application
13 |
14 |
15 | class ApplicationManagerTest(TestCase):
16 | def setUp(self):
17 | self.user1 = UserFactory.create()
18 | self.user2 = UserFactory.create()
19 | self.app1 = ApplicationFactory(**{
20 | 'user': self.user1
21 | })
22 | self.app2 = ApplicationFactory(**{
23 | 'user': self.user1
24 | })
25 | self.app3 = ApplicationFactory(**{
26 | 'user': self.user2
27 | })
28 | self.deleted_app = ApplicationFactory(**{
29 | 'user': self.user1,
30 | 'status': 'deleted'
31 | })
32 |
33 | def test_get_apps_with_user1(self):
34 | apps = Application.objects.get_list(self.user1)
35 | self.assertEqual(len(apps), 2)
36 | self.assertNotIn(self.deleted_app, apps)
37 | self.assertNotIn(self.app3, apps)
38 |
39 | def test_get_apps_with_user2(self):
40 | apps = Application.objects.get_list(self.user2)
41 | self.assertEqual(len(apps), 1)
42 | self.assertNotIn(self.deleted_app, apps)
43 | self.assertNotIn(self.app1, apps)
44 | self.assertNotIn(self.app2, apps)
45 |
46 | def test_get_single_app_with_user1(self):
47 | app = Application.objects.as_owner(self.user1, self.app1.id)
48 | self.assertEqual(app, self.app1)
49 |
50 | @raises(PermissionDenied)
51 | def test_get_single_app_with_user2(self):
52 | Application.objects.as_owner(self.user2, self.app1.id)
53 |
--------------------------------------------------------------------------------
/geokey/applications/tests/test_models.py:
--------------------------------------------------------------------------------
1 | """Tests for models of applications."""
2 |
3 | from django.test import TestCase
4 |
5 | from nose.tools import raises
6 |
7 | from .model_factories import ApplicationFactory
8 |
9 | from ..models import Application
10 |
11 |
12 | class ApplicationModelTest(TestCase):
13 | @raises(Application.DoesNotExist)
14 | def test_delete_app(self):
15 | app = ApplicationFactory()
16 | app.delete()
17 | Application.objects.get(pk=app.id)
18 |
--------------------------------------------------------------------------------
/geokey/categories/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ExCiteS/geokey/53b0bf85ffd30c9e958f028bf9ece5f6ef8d600f/geokey/categories/__init__.py
--------------------------------------------------------------------------------
/geokey/categories/base.py:
--------------------------------------------------------------------------------
1 | """Base for categories."""
2 |
3 | from model_utils import Choices
4 |
5 |
6 | STATUS = Choices('active', 'inactive', 'deleted')
7 | DEFAULT_STATUS = Choices('active', 'pending')
8 |
--------------------------------------------------------------------------------
/geokey/categories/forms.py:
--------------------------------------------------------------------------------
1 | """Forms for categories."""
2 |
3 | from django import forms
4 |
5 | from .models import Category, Field
6 |
7 |
8 | class CategoryCreateForm(forms.ModelForm):
9 | """
10 | Validates the inputs against the model definition.
11 | Used in .views.ObservationTypeAdminCreateView
12 | """
13 |
14 | class Meta:
15 | model = Category
16 | fields = ('name', 'description', 'default_status')
17 |
18 |
19 | class FieldCreateForm(forms.ModelForm):
20 | """
21 | Validates the inputs against the model definition.
22 | Used in .views.FieldAdminCreateView
23 | """
24 | class Meta:
25 | model = Field
26 | fields = ('name', 'description', 'required')
27 |
--------------------------------------------------------------------------------
/geokey/categories/migrations/0002_auto_20150106_1338.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals
3 |
4 | from django.db import models, migrations
5 | from django.conf import settings
6 |
7 |
8 | class Migration(migrations.Migration):
9 |
10 | dependencies = [
11 | ('categories', '0001_initial'),
12 | migrations.swappable_dependency(settings.AUTH_USER_MODEL),
13 | ('projects', '0001_initial'),
14 | ]
15 |
16 | operations = [
17 | migrations.AddField(
18 | model_name='category',
19 | name='creator',
20 | field=models.ForeignKey(to=settings.AUTH_USER_MODEL),
21 | preserve_default=True,
22 | ),
23 | migrations.AddField(
24 | model_name='category',
25 | name='project',
26 | field=models.ForeignKey(related_name='categories', to='projects.Project'),
27 | preserve_default=True,
28 | ),
29 | ]
30 |
--------------------------------------------------------------------------------
/geokey/categories/migrations/0003_datefield.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals
3 |
4 | from django.db import models, migrations
5 |
6 |
7 | class Migration(migrations.Migration):
8 |
9 | dependencies = [
10 | ('categories', '0002_auto_20150106_1338'),
11 | ]
12 |
13 | operations = [
14 | migrations.CreateModel(
15 | name='DateField',
16 | fields=[
17 | ('field_ptr', models.OneToOneField(parent_link=True, auto_created=True, primary_key=True, serialize=False, to='categories.Field')),
18 | ],
19 | options={
20 | },
21 | bases=('categories.field',),
22 | ),
23 | ]
24 |
--------------------------------------------------------------------------------
/geokey/categories/migrations/0004_timefield.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals
3 |
4 | from django.db import models, migrations
5 |
6 |
7 | class Migration(migrations.Migration):
8 |
9 | dependencies = [
10 | ('categories', '0003_datefield'),
11 | ]
12 |
13 | operations = [
14 | migrations.CreateModel(
15 | name='TimeField',
16 | fields=[
17 | ('field_ptr', models.OneToOneField(parent_link=True, auto_created=True, primary_key=True, serialize=False, to='categories.Field')),
18 | ],
19 | options={
20 | },
21 | bases=('categories.field',),
22 | ),
23 | ]
24 |
--------------------------------------------------------------------------------
/geokey/categories/migrations/0005_auto_20150112_1731.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals
3 |
4 | from django.db import migrations
5 |
6 |
7 | class Migration(migrations.Migration):
8 |
9 | dependencies = [
10 | ('categories', '0004_timefield'),
11 | ]
12 |
13 | operations = [
14 | migrations.AlterModelOptions(
15 | name='category',
16 | options={'ordering': ['id']},
17 | ),
18 | ]
19 |
--------------------------------------------------------------------------------
/geokey/categories/migrations/0006_category_display_field.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals
3 |
4 | from django.db import models, migrations
5 |
6 |
7 | class Migration(migrations.Migration):
8 |
9 | dependencies = [
10 | ('categories', '0005_auto_20150112_1731'),
11 | ]
12 |
13 | operations = [
14 | migrations.AddField(
15 | model_name='category',
16 | name='display_field',
17 | field=models.ForeignKey(related_name='display_field_of', default=None, to='categories.Field', null=True),
18 | preserve_default=False,
19 | ),
20 | ]
21 |
--------------------------------------------------------------------------------
/geokey/categories/migrations/0007_auto_20150130_1155.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals
3 |
4 | from django.db import migrations
5 |
6 |
7 | def update_display_field(apps, schema_editor):
8 | Category = apps.get_model("categories", "Category")
9 | Field = apps.get_model("categories", "Field")
10 | for category in Category.objects.all():
11 | try:
12 | first_field = category.fields.get(order=0)
13 | category.display_field = first_field
14 | category.save()
15 | except Field.DoesNotExist:
16 | pass
17 |
18 |
19 | class Migration(migrations.Migration):
20 |
21 | dependencies = [
22 | ('categories', '0006_category_display_field'),
23 | ]
24 |
25 | operations = [
26 | migrations.RunPython(update_display_field),
27 | ]
28 |
--------------------------------------------------------------------------------
/geokey/categories/migrations/0008_auto_20150130_1216.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals
3 |
4 | from django.db import models, migrations
5 |
6 |
7 | class Migration(migrations.Migration):
8 |
9 | dependencies = [
10 | ('categories', '0007_auto_20150130_1155'),
11 | ]
12 |
13 | operations = [
14 | # migrations.AlterField(
15 | # model_name='category',
16 | # name='display_field',
17 | # field=models.ForeignKey(related_name='display_field_of', to='categories.Field', null=True),
18 | # preserve_default=True,
19 | # ),
20 | ]
21 |
--------------------------------------------------------------------------------
/geokey/categories/migrations/0010_auto_20150202_1023.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals
3 |
4 | from django.db import migrations
5 |
6 |
7 | class Migration(migrations.Migration):
8 |
9 | dependencies = [
10 | ('categories', '0008_auto_20150130_1216'),
11 | ]
12 |
13 | operations = [
14 | migrations.AlterModelOptions(
15 | name='category',
16 | options={'ordering': ['name']},
17 | ),
18 | ]
19 |
--------------------------------------------------------------------------------
/geokey/categories/migrations/0011_auto_20150220_1413.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals
3 |
4 | from django.db import models, migrations
5 |
6 |
7 | class Migration(migrations.Migration):
8 |
9 | dependencies = [
10 | ('categories', '0010_auto_20150202_1023'),
11 | ]
12 |
13 | operations = [
14 | migrations.AddField(
15 | model_name='textfield',
16 | name='maxlength',
17 | field=models.IntegerField(null=True, blank=True),
18 | preserve_default=True,
19 | ),
20 | migrations.AddField(
21 | model_name='textfield',
22 | name='textarea',
23 | field=models.BooleanField(default=False),
24 | preserve_default=True,
25 | ),
26 | ]
27 |
--------------------------------------------------------------------------------
/geokey/categories/migrations/0012_auto_20150223_1311.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals
3 |
4 | from django.db import models, migrations
5 |
6 |
7 | class Migration(migrations.Migration):
8 |
9 | dependencies = [
10 | ('categories', '0011_auto_20150220_1413'),
11 | ]
12 |
13 | operations = [
14 | migrations.AlterModelOptions(
15 | name='category',
16 | options={'ordering': ['order']},
17 | ),
18 | migrations.AddField(
19 | model_name='category',
20 | name='order',
21 | field=models.IntegerField(default=0),
22 | preserve_default=True,
23 | ),
24 | ]
25 |
--------------------------------------------------------------------------------
/geokey/categories/migrations/0013_auto_20150130_1440.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals
3 |
4 | from django.db import migrations
5 | from geokey.contributions.models import Observation
6 |
7 |
8 | def populate_display_field(apps, schema_editor):
9 | Category = apps.get_model("categories", "Category")
10 | # Observation = apps.get_model("contributions", "Observation")
11 |
12 | for category in Category.objects.all():
13 | if category.display_field is not None:
14 | for obs in Observation.objects.filter(category=category):
15 | obs.update_display_field()
16 | obs.save()
17 |
18 |
19 | class Migration(migrations.Migration):
20 |
21 | dependencies = [
22 | ('categories', '0012_auto_20150223_1311'),
23 | ]
24 |
25 | operations = [
26 | migrations.RunPython(populate_display_field),
27 | ]
28 |
--------------------------------------------------------------------------------
/geokey/categories/migrations/0014_auto_20160104_1409.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals
3 |
4 | from django.db import migrations, models
5 |
6 |
7 | class Migration(migrations.Migration):
8 |
9 | dependencies = [
10 | ('categories', '0013_auto_20150130_1440'),
11 | ]
12 |
13 | operations = [
14 | migrations.AlterField(
15 | model_name='category',
16 | name='symbol',
17 | field=models.ImageField(max_length=500, null=True, upload_to=b'symbols'),
18 | ),
19 | ]
20 |
--------------------------------------------------------------------------------
/geokey/categories/migrations/0015_lookupvalue_symbol.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals
3 |
4 | from django.db import migrations, models
5 |
6 |
7 | class Migration(migrations.Migration):
8 |
9 | dependencies = [
10 | ('categories', '0014_auto_20160104_1409'),
11 | ]
12 |
13 | operations = [
14 | migrations.AddField(
15 | model_name='lookupvalue',
16 | name='symbol',
17 | field=models.ImageField(max_length=500, null=True, upload_to=b'symbols'),
18 | ),
19 | ]
20 |
--------------------------------------------------------------------------------
/geokey/categories/migrations/0016_multiplelookupvalue_symbol.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals
3 |
4 | from django.db import migrations, models
5 |
6 |
7 | class Migration(migrations.Migration):
8 |
9 | dependencies = [
10 | ('categories', '0015_lookupvalue_symbol'),
11 | ]
12 |
13 | operations = [
14 | migrations.AddField(
15 | model_name='multiplelookupvalue',
16 | name='symbol',
17 | field=models.ImageField(max_length=500, null=True, upload_to=b'symbols'),
18 | ),
19 | ]
20 |
--------------------------------------------------------------------------------
/geokey/categories/migrations/0017_category_expiry_field.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals
3 |
4 | from django.db import migrations, models
5 |
6 |
7 | class Migration(migrations.Migration):
8 |
9 | dependencies = [
10 | ('categories', '0016_multiplelookupvalue_symbol'),
11 | ]
12 |
13 | operations = [
14 | migrations.AddField(
15 | model_name='category',
16 | name='expiry_field',
17 | field=models.ForeignKey(related_name='expiry_field_of', to='categories.Field', null=True),
18 | ),
19 | ]
20 |
--------------------------------------------------------------------------------
/geokey/categories/migrations/0019_auto_20181028_1638.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by Django 1.11.16 on 2018-10-28 16:38
3 | from __future__ import unicode_literals
4 |
5 | from django.db import migrations, models
6 |
7 |
8 | class Migration(migrations.Migration):
9 |
10 | dependencies = [
11 | ('categories', '0018_historicalcategory'),
12 | ]
13 |
14 | operations = [
15 | migrations.AlterModelOptions(
16 | name='lookupvalue',
17 | options={'ordering': ['order']},
18 | ),
19 | migrations.AlterModelOptions(
20 | name='multiplelookupvalue',
21 | options={'ordering': ['order']},
22 | ),
23 | migrations.AddField(
24 | model_name='lookupvalue',
25 | name='order',
26 | field=models.IntegerField(default=0),
27 | ),
28 | migrations.AddField(
29 | model_name='multiplelookupvalue',
30 | name='order',
31 | field=models.IntegerField(default=0),
32 | ),
33 | ]
34 |
--------------------------------------------------------------------------------
/geokey/categories/migrations/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ExCiteS/geokey/53b0bf85ffd30c9e958f028bf9ece5f6ef8d600f/geokey/categories/migrations/__init__.py
--------------------------------------------------------------------------------
/geokey/categories/mixins.py:
--------------------------------------------------------------------------------
1 | """Mixins for categories."""
2 |
3 | from geokey.core.decorators import handle_exceptions_for_admin
4 | from geokey.categories.models import Category, Field
5 |
6 |
7 | class CategoryMixin(object):
8 | """A mixin for category."""
9 |
10 | @handle_exceptions_for_admin
11 | def get_context_data(self, project_id, category_id, *args, **kwargs):
12 | """
13 | Return the context to render the view.
14 |
15 | Overwrite the method to add the project and the category to the
16 | context.
17 |
18 | Returns
19 | -------
20 | dict
21 | Context.
22 | """
23 | category = Category.objects.as_admin(
24 | self.request.user,
25 | project_id,
26 | category_id
27 | )
28 | return super(CategoryMixin, self).get_context_data(
29 | project=category.project,
30 | category=category,
31 | *args,
32 | **kwargs
33 | )
34 |
35 |
36 | class FieldMixin(object):
37 | """A mixin for field."""
38 |
39 | @handle_exceptions_for_admin
40 | def get_context_data(self, project_id, category_id, field_id,
41 | *args, **kwargs):
42 | """
43 | Return the context to render the view.
44 |
45 | Overwrite the method to add the project, the category and the field to
46 | the context.
47 |
48 | Returns
49 | -------
50 | dict
51 | Context.
52 | """
53 | field = Field.objects.as_admin(
54 | self.request.user,
55 | project_id,
56 | category_id,
57 | field_id
58 | )
59 | return super(FieldMixin, self).get_context_data(
60 | project=field.category.project,
61 | category=field.category,
62 | field=field,
63 | is_display_field=(field == field.category.display_field),
64 | is_expiry_field=(field == field.category.expiry_field),
65 | *args,
66 | **kwargs
67 | )
68 |
--------------------------------------------------------------------------------
/geokey/categories/templatetags/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ExCiteS/geokey/53b0bf85ffd30c9e958f028bf9ece5f6ef8d600f/geokey/categories/templatetags/__init__.py
--------------------------------------------------------------------------------
/geokey/categories/templatetags/filter_fields.py:
--------------------------------------------------------------------------------
1 | """Template tags for filtering fields."""
2 |
3 | from django import template
4 |
5 |
6 | register = template.Library()
7 |
8 |
9 | @register.filter
10 | def only_fields(fields, type_names):
11 | type_names = [type_name.strip() for type_name in type_names.split(',')]
12 | return [field for field in fields if field.type_name in type_names]
13 |
14 |
15 | @register.filter
16 | def except_fields(fields, type_names):
17 | type_names = [type_name.strip() for type_name in type_names.split(',')]
18 | return [field for field in fields if field.type_name not in type_names]
19 |
--------------------------------------------------------------------------------
/geokey/categories/tests/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ExCiteS/geokey/53b0bf85ffd30c9e958f028bf9ece5f6ef8d600f/geokey/categories/tests/__init__.py
--------------------------------------------------------------------------------
/geokey/context_processors.py:
--------------------------------------------------------------------------------
1 | from django.conf import settings
2 |
3 |
4 | def allowed_contributors(request):
5 | """Allows access to settings constants within templates."""
6 | _ = request # PEP-8 compliance without reducing readability.
7 | default = ("true", "auth", "false")
8 | # return the value you want as a dictionary. you may add multiple values in there.
9 | if hasattr(settings, 'ALLOWED_CONTRIBUTORS'):
10 | return {'ALLOWED_CONTRIBUTORS': settings.ALLOWED_CONTRIBUTORS}
11 | else:
12 | return {'ALLOWED_CONTRIBUTORS': default}
13 |
--------------------------------------------------------------------------------
/geokey/contributions/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ExCiteS/geokey/53b0bf85ffd30c9e958f028bf9ece5f6ef8d600f/geokey/contributions/__init__.py
--------------------------------------------------------------------------------
/geokey/contributions/base.py:
--------------------------------------------------------------------------------
1 | """Base for contributions."""
2 |
3 | from model_utils import Choices
4 |
5 |
6 | LOCATION_STATUS = Choices('active', 'review')
7 | OBSERVATION_STATUS = Choices('active', 'draft', 'review', 'pending', 'deleted')
8 | COMMENT_STATUS = Choices('active', 'deleted')
9 | COMMENT_REVIEW = Choices('open', 'resolved')
10 | MEDIA_STATUS = Choices('active', 'deleted')
11 | ACCEPTED_AUDIO_TYPES = (
12 | ('MPEG ADTS, layer III', 'mp3'),
13 | ('Audio file', 'mp3'),
14 | ('Ogg data, Opus audio', 'opus'),
15 | ('Ogg data', 'ogg'),
16 | ('WAVE audio', 'wav'),
17 | ('AAC-LC (.M4A) Audio', 'm4a'),
18 | ('MPEG v4 system', 'm4a'),
19 | ('Adaptive Multi-Rate Codec', 'amr'),
20 | ('MPEG v4 system, 3GPP', '3gp'),
21 | ('AIFF audio', 'aiff'),
22 | ('AAC', 'aac'),
23 | ('FLAC audio bitstream data', 'flac'),
24 | ('Microsoft ASF', 'wma'),
25 | )
26 | ACCEPTED_VIDEO_TYPES = (
27 | ('Apple QuickTime movie', 'mov'),
28 | ('RIFF (little-endian) data, AVI', 'avi'),
29 | ('Macromedia Flash Video', 'flv'),
30 | ('Matroska data', 'mkv'),
31 | ('MPEG sequence', 'mpg'),
32 | ('Macromedia Flash data', 'swf'),
33 | ('WebM', 'webm'),
34 | ('Microsoft ASF', 'wmv'),
35 | )
36 | ACCEPTED_IMAGE_TYPES = (
37 | ('GIF image data', 'gif'),
38 | ('JPEG image data', 'jpg'),
39 | ('PNG image data', 'png'),
40 | ('Scalable Vector Graphics', 'svg'),
41 | ('TIFF image data', 'tiff'),
42 | )
43 | ACCEPTED_DOC_TYPES = (
44 | ('PDF document', 'pdf'),
45 | )
46 | ACCEPTED_FILE_TYPES = \
47 | ACCEPTED_AUDIO_TYPES + \
48 | ACCEPTED_VIDEO_TYPES + \
49 | ACCEPTED_IMAGE_TYPES + \
50 | ACCEPTED_DOC_TYPES
51 |
--------------------------------------------------------------------------------
/geokey/contributions/migrations/0003_auto_20150121_1544.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 |
4 | from django.db import models, migrations
5 |
6 |
7 | class Migration(migrations.Migration):
8 |
9 | dependencies = [
10 | ('contributions', '0002_auto_20150106_1338'),
11 | ]
12 |
13 | operations = [
14 | migrations.AddField(
15 | model_name='historicalobservation',
16 | name='display_field',
17 | field=models.TextField(null=True, blank=True),
18 | preserve_default=True,
19 | ),
20 | migrations.AddField(
21 | model_name='observation',
22 | name='display_field',
23 | field=models.TextField(null=True, blank=True),
24 | preserve_default=True,
25 | ),
26 | ]
27 |
--------------------------------------------------------------------------------
/geokey/contributions/migrations/0004_auto_20150121_1455.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 |
4 | from django.db import migrations
5 |
6 |
7 | def populate_display_field(apps, schema_editor):
8 | Observation = apps.get_model("contributions", "Observation")
9 | for observation in Observation.objects.all():
10 | first_field = observation.category.fields.get(order=0)
11 | value = observation.attributes.get(first_field.key)
12 | observation.display_field = '%s:%s' % (first_field.key, value)
13 | observation.save()
14 |
15 |
16 | class Migration(migrations.Migration):
17 |
18 | dependencies = [
19 | ('contributions', '0003_auto_20150121_1544'),
20 | ]
21 |
22 | operations = [
23 | migrations.RunPython(populate_display_field),
24 | ]
25 |
--------------------------------------------------------------------------------
/geokey/contributions/migrations/0005_auto_20150202_1135.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 |
4 | from django.db import migrations
5 |
6 |
7 | def update_search_matches(apps, schema_editor):
8 | Observation = apps.get_model("contributions", "Observation")
9 | for observation in Observation.objects.all():
10 | observation.update_search_matches()
11 | observation.save()
12 |
13 |
14 | class Migration(migrations.Migration):
15 |
16 | dependencies = [
17 | ('contributions', '0004_auto_20150121_1455'),
18 | ]
19 |
20 | operations = [
21 | migrations.RunPython(update_search_matches),
22 | ]
23 |
--------------------------------------------------------------------------------
/geokey/contributions/migrations/0006_auto_20150312_1247.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 |
4 | from django.db import migrations
5 | try:
6 | from django.contrib.postgres.fields import JSONField
7 | except ImportError:
8 | from django_pgjson.fields import JsonBField as JSONField
9 |
10 |
11 | class Migration(migrations.Migration):
12 |
13 | dependencies = [
14 | ('contributions', '0005_auto_20150202_1135'),
15 | ]
16 |
17 | operations = [
18 | migrations.AddField(
19 | model_name='historicalobservation',
20 | name='properties',
21 | field=JSONField(default={}),
22 | preserve_default=True,
23 | ),
24 | migrations.AddField(
25 | model_name='observation',
26 | name='properties',
27 | field=JSONField(default={}),
28 | preserve_default=True,
29 | ),
30 | ]
31 |
--------------------------------------------------------------------------------
/geokey/contributions/migrations/0007_auto_20150312_1249.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 |
4 | from django.db import migrations
5 |
6 |
7 | def convert_value(val):
8 | if val is not None and isinstance(val, str):
9 | try: # it's an int
10 | return int(val)
11 | except ValueError:
12 | pass
13 |
14 | try: # it's a float
15 | return float(val)
16 | except ValueError:
17 | pass
18 |
19 | # cannot convert to number, returns string or None
20 | return val
21 |
22 |
23 | def copy_attributes(apps, schema_editor):
24 | Observation = apps.get_model("contributions", "Observation")
25 | for observation in Observation.objects.all():
26 | properties = {}
27 | for field in observation.category.fields.all():
28 | value = observation.attributes.get(field.key)
29 | if value is not None:
30 | properties[field.key] = convert_value(value)
31 |
32 | observation.properties = properties
33 | observation.save()
34 |
35 |
36 | class Migration(migrations.Migration):
37 |
38 | dependencies = [
39 | ('contributions', '0006_auto_20150312_1247'),
40 | ]
41 |
42 | operations = [
43 | migrations.RunPython(copy_attributes),
44 | ]
45 |
--------------------------------------------------------------------------------
/geokey/contributions/migrations/0008_auto_20150312_1508.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 |
4 | from django.db import models, migrations
5 |
6 |
7 | class Migration(migrations.Migration):
8 |
9 | dependencies = [
10 | ('contributions', '0007_auto_20150312_1249'),
11 | ]
12 |
13 | operations = [
14 | migrations.RemoveField(
15 | model_name='historicalobservation',
16 | name='attributes',
17 | ),
18 | migrations.RemoveField(
19 | model_name='observation',
20 | name='attributes',
21 | ),
22 | ]
23 |
--------------------------------------------------------------------------------
/geokey/contributions/migrations/0009_auto_20150420_1549.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 |
4 | from django.db import models, migrations
5 | import django.db.models.deletion
6 | from django.conf import settings
7 |
8 |
9 | class Migration(migrations.Migration):
10 |
11 | dependencies = [
12 | ('contributions', '0008_auto_20150312_1508'),
13 | ]
14 |
15 | operations = [
16 | migrations.AlterModelOptions(
17 | name='historicalobservation',
18 | options={'ordering': ('-history_date', '-history_id'), 'get_latest_by': 'history_date', 'verbose_name': 'historical observation'},
19 | ),
20 | migrations.AlterField(
21 | model_name='historicalobservation',
22 | name='history_user',
23 | field=models.ForeignKey(on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL, null=True),
24 | preserve_default=True,
25 | ),
26 | ]
27 |
--------------------------------------------------------------------------------
/geokey/contributions/migrations/0011_auto_20150527_1255.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 |
4 | from django.db import models, migrations
5 |
6 |
7 | def clean_youtube_links(apps, schema_editor):
8 | VideoFile = apps.get_model("contributions", "VideoFile")
9 |
10 | for file in VideoFile.objects.all():
11 | new_link = file.youtube_link.replace('http://', 'https://')
12 | file.youtube_link = new_link
13 | file.save()
14 |
15 |
16 | class Migration(migrations.Migration):
17 |
18 | dependencies = [
19 | ('contributions', '0010_auto_20150511_1132'),
20 | ]
21 |
22 | operations = [
23 | migrations.RunPython(clean_youtube_links),
24 | ]
25 |
--------------------------------------------------------------------------------
/geokey/contributions/migrations/0012_auto_20150807_0854.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 |
4 | from django.db import models, migrations
5 |
6 |
7 | def update_count(apps, schema_editor):
8 | Observation = apps.get_model('contributions', 'Observation')
9 |
10 | for o in Observation.objects.all():
11 | o.num_media = o.files_attached.exclude(status='deleted').count()
12 | o.num_comments = o.comments.exclude(status='deleted').count()
13 | o.save()
14 |
15 |
16 | class Migration(migrations.Migration):
17 |
18 | dependencies = [
19 | ('contributions', '0011_auto_20150527_1255'),
20 | ]
21 |
22 | operations = [
23 | migrations.AddField(
24 | model_name='historicalobservation',
25 | name='num_comments',
26 | field=models.IntegerField(default=0),
27 | preserve_default=True,
28 | ),
29 | migrations.AddField(
30 | model_name='historicalobservation',
31 | name='num_media',
32 | field=models.IntegerField(default=0),
33 | preserve_default=True,
34 | ),
35 | migrations.AddField(
36 | model_name='observation',
37 | name='num_comments',
38 | field=models.IntegerField(default=0),
39 | preserve_default=True,
40 | ),
41 | migrations.AddField(
42 | model_name='observation',
43 | name='num_media',
44 | field=models.IntegerField(default=0),
45 | preserve_default=True,
46 | ),
47 | migrations.RunPython(update_count)
48 | ]
49 |
--------------------------------------------------------------------------------
/geokey/contributions/migrations/0014_auto_20150907_1345.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 |
4 | from django.db import models, migrations
5 | import re
6 |
7 |
8 | def create_search_index(apps, schema_editor):
9 | Observation = apps.get_model('contributions', 'Observation')
10 |
11 | for o in Observation.objects.all():
12 | search_index = []
13 |
14 | fields = o.search_matches.split('#####')
15 | for field in fields:
16 | if field:
17 | value = field.split(':')[1]
18 |
19 | cleaned = re.sub(r'[\W_]+', ' ', value)
20 | terms = cleaned.lower().split()
21 |
22 | search_index = search_index + list(
23 | set(terms) - set(search_index)
24 | )
25 |
26 | o.search_index = ','.join(search_index)
27 | o.save()
28 |
29 |
30 | class Migration(migrations.Migration):
31 |
32 | dependencies = [
33 | ('contributions', '0013_auto_20150907_1345'),
34 | ]
35 |
36 | operations = [
37 | migrations.RunPython(create_search_index)
38 | ]
39 |
--------------------------------------------------------------------------------
/geokey/contributions/migrations/0015_auto_20150907_1345.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 |
4 | from django.db import models, migrations
5 |
6 |
7 | class Migration(migrations.Migration):
8 |
9 | dependencies = [
10 | ('contributions', '0014_auto_20150907_1345'),
11 | ]
12 |
13 | operations = [
14 | migrations.RemoveField(
15 | model_name='historicalobservation',
16 | name='search_matches',
17 | ),
18 | migrations.RemoveField(
19 | model_name='observation',
20 | name='search_matches',
21 | ),
22 | ]
23 |
--------------------------------------------------------------------------------
/geokey/contributions/migrations/0016_audiofile.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 |
4 | from django.db import models, migrations
5 |
6 |
7 | class Migration(migrations.Migration):
8 |
9 | dependencies = [
10 | ('contributions', '0015_auto_20150907_1345'),
11 | ]
12 |
13 | operations = [
14 | migrations.CreateModel(
15 | name='AudioFile',
16 | fields=[
17 | ('mediafile_ptr', models.OneToOneField(parent_link=True, auto_created=True, primary_key=True, serialize=False, to='contributions.MediaFile')),
18 | ('audio', models.FileField(upload_to=b'user-uploads/audio')),
19 | ],
20 | options={
21 | 'ordering': ['id'],
22 | },
23 | bases=('contributions.mediafile',),
24 | ),
25 | ]
26 |
--------------------------------------------------------------------------------
/geokey/contributions/migrations/0017_auto_20160531_1434.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 |
4 | from django.db import migrations, models
5 |
6 |
7 | class Migration(migrations.Migration):
8 |
9 | dependencies = [
10 | ('contributions', '0016_audiofile'),
11 | ]
12 |
13 | operations = [
14 | migrations.AddField(
15 | model_name='historicalobservation',
16 | name='expiry_field',
17 | field=models.DateTimeField(null=True, blank=True),
18 | ),
19 | migrations.AddField(
20 | model_name='observation',
21 | name='expiry_field',
22 | field=models.DateTimeField(null=True, blank=True),
23 | ),
24 | ]
25 |
--------------------------------------------------------------------------------
/geokey/contributions/migrations/0019_auto_20181020_1915.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals
3 |
4 | from django.db import migrations, models
5 |
6 |
7 | class Migration(migrations.Migration):
8 |
9 | dependencies = [
10 | ('contributions', '0018_historicalcomment'),
11 | ]
12 |
13 | operations = [
14 | migrations.CreateModel(
15 | name='DocumentFile',
16 | fields=[
17 | ('mediafile_ptr', models.OneToOneField(parent_link=True, auto_created=True, primary_key=True, serialize=False, to='contributions.MediaFile')),
18 | ('document', models.FileField(upload_to=b'user-uploads/documents')),
19 | ('thumbnail', models.ImageField(null=True, upload_to=b'user-uploads/documents')),
20 | ],
21 | options={
22 | 'ordering': ['id'],
23 | },
24 | bases=('contributions.mediafile',),
25 | ),
26 | migrations.AlterModelOptions(
27 | name='mediafile',
28 | options={},
29 | ),
30 | ]
31 |
--------------------------------------------------------------------------------
/geokey/contributions/migrations/0020_update_media_and_comments_count.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | from django.db import migrations, transaction, IntegrityError
4 |
5 |
6 | def update_media_and_comments_count(apps, schema_editor):
7 | Observation = apps.get_model('contributions', 'Observation')
8 |
9 | for observation in Observation.objects.all():
10 | try:
11 | with transaction.atomic():
12 | observation.num_media = observation.files_attached.count()
13 | observation.num_comments = observation.comments.count()
14 | observation.save()
15 | except IntegrityError:
16 | pass
17 |
18 |
19 | class Migration(migrations.Migration):
20 |
21 | dependencies = [
22 | ('contributions', '0019_auto_20181020_1915'),
23 | ]
24 |
25 | operations = [
26 | migrations.RunPython(update_media_and_comments_count)
27 | ]
28 |
--------------------------------------------------------------------------------
/geokey/contributions/migrations/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ExCiteS/geokey/53b0bf85ffd30c9e958f028bf9ece5f6ef8d600f/geokey/contributions/migrations/__init__.py
--------------------------------------------------------------------------------
/geokey/contributions/parsers/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ExCiteS/geokey/53b0bf85ffd30c9e958f028bf9ece5f6ef8d600f/geokey/contributions/parsers/__init__.py
--------------------------------------------------------------------------------
/geokey/contributions/parsers/geojson.py:
--------------------------------------------------------------------------------
1 | """GeoJSON parser."""
2 |
3 | import json
4 | from rest_framework.parsers import BaseParser
5 |
6 |
7 | class GeoJsonParser(BaseParser):
8 | """Parses GeoJson into deserialisable native Python objects """
9 | media_type = 'application/json'
10 |
11 | def parse(self, stream, media_type=None, parser_context=None):
12 | """
13 | Parses the GeoJson imput and returns deserialisable Python native
14 | """
15 | parser_context = parser_context or {}
16 |
17 | request_data = stream.read()
18 | data = json.loads(request_data)
19 |
20 | if 'geometry' in data:
21 | if 'location' not in data:
22 | data['location'] = {}
23 |
24 | data['location']['geometry'] = json.dumps(data.pop('geometry'))
25 |
26 | return data
27 |
--------------------------------------------------------------------------------
/geokey/contributions/renderers/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ExCiteS/geokey/53b0bf85ffd30c9e958f028bf9ece5f6ef8d600f/geokey/contributions/renderers/__init__.py
--------------------------------------------------------------------------------
/geokey/contributions/renderers/geojson.py:
--------------------------------------------------------------------------------
1 | """GeoJSON renderer."""
2 |
3 | import json
4 |
5 | from rest_framework.renderers import BaseRenderer
6 |
7 |
8 | class GeoJsonRenderer(BaseRenderer):
9 | """
10 | Renderes serialised Contributions into GeoJson
11 | """
12 | media_type = 'application/json'
13 | format = 'json'
14 | separators = (',', ':')
15 |
16 | def render_single(self, data):
17 | """
18 | Renders a single `Contribution` into GeoJson
19 | """
20 | try:
21 | data['type'] = "Feature"
22 | data['geometry'] = json.loads(data.get('location').pop('geometry'))
23 | return data
24 | except:
25 | return data
26 |
27 | def render_many(self, data):
28 | """
29 | Creates a `FeatureCollection` object and adds Contributions to
30 | `features`.
31 | """
32 | return {
33 | "type": "FeatureCollection",
34 | "features": [self.render_single(item) for item in data]
35 | }
36 |
37 | def render(self, data, accepted_media_type=None, renderer_context=None):
38 | """
39 | Renders `data` into serialized GeoJson.
40 | """
41 |
42 | if '(e.g:bbox=xmin,ymin,xmax,ymax)' in str(data):
43 | rendered = {'error': str(data)}
44 | return json.dumps(rendered)
45 | if data is None:
46 | return ''
47 |
48 | if 'error' in data:
49 | rendered = data
50 | elif isinstance(data, dict):
51 | rendered = self.render_single(data)
52 | else:
53 | rendered = self.render_many(data)
54 |
55 | return json.dumps(rendered, separators=self.separators)
56 |
--------------------------------------------------------------------------------
/geokey/contributions/renderers/kml.py:
--------------------------------------------------------------------------------
1 | """KML renderer."""
2 |
3 | from django.template.loader import render_to_string
4 |
5 | from rest_framework.renderers import BaseRenderer
6 |
7 |
8 | class KmlRenderer(BaseRenderer):
9 | media_type = 'application/vnd.google-earth.kml+xml'
10 | format = 'kml'
11 |
12 | def render(self, data, accepted_media_type=None, renderer_context=None):
13 | rendered = render_to_string(
14 | 'geometries/placemarks.kml',
15 | {'data': data}
16 | )
17 |
18 | return rendered
19 |
--------------------------------------------------------------------------------
/geokey/contributions/templatetags/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ExCiteS/geokey/53b0bf85ffd30c9e958f028bf9ece5f6ef8d600f/geokey/contributions/templatetags/__init__.py
--------------------------------------------------------------------------------
/geokey/contributions/tests/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ExCiteS/geokey/53b0bf85ffd30c9e958f028bf9ece5f6ef8d600f/geokey/contributions/tests/__init__.py
--------------------------------------------------------------------------------
/geokey/contributions/tests/comments/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ExCiteS/geokey/53b0bf85ffd30c9e958f028bf9ece5f6ef8d600f/geokey/contributions/tests/comments/__init__.py
--------------------------------------------------------------------------------
/geokey/contributions/tests/comments/test_managers.py:
--------------------------------------------------------------------------------
1 | """Tests for managers of contributions (comments)."""
2 |
3 | from django.test import TestCase
4 |
5 | from ..model_factories import ObservationFactory, CommentFactory
6 | from geokey.contributions.models import Comment
7 |
8 |
9 | class CommentTest(TestCase):
10 | def test_get_comments(self):
11 | observation = ObservationFactory.create()
12 | CommentFactory.create_batch(5, **{'commentto': observation})
13 | CommentFactory.create(**{
14 | 'commentto': observation,
15 | 'status': 'deleted'
16 | })
17 | comments = Comment.objects.all()
18 | self.assertEqual(len(comments), 5)
19 | for comment in comments:
20 | self.assertNotEqual(comment.status, 'deleted')
21 |
--------------------------------------------------------------------------------
/geokey/contributions/tests/comments/test_models.py:
--------------------------------------------------------------------------------
1 | """Tests for models of contributions (comments)."""
2 |
3 | from django.test import TestCase
4 |
5 | from nose.tools import raises
6 |
7 | from geokey.contributions.models import Comment, post_save_count_update
8 | from ..model_factories import ObservationFactory, CommentFactory
9 |
10 |
11 | class TestCommentPostSave(TestCase):
12 | def test_post_save_comment_count_update(self):
13 | observation = ObservationFactory()
14 | CommentFactory.create_batch(5, **{'commentto': observation})
15 | comment = CommentFactory.create(**{
16 | 'commentto': observation,
17 | 'status': 'deleted'
18 | })
19 |
20 | post_save_count_update(
21 | Comment,
22 | instance=comment,
23 | created=True)
24 |
25 | observation.refresh_from_db()
26 | self.assertEqual(observation.num_media, 0)
27 | self.assertEqual(observation.num_comments, 5)
28 |
29 |
30 | class CommentTest(TestCase):
31 | @raises(Comment.DoesNotExist)
32 | def test_delete_comment(self):
33 | comment = CommentFactory()
34 | comment.delete()
35 | Comment.objects.get(pk=comment.id)
36 |
37 | def test_delete_nested(self):
38 | comment = CommentFactory()
39 | response = CommentFactory(**{'respondsto': comment})
40 | CommentFactory.create_batch(3, **{'respondsto': response})
41 | self.assertEqual(len(Comment.objects.all()), 5)
42 | comment.delete()
43 | self.assertEqual(len(Comment.objects.all()), 0)
44 |
--------------------------------------------------------------------------------
/geokey/contributions/tests/locations/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ExCiteS/geokey/53b0bf85ffd30c9e958f028bf9ece5f6ef8d600f/geokey/contributions/tests/locations/__init__.py
--------------------------------------------------------------------------------
/geokey/contributions/tests/media/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ExCiteS/geokey/53b0bf85ffd30c9e958f028bf9ece5f6ef8d600f/geokey/contributions/tests/media/__init__.py
--------------------------------------------------------------------------------
/geokey/contributions/tests/media/files/audio_1.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ExCiteS/geokey/53b0bf85ffd30c9e958f028bf9ece5f6ef8d600f/geokey/contributions/tests/media/files/audio_1.mp3
--------------------------------------------------------------------------------
/geokey/contributions/tests/media/files/audio_10.flac:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ExCiteS/geokey/53b0bf85ffd30c9e958f028bf9ece5f6ef8d600f/geokey/contributions/tests/media/files/audio_10.flac
--------------------------------------------------------------------------------
/geokey/contributions/tests/media/files/audio_12.wma:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ExCiteS/geokey/53b0bf85ffd30c9e958f028bf9ece5f6ef8d600f/geokey/contributions/tests/media/files/audio_12.wma
--------------------------------------------------------------------------------
/geokey/contributions/tests/media/files/audio_2.3gp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ExCiteS/geokey/53b0bf85ffd30c9e958f028bf9ece5f6ef8d600f/geokey/contributions/tests/media/files/audio_2.3gp
--------------------------------------------------------------------------------
/geokey/contributions/tests/media/files/audio_3.opus:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ExCiteS/geokey/53b0bf85ffd30c9e958f028bf9ece5f6ef8d600f/geokey/contributions/tests/media/files/audio_3.opus
--------------------------------------------------------------------------------
/geokey/contributions/tests/media/files/audio_4.m4a:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ExCiteS/geokey/53b0bf85ffd30c9e958f028bf9ece5f6ef8d600f/geokey/contributions/tests/media/files/audio_4.m4a
--------------------------------------------------------------------------------
/geokey/contributions/tests/media/files/audio_5.amr:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ExCiteS/geokey/53b0bf85ffd30c9e958f028bf9ece5f6ef8d600f/geokey/contributions/tests/media/files/audio_5.amr
--------------------------------------------------------------------------------
/geokey/contributions/tests/media/files/audio_6.aiff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ExCiteS/geokey/53b0bf85ffd30c9e958f028bf9ece5f6ef8d600f/geokey/contributions/tests/media/files/audio_6.aiff
--------------------------------------------------------------------------------
/geokey/contributions/tests/media/files/audio_7.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ExCiteS/geokey/53b0bf85ffd30c9e958f028bf9ece5f6ef8d600f/geokey/contributions/tests/media/files/audio_7.wav
--------------------------------------------------------------------------------
/geokey/contributions/tests/media/files/audio_8:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ExCiteS/geokey/53b0bf85ffd30c9e958f028bf9ece5f6ef8d600f/geokey/contributions/tests/media/files/audio_8
--------------------------------------------------------------------------------
/geokey/contributions/tests/media/files/audio_8.opus:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ExCiteS/geokey/53b0bf85ffd30c9e958f028bf9ece5f6ef8d600f/geokey/contributions/tests/media/files/audio_8.opus
--------------------------------------------------------------------------------
/geokey/contributions/tests/media/files/audio_9.aac:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ExCiteS/geokey/53b0bf85ffd30c9e958f028bf9ece5f6ef8d600f/geokey/contributions/tests/media/files/audio_9.aac
--------------------------------------------------------------------------------
/geokey/contributions/tests/media/files/document_1.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ExCiteS/geokey/53b0bf85ffd30c9e958f028bf9ece5f6ef8d600f/geokey/contributions/tests/media/files/document_1.pdf
--------------------------------------------------------------------------------
/geokey/contributions/tests/media/files/document_2.doc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ExCiteS/geokey/53b0bf85ffd30c9e958f028bf9ece5f6ef8d600f/geokey/contributions/tests/media/files/document_2.doc
--------------------------------------------------------------------------------
/geokey/contributions/tests/media/files/image_01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ExCiteS/geokey/53b0bf85ffd30c9e958f028bf9ece5f6ef8d600f/geokey/contributions/tests/media/files/image_01.png
--------------------------------------------------------------------------------
/geokey/contributions/tests/media/files/image_02.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ExCiteS/geokey/53b0bf85ffd30c9e958f028bf9ece5f6ef8d600f/geokey/contributions/tests/media/files/image_02.jpg
--------------------------------------------------------------------------------
/geokey/contributions/tests/media/files/image_03.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ExCiteS/geokey/53b0bf85ffd30c9e958f028bf9ece5f6ef8d600f/geokey/contributions/tests/media/files/image_03.gif
--------------------------------------------------------------------------------
/geokey/contributions/tests/media/files/image_05.tiff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ExCiteS/geokey/53b0bf85ffd30c9e958f028bf9ece5f6ef8d600f/geokey/contributions/tests/media/files/image_05.tiff
--------------------------------------------------------------------------------
/geokey/contributions/tests/media/files/text_1.txt:
--------------------------------------------------------------------------------
1 | A test text file.
2 |
--------------------------------------------------------------------------------
/geokey/contributions/tests/media/files/video.MOV:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ExCiteS/geokey/53b0bf85ffd30c9e958f028bf9ece5f6ef8d600f/geokey/contributions/tests/media/files/video.MOV
--------------------------------------------------------------------------------
/geokey/contributions/tests/media/helpers/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ExCiteS/geokey/53b0bf85ffd30c9e958f028bf9ece5f6ef8d600f/geokey/contributions/tests/media/helpers/__init__.py
--------------------------------------------------------------------------------
/geokey/contributions/tests/media/helpers/document_helpers.py:
--------------------------------------------------------------------------------
1 | """Document helpers of contributions."""
2 |
3 | from os.path import dirname, normpath, abspath, join
4 |
5 | from django.core.files import File
6 | from django.core.files.base import ContentFile
7 |
8 |
9 | def get_pdf_document(file_name='document_1.pdf'):
10 | pdf_file = File(open(
11 | normpath(join(
12 | dirname(dirname(abspath(__file__))),
13 | 'files/document_1.pdf'
14 | )),
15 | 'rb'
16 | ))
17 |
18 | the_file = ContentFile(pdf_file.read(), file_name)
19 | the_file.content_type = 'application/pdf'
20 |
21 | return the_file
22 |
23 |
24 | def get_doc_document(file_name='document_2.doc'):
25 | doc_file = File(open(
26 | normpath(join(
27 | dirname(dirname(abspath(__file__))),
28 | 'files/document_2.doc'
29 | )),
30 | 'rb'
31 | ))
32 |
33 | the_file = ContentFile(doc_file.read(), file_name)
34 | the_file.content_type = 'application/msword'
35 |
36 | return the_file
37 |
--------------------------------------------------------------------------------
/geokey/contributions/tests/model_factories.py:
--------------------------------------------------------------------------------
1 | """Model factories used for tests of contributions."""
2 |
3 | import datetime
4 | import factory
5 |
6 | from geokey.users.tests.model_factories import UserFactory
7 | from geokey.projects.tests.model_factories import ProjectFactory
8 | from geokey.categories.tests.model_factories import CategoryFactory
9 |
10 | from ..models import Location, Observation, Comment
11 |
12 |
13 | class LocationFactory(factory.django.DjangoModelFactory):
14 | class Meta:
15 | model = Location
16 |
17 | name = factory.Sequence(lambda n: 'name_%d' % n)
18 | description = factory.LazyAttribute(lambda o: '%s description' % o.name)
19 | geometry = 'POINT(-0.134040713310241 51.52447878755655)'
20 | created_at = datetime.date(2014, 11, 11)
21 | creator = factory.SubFactory(UserFactory)
22 | status = 'active'
23 | version = 1
24 | private = False
25 | private_for_project = None
26 |
27 |
28 | class ObservationFactory(factory.django.DjangoModelFactory):
29 | class Meta:
30 | model = Observation
31 |
32 | location = factory.SubFactory(LocationFactory)
33 | project = factory.SubFactory(ProjectFactory)
34 | status = 'active'
35 | category = factory.SubFactory(CategoryFactory)
36 | created_at = datetime.date(2014, 11, 11)
37 | creator = factory.SubFactory(UserFactory)
38 | version = 1
39 |
40 |
41 | class CommentFactory(factory.django.DjangoModelFactory):
42 | class Meta:
43 | model = Comment
44 |
45 | text = factory.Sequence(lambda n: 'Comment number %d' % n)
46 | created_at = datetime.date(2014, 11, 11)
47 | creator = factory.SubFactory(UserFactory)
48 | commentto = factory.SubFactory(ObservationFactory)
49 | respondsto = None
50 | status = 'active'
51 |
--------------------------------------------------------------------------------
/geokey/contributions/tests/observations/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ExCiteS/geokey/53b0bf85ffd30c9e958f028bf9ece5f6ef8d600f/geokey/contributions/tests/observations/__init__.py
--------------------------------------------------------------------------------
/geokey/contributions/views/__init__.py:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/geokey/contributions/views/base.py:
--------------------------------------------------------------------------------
1 | """Base for views of contributions."""
2 |
3 | from geokey.projects.models import Project
4 |
5 |
6 | class SingleAllContribution(object):
7 | """Base class for a single contribution of all contributions."""
8 |
9 | def get_contribution(self, user, project_id, contribution_id):
10 | """
11 | Get a single contribution.
12 |
13 | Parameters
14 | ----------
15 | user : geokey.users.models.User
16 | User requesting the request.
17 | project_id : int
18 | Identifies the project in the database.
19 | contribution_id : int
20 | Identifies the contribution in the database.
21 |
22 | Returns
23 | -------
24 | geokey.contributions.models.Observation
25 | Contribution with the required ID.
26 | """
27 | project = Project.objects.get_single(user, project_id)
28 |
29 | if project.can_moderate(user):
30 | return project\
31 | .get_all_contributions(user)\
32 | .for_moderator(user)\
33 | .select_related('location', 'project')\
34 | .prefetch_related('comments')\
35 | .get(pk=contribution_id)
36 | else:
37 | return project\
38 | .get_all_contributions(user)\
39 | .for_viewer(user)\
40 | .select_related('location', 'project')\
41 | .prefetch_related('comments')\
42 | .get(pk=contribution_id)
43 |
--------------------------------------------------------------------------------
/geokey/core/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ExCiteS/geokey/53b0bf85ffd30c9e958f028bf9ece5f6ef8d600f/geokey/core/__init__.py
--------------------------------------------------------------------------------
/geokey/core/adapters.py:
--------------------------------------------------------------------------------
1 | """Core adapters."""
2 |
3 | import re
4 |
5 | from django.core.urlresolvers import reverse
6 | from django.contrib import messages
7 |
8 | from allauth.account.adapter import DefaultAccountAdapter
9 | from allauth.socialaccount.adapter import DefaultSocialAccountAdapter
10 | from allauth.account.models import EmailAddress
11 |
12 |
13 | class AccountAdapter(DefaultAccountAdapter):
14 | """Adapter for accounts."""
15 |
16 | username_regex = re.compile(r'^.+$')
17 |
18 | def respond_user_inactive(self, request, user):
19 | """Resend email confirmation instructions if user is inactive."""
20 | try:
21 | email_address = EmailAddress.objects.get(
22 | user=user,
23 | email=user.email)
24 | self.add_message(
25 | request,
26 | messages.INFO,
27 | 'account/messages/'
28 | 'email_confirmation_sent.txt',
29 | {'email': user.email})
30 | email_address.send_confirmation(request)
31 | except EmailAddress.DoesNotExist:
32 | pass
33 |
34 | return super(AccountAdapter, self).respond_user_inactive(request, user)
35 |
36 |
37 | class SocialAccountAdapter(DefaultSocialAccountAdapter):
38 | """Adapter for social accounts."""
39 |
40 | def get_connect_redirect_url(self, request, socialaccount):
41 | """Return URL after successfull connecting a social account."""
42 | assert request.user.is_authenticated()
43 | url = reverse('admin:userprofile')
44 | return url
45 |
--------------------------------------------------------------------------------
/geokey/core/base.py:
--------------------------------------------------------------------------------
1 | """Core base."""
2 |
3 | from model_utils import Choices
4 |
5 |
6 | STATUS_ACTION = Choices('created', 'updated', 'deleted')
7 | LOG_MODELS = {
8 | 'Project': [
9 | 'name',
10 | 'status',
11 | 'isprivate',
12 | 'islocked',
13 | 'everyone_contributes',
14 | 'geographic_extent',
15 | ],
16 | 'Admins': [],
17 | 'UserGroup': [
18 | 'name',
19 | 'can_contribute',
20 | 'can_moderate',
21 | ],
22 | 'Category': [
23 | 'name',
24 | 'status',
25 | 'default_status',
26 | ],
27 | 'TextField': [
28 | 'name',
29 | 'status',
30 | 'required',
31 | ],
32 | 'NumericField': [
33 | 'name',
34 | 'status',
35 | 'required',
36 | ],
37 | 'DateTimeField': [
38 | 'name',
39 | 'status',
40 | 'required',
41 | ],
42 | 'DateField': [
43 | 'name',
44 | 'status',
45 | 'required',
46 | ],
47 | 'TimeField': [
48 | 'name',
49 | 'status',
50 | 'required',
51 | ],
52 | 'LookupField': [
53 | 'name',
54 | 'status',
55 | 'required',
56 | ],
57 | 'MultipleLookupField': [
58 | 'name',
59 | 'status',
60 | 'required',
61 | ],
62 | 'Location': [
63 | 'name',
64 | 'geometry',
65 | ],
66 | 'Observation': [
67 | 'status',
68 | 'properties',
69 | ],
70 | 'Comment': [
71 | 'status',
72 | ],
73 | 'ImageFile': [
74 | 'status',
75 | ],
76 | 'DocumentFile': [
77 | 'status',
78 | ],
79 | 'VideoFile': [
80 | 'status',
81 | ],
82 | 'AudioFile': [
83 | 'status',
84 | ],
85 | 'Subset': [
86 | 'name',
87 | ],
88 | }
89 | LOG_M2M_RELATIONS = ['UserGroup_users']
90 |
--------------------------------------------------------------------------------
/geokey/core/context_processors.py:
--------------------------------------------------------------------------------
1 | """Core context processors."""
2 |
3 | from django.conf import settings
4 | from django.contrib.sites.shortcuts import get_current_site
5 |
6 | from geokey import version
7 |
8 |
9 | def project_settings(request):
10 | GOOGLE_ANALYTICS = None
11 |
12 | if hasattr(settings, 'GOOGLE_ANALYTICS'):
13 | GOOGLE_ANALYTICS = settings.GOOGLE_ANALYTICS
14 |
15 | return {
16 | 'DEBUG': settings.DEBUG,
17 | 'PLATFORM_NAME': get_current_site(request).name,
18 | 'GEOKEY_VERSION': version.get_version(),
19 | 'GOOGLE_ANALYTICS': GOOGLE_ANALYTICS
20 | }
21 |
--------------------------------------------------------------------------------
/geokey/core/exceptions.py:
--------------------------------------------------------------------------------
1 | """Core exceptions."""
2 |
3 |
4 | class Unauthenticated(Exception):
5 | """Thrown when user is not authenticated."""
6 |
7 | pass
8 |
9 |
10 | class MalformedRequestData(Exception):
11 | """Thrown when request data is malformed."""
12 |
13 | pass
14 |
15 |
16 | class InputError(Exception):
17 | """Thrown on input error."""
18 |
19 | pass
20 |
21 |
22 | class FileTypeError(Exception):
23 | """Thrown on file type error."""
24 |
25 | pass
26 |
--------------------------------------------------------------------------------
/geokey/core/migrations/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ExCiteS/geokey/53b0bf85ffd30c9e958f028bf9ece5f6ef8d600f/geokey/core/migrations/__init__.py
--------------------------------------------------------------------------------
/geokey/core/mixins.py:
--------------------------------------------------------------------------------
1 | """Core mixins."""
2 |
3 |
4 | class FilterMixin(object):
5 | """A mixin for filter."""
6 |
7 | def remove_filter_field(self, field):
8 | """
9 | Remove a field from the filter.
10 |
11 | Parameters
12 | ----------
13 | field : geokey.categories.models.Field
14 | Represents the field of a category.
15 | """
16 | if self.filters:
17 | category_filter = self.filters.get(str(field.category.id), None)
18 |
19 | if category_filter:
20 | field_filter = category_filter.pop(field.key, None)
21 |
22 | if field_filter:
23 | self.save()
24 |
25 | def save(self, *args, **kwargs):
26 | """Overwrite `save` to implement integrity ensurance."""
27 | self.where_clause = None
28 |
29 | if self.filters is not None:
30 | queries = []
31 |
32 | for key in self.filters:
33 | category = self.project.categories.get(pk=key)
34 | queries.append(category.get_query(self.filters[key]))
35 |
36 | if len(queries) > 0:
37 | query = ' OR '.join(queries)
38 | self.where_clause = query
39 | else:
40 | self.where_clause = 'FALSE'
41 |
42 | super(FilterMixin, self).save(*args, **kwargs)
43 |
--------------------------------------------------------------------------------
/geokey/core/serializers.py:
--------------------------------------------------------------------------------
1 | """Core serializers."""
2 |
3 | from rest_framework import serializers
4 |
5 |
6 | class FieldSelectorSerializer(serializers.ModelSerializer):
7 | """
8 | Field selector serializer.
9 |
10 | Instances accept a `fields` keyword argument to set which fields shall be
11 | serialized.
12 | """
13 |
14 | def __init__(self, *args, **kwargs):
15 | """Initialization."""
16 | # Don't pass the `fields` argument to the superclass
17 | fields = kwargs.pop('fields', None)
18 |
19 | # Instantiate the superclass
20 | super(FieldSelectorSerializer, self).__init__(*args, **kwargs)
21 |
22 | if fields:
23 | # Drop any fields that are not specified in the `fields` argument
24 | allowed = set(fields)
25 | existing = set(self.fields.keys())
26 | for field in existing - allowed:
27 | self.fields.pop(field)
28 |
--------------------------------------------------------------------------------
/geokey/core/settings/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ExCiteS/geokey/53b0bf85ffd30c9e958f028bf9ece5f6ef8d600f/geokey/core/settings/__init__.py
--------------------------------------------------------------------------------
/geokey/core/settings/prod.py:
--------------------------------------------------------------------------------
1 | """Production settings."""
2 |
3 | from .base import *
4 |
5 | # Hosts/domain names that are valid for this site; required if DEBUG is False
6 | # See https://docs.djangoproject.com/en/1.5/ref/settings/#allowed-hosts
7 | ALLOWED_HOSTS = ['*']
8 |
--------------------------------------------------------------------------------
/geokey/core/signals.py:
--------------------------------------------------------------------------------
1 | """Core signals."""
2 |
3 | from django.dispatch import Signal
4 |
5 | delete_project = Signal(providing_args=["project"])
6 |
7 | class RequestAccessorSignal(Signal):
8 | """Request accessor signal."""
9 |
10 | def __init__(self, providing_args=None):
11 | """Initiate the signal."""
12 | return Signal.__init__(self, providing_args)
13 |
14 | def connect(self, receiver, sender=None, weak=True, dispatch_uid=None):
15 | """Connect the signal."""
16 | Signal.connect(self, receiver, sender, weak, dispatch_uid)
17 |
18 |
19 | request_accessor = RequestAccessorSignal()
20 |
21 |
22 | def get_request():
23 | """Get the current request."""
24 | entry = request_accessor.send(None)
25 | if entry:
26 | entry = entry[0]
27 | if entry:
28 | return entry[1]
29 | return None
30 |
--------------------------------------------------------------------------------
/geokey/core/templatetags/__init__.py:
--------------------------------------------------------------------------------
1 | """Custome template tags for GeoKey."""
--------------------------------------------------------------------------------
/geokey/core/templatetags/logger.py:
--------------------------------------------------------------------------------
1 | """Custom GeoKey template tags."""
2 |
3 | from django import template
4 |
5 | register = template.Library()
6 |
7 |
8 | @register.filter()
9 | def check_media_file_type(media_file_class):
10 | """Check media file type and returns in a human-readble format."""
11 | if media_file_class == 'AudioFile':
12 | media_file_type = 'Audio file'
13 | elif media_file_class == 'VideoFile':
14 | media_file_type = 'Video file'
15 | elif media_file_class == 'DocumentFile':
16 | media_file_type = 'Document file'
17 | elif media_file_class == 'ImageFile':
18 | media_file_type = 'Image file'
19 |
20 | return media_file_type
21 |
22 |
23 | @register.filter()
24 | def check_field_type(field_class):
25 | """Check field type and returns in a human-readble format."""
26 | if field_class == 'TextField':
27 | field_type = 'Text field'
28 | elif field_class == 'NumericField':
29 | field_type = 'Numeric field'
30 | elif field_class == 'DateField':
31 | field_type = 'Date field'
32 | elif field_class == 'DateTimeField':
33 | field_type = 'Date & time field'
34 | elif field_class == 'TimeField':
35 | field_type = 'Time field'
36 | elif field_class == 'LookupField':
37 | field_type = 'Select box field'
38 | elif field_class == 'MultipleLookupField':
39 | field_type = 'Multiple select field'
40 |
41 | return field_type
42 |
--------------------------------------------------------------------------------
/geokey/core/tests/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ExCiteS/geokey/53b0bf85ffd30c9e958f028bf9ece5f6ef8d600f/geokey/core/tests/__init__.py
--------------------------------------------------------------------------------
/geokey/core/tests/helpers/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ExCiteS/geokey/53b0bf85ffd30c9e958f028bf9ece5f6ef8d600f/geokey/core/tests/helpers/__init__.py
--------------------------------------------------------------------------------
/geokey/core/tests/helpers/image_helpers.py:
--------------------------------------------------------------------------------
1 | """Core image helpers."""
2 |
3 | from PIL import Image
4 | from io import BytesIO
5 |
6 | from django.core.files.base import ContentFile
7 |
8 |
9 | def get_image(file_name='test.png', width=200, height=200):
10 | image_file = BytesIO()
11 | image = Image.new('RGBA', size=(width, height), color=(255, 0, 255))
12 | image.save(image_file, 'png')
13 | image_file.seek(0)
14 |
15 | the_file = ContentFile(image_file.read(), file_name)
16 | the_file.content_type = 'image/png'
17 |
18 | return the_file
19 |
--------------------------------------------------------------------------------
/geokey/core/tests/helpers/render_helpers.py:
--------------------------------------------------------------------------------
1 | """Core render helpers."""
2 |
3 | from re import sub
4 |
5 |
6 | def remove_csrf(decoded_input):
7 | csrf_regex = r' ]+csrfmiddlewaretoken[^>]+>'
8 | return sub(csrf_regex, '', decoded_input)
9 |
--------------------------------------------------------------------------------
/geokey/core/tests/logger/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ExCiteS/geokey/53b0bf85ffd30c9e958f028bf9ece5f6ef8d600f/geokey/core/tests/logger/__init__.py
--------------------------------------------------------------------------------
/geokey/core/tests/logger/test_log_user.py:
--------------------------------------------------------------------------------
1 | """Tests for logger: model User."""
2 |
3 | from django.test import TestCase
4 |
5 | from geokey.core.models import LoggerHistory
6 | from geokey.users.tests.model_factories import UserFactory
7 |
8 |
9 | class LogUserTest(TestCase):
10 | """Test model User."""
11 |
12 | def setUp(self):
13 | """Set up test."""
14 | self.user = UserFactory.create()
15 |
16 | def test_log_create(self):
17 | """Test when user gets created."""
18 | log_count_init = LoggerHistory.objects.count()
19 | UserFactory.create()
20 | self.assertEqual(LoggerHistory.objects.count(), log_count_init)
21 |
22 | def test_log_update_display_name(self):
23 | """Test when display name changes."""
24 | log_count_init = LoggerHistory.objects.count()
25 | self.user.display_name = '%s UPDATED' % self.user.display_name
26 | self.user.save()
27 | self.assertEqual(LoggerHistory.objects.count(), log_count_init)
28 |
--------------------------------------------------------------------------------
/geokey/core/tests/test_urls.py:
--------------------------------------------------------------------------------
1 | """Tests for URLs."""
2 |
3 | from django.test import TestCase
4 | from django.core.urlresolvers import reverse, resolve
5 |
6 | from geokey.core.views import InfoAPIView
7 |
8 |
9 | class UrlsTest(TestCase):
10 | """Test all URLs."""
11 |
12 | def test_reverse_info(self):
13 | """Test reverser for info API."""
14 | self.assertEqual(reverse('api:info'), '/api/info/')
15 |
16 | def test_resolve_subset_list(self):
17 | """Test resolver for info API."""
18 | resolved = resolve('/api/info/')
19 | self.assertEqual(resolved.func.__name__, InfoAPIView.__name__)
20 |
--------------------------------------------------------------------------------
/geokey/core/url/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ExCiteS/geokey/53b0bf85ffd30c9e958f028bf9ece5f6ef8d600f/geokey/core/url/__init__.py
--------------------------------------------------------------------------------
/geokey/core/urls.py:
--------------------------------------------------------------------------------
1 | """Core URLs."""
2 |
3 | from django.conf import settings
4 | from django.conf.urls import include, url
5 | from django.conf.urls.static import static
6 | from django.views.generic.base import RedirectView
7 |
8 |
9 | urlpatterns = [
10 | url(
11 | r'^oauth2/',
12 | include('oauth2_provider.urls', namespace='oauth2_provider')
13 | ),
14 | url(
15 | r'^admin/',
16 | include('geokey.core.url.admin', namespace='admin')
17 | ),
18 | url(
19 | r'^admin/account/',
20 | include('allauth.urls')
21 | ),
22 | url(
23 | r'^ajax/',
24 | include('geokey.core.url.ajax', namespace='ajax')
25 | ),
26 | url(
27 | r'^api/',
28 | include('geokey.core.url.api', namespace='api')
29 | ),
30 | url(
31 | r'^',
32 | include('geokey.extensions.urls')
33 | ),
34 | url(
35 | r'^$',
36 | RedirectView.as_view(url='/admin/', permanent=True)
37 | ),
38 | ] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
39 |
40 |
41 | if settings.DEBUG and settings.DEBUG_TOOLBAR:
42 | import debug_toolbar
43 | urlpatterns += [
44 | url(r'^debug-toolbar/', include(debug_toolbar.urls)),
45 | ]
46 |
--------------------------------------------------------------------------------
/geokey/extensions/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ExCiteS/geokey/53b0bf85ffd30c9e958f028bf9ece5f6ef8d600f/geokey/extensions/__init__.py
--------------------------------------------------------------------------------
/geokey/extensions/base.py:
--------------------------------------------------------------------------------
1 | """Base for extensions."""
2 |
3 | from geokey.extensions.exceptions import ExtensionExists
4 |
5 |
6 | extensions = {}
7 |
8 |
9 | def register(ext_id, name, display_admin=False, superuser=False, version=None):
10 | """
11 | Register a new extension on the system.
12 |
13 | Parameters
14 | ----------
15 | ext_id : str
16 | Unique identifier for the extension.
17 | name : str
18 | Human readable name of the extension.
19 | display_admin : bool
20 | Indicates if the extension provides pages for the admin interface.
21 | superuser : bool
22 | Indicates if the extentsion is available for superusers only.
23 | version : str
24 | Version of the extension (optional).
25 |
26 | Raises
27 | ------
28 | ExtensionExists
29 | When another extension with the same `ext_id` has already been
30 | registered.
31 | """
32 | if ext_id in extensions.keys():
33 | raise ExtensionExists(
34 | 'An extension with ID %s has already been registered.' % ext_id
35 | )
36 |
37 | extensions[ext_id] = {
38 | 'ext_id': ext_id,
39 | 'name': name,
40 | 'version': version,
41 | 'display_admin': display_admin,
42 | 'superuser': superuser,
43 | 'index_url': ext_id + ':index'
44 | }
45 |
46 |
47 | def deregister(ext_id):
48 | """
49 | Deregister an extension from the system.
50 |
51 | Only to be used for testing.
52 |
53 | Parameters
54 | ----------
55 | ext_id : str
56 | Unique identifier for the extension.
57 | """
58 | extensions.pop(ext_id, None)
59 |
--------------------------------------------------------------------------------
/geokey/extensions/exceptions.py:
--------------------------------------------------------------------------------
1 | """Exceptions for extensions."""
2 |
3 |
4 | class ExtensionExists(BaseException):
5 | """Thrown when extension already exists."""
6 |
7 | pass
8 |
--------------------------------------------------------------------------------
/geokey/extensions/mixins.py:
--------------------------------------------------------------------------------
1 | """Mixins for extensions."""
2 |
3 | from geokey.superusertools.mixins import SuperuserMixin
4 |
5 |
6 | class SuperuserMixin(SuperuserMixin):
7 | """A mixin for superuser."""
8 |
9 | exception_message = 'This extension is for superusers only.'
10 |
--------------------------------------------------------------------------------
/geokey/extensions/tests/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ExCiteS/geokey/53b0bf85ffd30c9e958f028bf9ece5f6ef8d600f/geokey/extensions/tests/__init__.py
--------------------------------------------------------------------------------
/geokey/extensions/tests/test_base.py:
--------------------------------------------------------------------------------
1 | """Tests for base of extensions."""
2 |
3 | from django.test import TestCase
4 |
5 | from geokey.extensions.base import extensions, register, deregister
6 | from geokey.extensions.exceptions import ExtensionExists
7 |
8 |
9 | class RegisterTest(TestCase):
10 | """Test register."""
11 |
12 | def tearDown(self):
13 | """Tear down test."""
14 | deregister(self.ext_id)
15 |
16 | def test_register(self):
17 | """Test registering new extension."""
18 | self.ext_id = 'test_ext'
19 | register(self.ext_id, 'Test', True, True, '1.0.0')
20 |
21 | extension = extensions.get(self.ext_id)
22 | self.assertEqual(extension.get('ext_id'), self.ext_id)
23 | self.assertEqual(extension.get('name'), 'Test')
24 | self.assertEqual(extension.get('version'), '1.0.0')
25 | self.assertTrue(extension.get('display_admin'))
26 | self.assertTrue(extension.get('superuser'))
27 | self.assertEqual(extension.get('index_url'), self.ext_id + ':index')
28 |
29 | def test_register_when_already_exists(self):
30 | """Test registering existing extension."""
31 | self.ext_id = 'test_ext'
32 | extensions[self.ext_id] = {
33 | 'ext_id': self.ext_id,
34 | 'name': 'Test',
35 | 'version': '1.0.0',
36 | 'display_admin': True,
37 | 'superuser': True,
38 | 'index_url': self.ext_id + ':index'
39 | }
40 |
41 | with self.assertRaises(ExtensionExists):
42 | register(self.ext_id, 'Test B', False, False, '1.0.0')
43 |
44 |
45 | class DeregisterTest(TestCase):
46 | """Test deregister."""
47 |
48 | def test_deregister(self):
49 | """Test deregistering existing extension."""
50 | ext_id = 'test_ext'
51 | extensions[ext_id] = {
52 | 'ext_id': ext_id,
53 | 'name': 'Test',
54 | 'version': '1.0.0',
55 | 'display_admin': True,
56 | 'superuser': True,
57 | 'index_url': ext_id + ':index'
58 | }
59 | deregister(ext_id)
60 |
61 | self.assertNotIn(ext_id, extensions)
62 |
--------------------------------------------------------------------------------
/geokey/extensions/tests/test_mixins.py:
--------------------------------------------------------------------------------
1 | """Tests for mixins of extensions."""
2 |
3 | from django.test import TestCase
4 | from django.views.generic import View
5 | from django.views.generic.base import TemplateResponseMixin
6 |
7 | from rest_framework.test import APIRequestFactory
8 |
9 | from geokey.users.tests.model_factories import UserFactory
10 | from geokey.extensions.mixins import SuperuserMixin
11 |
12 |
13 | class ExampleView(SuperuserMixin, TemplateResponseMixin, View):
14 | """Set up example view."""
15 |
16 | template_name = 'base.html'
17 |
18 | def get(self, request):
19 | """Set up GET request."""
20 | return self.render_to_response({
21 | 'country': 'United Kingdom'
22 | })
23 |
24 |
25 | class SuperuserMixinTest(TestCase):
26 | """Test superuser mixin."""
27 |
28 | def setUp(self):
29 | """Set up test."""
30 | self.view = ExampleView.as_view()
31 | self.request = APIRequestFactory().get('http://example.com')
32 |
33 | def test_with_user(self):
34 | """Test with user."""
35 | self.request.user = UserFactory.create(**{'is_superuser': False})
36 | response = self.view(self.request).render()
37 |
38 | self.assertEqual(response.status_code, 200)
39 | self.assertContains(
40 | response,
41 | 'This extension is for superusers only.'
42 | )
43 |
44 | def test_with_superuser(self):
45 | """Test with superuser."""
46 | self.request.user = UserFactory.create(**{'is_superuser': True})
47 | response = self.view(self.request).render()
48 |
49 | self.assertEqual(response.status_code, 200)
50 | self.assertNotContains(
51 | response,
52 | 'This extension is for superusers only.'
53 | )
54 |
--------------------------------------------------------------------------------
/geokey/extensions/urls.py:
--------------------------------------------------------------------------------
1 | """URLs for extensions."""
2 |
3 | from os.path import dirname, isfile, join
4 |
5 | from django.conf.urls import url, include
6 |
7 | from geokey.extensions.base import extensions
8 |
9 |
10 | urlpatterns = []
11 |
12 | for extension in extensions:
13 | if isfile(join(dirname(__import__(extension).__file__), 'urls.py')):
14 | urls = '%s.urls' % extension
15 | urlpatterns.append(url(r'^', include(urls, namespace=extension)))
16 |
--------------------------------------------------------------------------------
/geokey/projects/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ExCiteS/geokey/53b0bf85ffd30c9e958f028bf9ece5f6ef8d600f/geokey/projects/__init__.py
--------------------------------------------------------------------------------
/geokey/projects/base.py:
--------------------------------------------------------------------------------
1 | """Base for projects."""
2 |
3 | from model_utils import Choices
4 |
5 | from django.conf import settings
6 |
7 |
8 | STATUS = Choices('active', 'inactive', 'deleted')
9 | allowed = ("auth", "false", "true")
10 | if hasattr(settings, 'ALLOWED_CONTRIBUTORS'):
11 | allowed = settings.ALLOWED_CONTRIBUTORS
12 | EVERYONE_CONTRIBUTES = Choices(*allowed)
13 |
--------------------------------------------------------------------------------
/geokey/projects/forms.py:
--------------------------------------------------------------------------------
1 | """Forms for projects."""
2 |
3 | from django import forms
4 |
5 | from .models import Project
6 |
7 |
8 | class ProjectCreateForm(forms.ModelForm):
9 | """
10 | Validates the inputs against the model definition.
11 | Used in .views.ProjectAdminCreateView
12 | """
13 | class Meta:
14 | model = Project
15 | fields = ('name', 'description', 'isprivate', 'islocked',
16 | 'everyone_contributes')
17 |
--------------------------------------------------------------------------------
/geokey/projects/migrations/0001_initial.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals
3 |
4 | from django.db import models, migrations
5 | import django.contrib.gis.db.models.fields
6 |
7 |
8 | class Migration(migrations.Migration):
9 |
10 | dependencies = [
11 | ('core', '0001_initial'),
12 | ]
13 |
14 | operations = [
15 | migrations.CreateModel(
16 | name='Admins',
17 | fields=[
18 | ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
19 | ('contact', models.BooleanField(default=True)),
20 | ],
21 | options={
22 | 'ordering': ['project__name'],
23 | },
24 | bases=(models.Model,),
25 | ),
26 | migrations.CreateModel(
27 | name='Project',
28 | fields=[
29 | ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
30 | ('name', models.CharField(max_length=100)),
31 | ('description', models.TextField(null=True, blank=True)),
32 | ('isprivate', models.BooleanField(default=False)),
33 | ('created_at', models.DateTimeField(auto_now_add=True)),
34 | ('everyone_contributes', models.BooleanField(default=True)),
35 | ('status', models.CharField(default=b'active', max_length=20, choices=[(b'active', b'active'), (b'inactive', b'inactive'), (b'deleted', b'deleted')])),
36 | ('geographic_extend', django.contrib.gis.db.models.fields.PolygonField(srid=4326, null=True, geography=True)),
37 | ],
38 | options={
39 | 'ordering': ['name'],
40 | },
41 | bases=(models.Model,),
42 | ),
43 | ]
44 |
--------------------------------------------------------------------------------
/geokey/projects/migrations/0002_auto_20150106_1338.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals
3 |
4 | from django.db import models, migrations
5 | from django.conf import settings
6 |
7 |
8 | class Migration(migrations.Migration):
9 |
10 | dependencies = [
11 | migrations.swappable_dependency(settings.AUTH_USER_MODEL),
12 | ('projects', '0001_initial'),
13 | ]
14 |
15 | operations = [
16 | migrations.AddField(
17 | model_name='project',
18 | name='admins',
19 | field=models.ManyToManyField(related_name='admins', through='projects.Admins', to=settings.AUTH_USER_MODEL),
20 | preserve_default=True,
21 | ),
22 | migrations.AddField(
23 | model_name='project',
24 | name='creator',
25 | field=models.ForeignKey(to=settings.AUTH_USER_MODEL),
26 | preserve_default=True,
27 | ),
28 | migrations.AddField(
29 | model_name='admins',
30 | name='project',
31 | field=models.ForeignKey(related_name='admin_of', to='projects.Project'),
32 | preserve_default=True,
33 | ),
34 | migrations.AddField(
35 | model_name='admins',
36 | name='user',
37 | field=models.ForeignKey(related_name='has_admins', to=settings.AUTH_USER_MODEL),
38 | preserve_default=True,
39 | ),
40 | migrations.AlterUniqueTogether(
41 | name='admins',
42 | unique_together=set([('project', 'user')]),
43 | ),
44 | ]
45 |
--------------------------------------------------------------------------------
/geokey/projects/migrations/0003_auto_20150123_1148.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals
3 |
4 | from django.db import models, migrations
5 |
6 |
7 | class Migration(migrations.Migration):
8 |
9 | dependencies = [
10 | ('projects', '0002_auto_20150106_1338'),
11 | ]
12 |
13 | operations = [
14 | migrations.AlterField(
15 | model_name='project',
16 | name='everyone_contributes',
17 | field=models.CharField(default=b'Auth', max_length=20, choices=[(b'True', b'True'), (b'Auth', b'Auth'), (b'False', b'False')]),
18 | preserve_default=True,
19 | ),
20 | ]
21 |
--------------------------------------------------------------------------------
/geokey/projects/migrations/0004_auto_20150123_1507.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals
3 |
4 | from django.db import models, migrations
5 |
6 |
7 | class Migration(migrations.Migration):
8 |
9 | dependencies = [
10 | ('projects', '0003_auto_20150123_1148'),
11 | ]
12 |
13 | operations = [
14 | migrations.AlterField(
15 | model_name='project',
16 | name='everyone_contributes',
17 | field=models.CharField(default=b'auth', max_length=20, choices=[(b'true', b'true'), (b'auth', b'auth'), (b'false', b'false')]),
18 | preserve_default=True,
19 | ),
20 | ]
21 |
--------------------------------------------------------------------------------
/geokey/projects/migrations/0005_auto_20150202_1041.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals
3 |
4 | from django.db import migrations
5 |
6 |
7 | class Migration(migrations.Migration):
8 |
9 | dependencies = [
10 | ('projects', '0004_auto_20150123_1507'),
11 | ]
12 |
13 | operations = [
14 | migrations.RunSQL("DELETE FROM projects_admins WHERE project_id IN (SELECT id FROM projects_project WHERE status = 'deleted');")
15 | ]
16 |
--------------------------------------------------------------------------------
/geokey/projects/migrations/0006_remove_admins_contact.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals
3 |
4 | from django.db import models, migrations
5 |
6 |
7 | class Migration(migrations.Migration):
8 |
9 | dependencies = [
10 | ('projects', '0005_auto_20150202_1041'),
11 | ]
12 |
13 | operations = [
14 | migrations.RemoveField(
15 | model_name='admins',
16 | name='contact',
17 | ),
18 | ]
19 |
--------------------------------------------------------------------------------
/geokey/projects/migrations/0007_auto_20160122_1409.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals
3 |
4 | from django.db import migrations, models
5 |
6 |
7 | class Migration(migrations.Migration):
8 |
9 | dependencies = [
10 | ('projects', '0006_remove_admins_contact'),
11 | ]
12 |
13 | operations = [
14 | migrations.RenameField(
15 | model_name='project',
16 | old_name='geographic_extend',
17 | new_name='geographic_extent',
18 | ),
19 | migrations.AddField(
20 | model_name='project',
21 | name='islocked',
22 | field=models.BooleanField(default=False),
23 | ),
24 | ]
25 |
--------------------------------------------------------------------------------
/geokey/projects/migrations/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ExCiteS/geokey/53b0bf85ffd30c9e958f028bf9ece5f6ef8d600f/geokey/projects/migrations/__init__.py
--------------------------------------------------------------------------------
/geokey/projects/templatetags/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ExCiteS/geokey/53b0bf85ffd30c9e958f028bf9ece5f6ef8d600f/geokey/projects/templatetags/__init__.py
--------------------------------------------------------------------------------
/geokey/projects/templatetags/count.py:
--------------------------------------------------------------------------------
1 | """Template tags for counting."""
2 |
3 | from django import template
4 |
5 | register = template.Library()
6 |
7 |
8 | @register.simple_tag
9 | def more_link_text(count, singular, plural, minus=5):
10 | return 'Show {more_count} more {label}'.format(
11 | more_count=count-minus,
12 | label=(plural if count-minus != 1 else singular)
13 | )
14 |
--------------------------------------------------------------------------------
/geokey/projects/templatetags/project_attributes.py:
--------------------------------------------------------------------------------
1 | """Template tags for project attributes."""
2 |
3 | from django import template
4 | from django.template.loader import render_to_string
5 |
6 |
7 | register = template.Library()
8 |
9 |
10 | @register.simple_tag
11 | def project_attributes(project):
12 | return render_to_string(
13 | 'projects/project_attributes.html',
14 | {
15 | 'creator': project.creator.display_name,
16 | 'created_at': project.created_at.strftime("%d %B %Y, %H:%M"),
17 | 'private_label': ('Private' if project.isprivate else 'Public'),
18 | 'inactive': project.status == 'inactive'
19 | }
20 | )
21 |
--------------------------------------------------------------------------------
/geokey/projects/tests/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ExCiteS/geokey/53b0bf85ffd30c9e958f028bf9ece5f6ef8d600f/geokey/projects/tests/__init__.py
--------------------------------------------------------------------------------
/geokey/projects/tests/test_serializers.py:
--------------------------------------------------------------------------------
1 | """Tests for serializers of projects."""
2 |
3 | from django.test import TestCase
4 | from django.contrib.auth.models import AnonymousUser
5 |
6 | from geokey.users.tests.model_factories import UserFactory
7 | from geokey.contributions.tests.model_factories import ObservationFactory
8 |
9 | from .model_factories import ProjectFactory
10 | from ..serializers import ProjectSerializer
11 |
12 |
13 | class SerializerTest(TestCase):
14 | def test_get_subsets(self):
15 | project = ProjectFactory.create()
16 | serializer = ProjectSerializer(project)
17 | self.assertIsNotNone(serializer.get_subsets(project))
18 |
19 | def test_get_geographic_extent(self):
20 | project = ProjectFactory.create(**{'geographic_extent': None})
21 | serializer = ProjectSerializer(project)
22 | self.assertIsNone(serializer.get_geographic_extent(project))
23 |
24 | project = ProjectFactory.create()
25 | serializer = ProjectSerializer(project)
26 | self.assertIsNotNone(serializer.get_geographic_extent(project))
27 |
28 | def test_get_user_contributions(self):
29 | user = UserFactory.create()
30 | project = ProjectFactory.create()
31 | ObservationFactory.create_batch(
32 | 5,
33 | **{'creator': user, 'project': project}
34 | )
35 | serializer = ProjectSerializer(project, context={'user': user})
36 | self.assertEqual(5, serializer.get_user_contributions(project))
37 |
38 | serializer = ProjectSerializer(
39 | project, context={'user': AnonymousUser()}
40 | )
41 | self.assertEqual(0, serializer.get_user_contributions(project))
42 |
--------------------------------------------------------------------------------
/geokey/socialinteractions/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ExCiteS/geokey/53b0bf85ffd30c9e958f028bf9ece5f6ef8d600f/geokey/socialinteractions/__init__.py
--------------------------------------------------------------------------------
/geokey/socialinteractions/base.py:
--------------------------------------------------------------------------------
1 | """Base for categories."""
2 |
3 | from model_utils import Choices
4 |
5 | STATUS = Choices('active', 'inactive')
6 |
7 | FREQUENCY = Choices('5min',
8 | '10min',
9 | '20min',
10 | '30min',
11 | 'hourly',
12 | 'daily',
13 | 'weekly',
14 | 'fortnightly',
15 | 'monthly')
16 |
17 | freq_dic = {
18 | '5min': 0.083,
19 | '10min': 0.17,
20 | '20min': 0.33,
21 | '30min': 0.5,
22 | 'hourly': 1,
23 | 'daily': 24,
24 | 'weekly': 168,
25 | 'fortnightly': 336,
26 | 'monthly': 672
27 | }
28 |
--------------------------------------------------------------------------------
/geokey/socialinteractions/migrations/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ExCiteS/geokey/53b0bf85ffd30c9e958f028bf9ece5f6ef8d600f/geokey/socialinteractions/migrations/__init__.py
--------------------------------------------------------------------------------
/geokey/socialinteractions/templatetags/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ExCiteS/geokey/53b0bf85ffd30c9e958f028bf9ece5f6ef8d600f/geokey/socialinteractions/templatetags/__init__.py
--------------------------------------------------------------------------------
/geokey/socialinteractions/templatetags/placeholder_filters.py:
--------------------------------------------------------------------------------
1 | """Custom placeholder template filters"""
2 |
3 | from django import template
4 |
5 | register = template.Library()
6 |
7 |
8 | @register.filter()
9 | def project_replace(value, project_name):
10 | return value.replace('$project$', hashify(project_name))
11 |
12 |
13 | @register.filter()
14 | def hashify(value):
15 | return "#" + value.replace(' ', '').replace('-', '').lower()
16 |
17 |
18 | @register.filter()
19 | def add_link(value, link):
20 | link = '' + link + ' '
21 | value = value.replace("$link$", link)
22 | return value
23 |
--------------------------------------------------------------------------------
/geokey/socialinteractions/tests/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ExCiteS/geokey/53b0bf85ffd30c9e958f028bf9ece5f6ef8d600f/geokey/socialinteractions/tests/__init__.py
--------------------------------------------------------------------------------
/geokey/socialinteractions/tests/model_factories.py:
--------------------------------------------------------------------------------
1 | """Model factories used for tests of socialinteractions."""
2 |
3 | import factory
4 |
5 | from allauth.socialaccount.models import SocialAccount
6 |
7 | from geokey.users.tests.model_factories import UserFactory
8 | from geokey.projects.tests.model_factories import ProjectFactory
9 |
10 | from ..models import SocialInteractionPost, SocialInteractionPull
11 |
12 |
13 | class SocialInteractionFactory(factory.django.DjangoModelFactory):
14 | class Meta:
15 | model = SocialInteractionPost
16 |
17 | creator = factory.SubFactory(UserFactory)
18 | text_to_post = 'Text to post including $link$'
19 | link = 'www.link.com'
20 | project = factory.SubFactory(ProjectFactory)
21 | status = 'active'
22 | socialaccount = SocialAccount()
23 |
24 |
25 | class SocialInteractionPullFactory(factory.django.DjangoModelFactory):
26 | class Meta:
27 | model = SocialInteractionPull
28 |
29 | creator = factory.SubFactory(UserFactory)
30 | text_to_pull = '#Project2'
31 | project = factory.SubFactory(ProjectFactory)
32 | status = 'active'
33 | socialaccount = SocialAccount()
34 | frequency = '5min'
35 |
--------------------------------------------------------------------------------
/geokey/static/img/ajax-loader-blue.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ExCiteS/geokey/53b0bf85ffd30c9e958f028bf9ece5f6ef8d600f/geokey/static/img/ajax-loader-blue.gif
--------------------------------------------------------------------------------
/geokey/static/img/ajax-loader.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ExCiteS/geokey/53b0bf85ffd30c9e958f028bf9ece5f6ef8d600f/geokey/static/img/ajax-loader.gif
--------------------------------------------------------------------------------
/geokey/static/img/blurry.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ExCiteS/geokey/53b0bf85ffd30c9e958f028bf9ece5f6ef8d600f/geokey/static/img/blurry.jpg
--------------------------------------------------------------------------------
/geokey/static/img/play.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ExCiteS/geokey/53b0bf85ffd30c9e958f028bf9ece5f6ef8d600f/geokey/static/img/play.png
--------------------------------------------------------------------------------
/geokey/static/img/providers/facebook.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/geokey/static/img/providers/twitter.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/geokey/static/img/success.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ExCiteS/geokey/53b0bf85ffd30c9e958f028bf9ece5f6ef8d600f/geokey/static/img/success.png
--------------------------------------------------------------------------------
/geokey/static/js/admin.ui.category.display.js:
--------------------------------------------------------------------------------
1 | /* ***********************************************
2 | * Initialises the color picker.
3 | * Initialises the file upload and sets the initial state.
4 | *
5 | * Docs for colorpicker:
6 | * http://mjolnic.com/bootstrap-colorpicker/
7 | *
8 | * Docs for file upload:
9 | * http://plugins.krajee.com/file-input
10 | *
11 | * Used in:
12 | * - templates/categories/category_display.html
13 | * ***********************************************/
14 |
15 | $(function() {
16 | 'use strict';
17 |
18 | // Initialise the color picker
19 | $('#colour').colorpicker({
20 | format: 'hex'
21 | });
22 |
23 | // Initialise file upload for each field
24 | $('input:file').each(function() {
25 | Ui.FileInput.init($(this));
26 | });
27 | });
28 |
--------------------------------------------------------------------------------
/geokey/static/js/admin.ui.field.create.js:
--------------------------------------------------------------------------------
1 | /* ***********************************************
2 | * Based on what is selected as field type, the script shows and hides form
3 | * fields specific to certain field types.
4 | *
5 | * For instance, if you select the type TextField, the inputs for max lenght and
6 | * display as textbox are show. These fields are wrapped in a div with
7 | * id="text", which is shown.
8 | *
9 | * Used in:
10 | * - templates/categories/field_create.html
11 | * ***********************************************/
12 |
13 | (function () {
14 | 'use strict';
15 |
16 | function handleTypeSelect(event) {
17 | // hide all specific inputs
18 | $('.field-special').addClass('hidden');
19 |
20 | // switch on the field type, it shows specific fields accordingly
21 | switch (event.target.value) {
22 | case 'TextField':
23 | $('#text').removeClass('hidden');
24 | break;
25 | case 'NumericField':
26 | $('#minmax').removeClass('hidden');
27 | break;
28 | case 'LookupField':
29 | case 'MultipleLookupField':
30 | $('#lookup').removeClass('hidden');
31 | break;
32 | }
33 | }
34 |
35 | // register the event handler on the select field
36 | $('form select#type').change(handleTypeSelect);
37 | }());
38 |
--------------------------------------------------------------------------------
/geokey/static/js/admin.ui.field.js:
--------------------------------------------------------------------------------
1 | /* ***********************************************
2 | * Module to edit field properties. Is currently only responsible
3 | * for setting minimum and maximum values of numeric fields and initialising
4 | * lookup field edits.
5 | * Is automatically loaded when included in a page.
6 |
7 | * Used in:
8 | * - templates/categories/field_settings.html
9 | * ***********************************************/
10 |
11 | $(function() {
12 | 'use strict';
13 |
14 | var projectId = $('body').attr('data-project-id'),
15 | categoryId = $('body').attr('data-category-id'),
16 | fieldId = $('body').attr('data-field-id'),
17 | url = 'projects/' + projectId + '/categories/' + categoryId + '/fields/' + fieldId;
18 |
19 | // Initialize the lookup panel functionality if the field is a lookup
20 | if ($('#lookupValuesPanel').length !== 0) {
21 | new Ui.LookupPanel('#lookupValuesPanel', url);
22 |
23 | // Initialise file upload for each field
24 | $('input:file').each(function() {
25 | Ui.FileInput.init($(this));
26 | });
27 | }
28 |
29 | // Set the min and maximum values for numeric fields, so they can be
30 | // validated
31 | function handleNumericFieldEdit(event) {
32 | var target = $(event.target);
33 |
34 | if (target.attr('id') === 'minval') {
35 | // set the current minval as minimum value for maxval field
36 | $('form input#maxval').attr('min', target.val());
37 | } else if (target.attr('id') === 'maxval') {
38 | // set the current maxval as minimum value for minval field
39 | $('form input#minval').attr('max', target.val());
40 | }
41 | }
42 |
43 | $('form input[type="number"]').change(handleNumericFieldEdit);
44 | });
45 |
--------------------------------------------------------------------------------
/geokey/static/js/admin.ui.fileinput.js:
--------------------------------------------------------------------------------
1 | /* ***********************************************
2 | * Initialises the file input functionality for
3 | * input field.
4 | *
5 | * Used in:
6 | * - templates/categories/category_display.html
7 | * - templates/categories/field_settings.html
8 | * ***********************************************/
9 |
10 | $(function(global) {
11 | 'use strict';
12 |
13 | function FileInput() {}
14 |
15 | FileInput.prototype.init = function(field, additionalSettings) {
16 | var settings = {
17 | showUpload: false,
18 | showCancel: false,
19 | browseLabel: 'Browse...',
20 | msgLoading: 'Loading file {index} of {files}...'
21 | };
22 |
23 | for (var key in additionalSettings) {
24 | settings[key] = additionalSettings[key];
25 | }
26 |
27 | if (field.attr('data-preview')) {
28 | settings.initialPreview = ' ';
29 | }
30 |
31 | field.fileinput(settings);
32 | field.parents().find('div.fileinput-remove').hide();
33 |
34 | field.on('fileclear', function() {
35 | $('input#' + $(this).data('target') + '-clear').val('true');
36 | });
37 | };
38 |
39 | global.FileInput = new FileInput();
40 | }(window.Ui ? window.Ui : window.Ui = {}));
41 |
--------------------------------------------------------------------------------
/geokey/static/js/admin.ui.project.js:
--------------------------------------------------------------------------------
1 | /* ***********************************************
2 | * Changes the display of radio buttons for
3 | * contributing permissions on a project.
4 | *
5 | * Used in:
6 | * - projects/project_create.html
7 | * ***********************************************/
8 |
9 | $(function() {
10 | 'use strict';
11 |
12 | $('input[name="isprivate"]').change(function(event) {
13 | if ($(event.target).attr('id') === 'public') {
14 | $('.public').removeClass('hidden');
15 | $('.private').addClass('hidden');
16 | } else if ($(event.target).attr('id') === 'private') {
17 | $('.public').addClass('hidden');
18 | $('.private').removeClass('hidden');
19 | }
20 | });
21 | });
22 |
--------------------------------------------------------------------------------
/geokey/static/js/admin.ui.socialinteractions.twittervalidator.js:
--------------------------------------------------------------------------------
1 | /* ***********************************************
2 | * Indicates to user how many characters are still
3 | * left in the post to Twitter
4 | *
5 | * if selected #socialaccount is twitter:
6 | * #remaining_characters are calculated based on fields: #text_post & #text_link
7 | * maxlength attribute in #text_post is dynamically updated
8 | * else #characters is hidden
9 | *
10 | * Used in:
11 | * - templates/socialinteractions/socialinteraction_post_create.html
12 | * - templates/socialinteractions/socialinteraction_post_settings.html
13 | *
14 | * ***********************************************/
15 |
16 | if ($("#socialaccount option:selected").text().match("¦¦ twitter$")) {
17 | $("#text_post").on('input', function () {
18 | update_length()
19 | }).trigger('input')
20 |
21 | $("#text_link").on('input', function () {
22 | update_length()
23 | }).trigger('input')
24 |
25 | function update_length() {
26 | if (/\$link\$/i.test($("#text_post").val())) {
27 | post_length = $("#text_post").val().length - "\$link\$".length
28 | url_length = $('#text_link').val().length
29 | if (/\$project_id\$/i.test($('#text_link').val()))
30 | url_length = url_length - "\$project_id\$".length + $('body').data('project-id').toString().length
31 | if (/\$contribution_id\$/i.test($('#text_link').val()))
32 | url_length = url_length - "\$contribution_id\$".length + $('body').data('contributions-count').toString().length + 1
33 | } else {
34 | post_length = $("#text_post").val().length
35 | url_length = 0
36 | }
37 | var remaining = 280 - post_length - url_length
38 | $('#remaining_characters').text(remaining)
39 | $('#text_post').attr('maxlength', $("#text_post").val().length + remaining)
40 | }
41 |
42 | }
43 |
44 | else {
45 | $('#characters').hide()
46 | }
47 |
--------------------------------------------------------------------------------
/geokey/static/js/admin.ui.usergroup.permissions.js:
--------------------------------------------------------------------------------
1 | /* ***********************************************
2 | * Based on changes to input[name="permission"}, the script displays (or hides)
3 | * a message that specific settings will be overwritten by project settings,
4 | * i.e. when all users can contribute to the project.
5 | *
6 | * Used in:
7 | * - templates/users/usergroup_permissions.html
8 | * ***********************************************/
9 |
10 | (function() {
11 | var projectId = $('body').attr('data-project-id');
12 | var projectPrivate = $('body').attr('data-project-private');
13 | var everyoneContributes = $('body').attr('data-project-everyone-contributes');
14 |
15 | function handlePermissionChange(event) {
16 | if ($(this).val() === 'read_only' && everyoneContributes !== 'false') {
17 | var add = '';
18 | if (projectPrivate !== 'True' && everyoneContributes === 'auth') {
19 | add = ', who have access to this project,';
20 | }
21 | $('form#permissions').before('
Currently, all users' + add + ' can contribute to the project. This setting overwrites permissions of individual user groups. If you plan to restrict contributing permissions to certain user groups, head to
project settings first and change the project permissions.
');
22 | } else {
23 | $('.hint').remove();
24 | }
25 | }
26 |
27 | $('form#permissions input[name="permission"]').change(handlePermissionChange);
28 | }());
29 |
--------------------------------------------------------------------------------
/geokey/static/lib/bootstrap-colorpicker/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright 2012 Stefan Petre
2 |
3 | Licensed under the Apache License, Version 2.0 (the "License");
4 | you may not use this file except in compliance with the License.
5 | You may obtain a copy of the License at
6 |
7 | http://www.apache.org/licenses/LICENSE-2.0
8 |
9 | Unless required by applicable law or agreed to in writing, software
10 | distributed under the License is distributed on an "AS IS" BASIS,
11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | See the License for the specific language governing permissions and
13 | limitations under the License.
14 |
--------------------------------------------------------------------------------
/geokey/static/lib/bootstrap-colorpicker/img/bootstrap-colorpicker/alpha-horizontal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ExCiteS/geokey/53b0bf85ffd30c9e958f028bf9ece5f6ef8d600f/geokey/static/lib/bootstrap-colorpicker/img/bootstrap-colorpicker/alpha-horizontal.png
--------------------------------------------------------------------------------
/geokey/static/lib/bootstrap-colorpicker/img/bootstrap-colorpicker/alpha.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ExCiteS/geokey/53b0bf85ffd30c9e958f028bf9ece5f6ef8d600f/geokey/static/lib/bootstrap-colorpicker/img/bootstrap-colorpicker/alpha.png
--------------------------------------------------------------------------------
/geokey/static/lib/bootstrap-colorpicker/img/bootstrap-colorpicker/hue-horizontal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ExCiteS/geokey/53b0bf85ffd30c9e958f028bf9ece5f6ef8d600f/geokey/static/lib/bootstrap-colorpicker/img/bootstrap-colorpicker/hue-horizontal.png
--------------------------------------------------------------------------------
/geokey/static/lib/bootstrap-colorpicker/img/bootstrap-colorpicker/hue.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ExCiteS/geokey/53b0bf85ffd30c9e958f028bf9ece5f6ef8d600f/geokey/static/lib/bootstrap-colorpicker/img/bootstrap-colorpicker/hue.png
--------------------------------------------------------------------------------
/geokey/static/lib/bootstrap-colorpicker/img/bootstrap-colorpicker/saturation.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ExCiteS/geokey/53b0bf85ffd30c9e958f028bf9ece5f6ef8d600f/geokey/static/lib/bootstrap-colorpicker/img/bootstrap-colorpicker/saturation.png
--------------------------------------------------------------------------------
/geokey/static/lib/bootstrap-datetimepicker/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 Jonathan Peterson (@Eonasdan)
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 |
--------------------------------------------------------------------------------
/geokey/static/lib/bootstrap-fileinput/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2014 - 2016, Kartik Visweswaran
2 | Krajee.com
3 | All rights reserved.
4 |
5 | Redistribution and use in source and binary forms, with or without modification,
6 | are permitted provided that the following conditions are met:
7 |
8 | * Redistributions of source code must retain the above copyright notice, this
9 | list of conditions and the following disclaimer.
10 |
11 | * Redistributions in binary form must reproduce the above copyright notice, this
12 | list of conditions and the following disclaimer in the documentation and/or
13 | other materials provided with the distribution.
14 |
15 | * Neither the names of Kartik Visweswaran or Krajee nor the names of its
16 | contributors may be used to endorse or promote products derived from
17 | this software without specific prior written permission.
18 |
19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
20 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
23 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
26 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 |
--------------------------------------------------------------------------------
/geokey/static/lib/bootstrap-fileinput/img/loading-sm.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ExCiteS/geokey/53b0bf85ffd30c9e958f028bf9ece5f6ef8d600f/geokey/static/lib/bootstrap-fileinput/img/loading-sm.gif
--------------------------------------------------------------------------------
/geokey/static/lib/bootstrap-fileinput/img/loading.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ExCiteS/geokey/53b0bf85ffd30c9e958f028bf9ece5f6ef8d600f/geokey/static/lib/bootstrap-fileinput/img/loading.gif
--------------------------------------------------------------------------------
/geokey/static/lib/bootstrap/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2011-2016 Twitter, Inc.
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
13 | all 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
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/geokey/static/lib/bootstrap/fonts/glyphicons-halflings-regular.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ExCiteS/geokey/53b0bf85ffd30c9e958f028bf9ece5f6ef8d600f/geokey/static/lib/bootstrap/fonts/glyphicons-halflings-regular.eot
--------------------------------------------------------------------------------
/geokey/static/lib/bootstrap/fonts/glyphicons-halflings-regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ExCiteS/geokey/53b0bf85ffd30c9e958f028bf9ece5f6ef8d600f/geokey/static/lib/bootstrap/fonts/glyphicons-halflings-regular.ttf
--------------------------------------------------------------------------------
/geokey/static/lib/bootstrap/fonts/glyphicons-halflings-regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ExCiteS/geokey/53b0bf85ffd30c9e958f028bf9ece5f6ef8d600f/geokey/static/lib/bootstrap/fonts/glyphicons-halflings-regular.woff
--------------------------------------------------------------------------------
/geokey/static/lib/bootstrap/fonts/glyphicons-halflings-regular.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ExCiteS/geokey/53b0bf85ffd30c9e958f028bf9ece5f6ef8d600f/geokey/static/lib/bootstrap/fonts/glyphicons-halflings-regular.woff2
--------------------------------------------------------------------------------
/geokey/static/lib/handlebars/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (C) 2011-2016 by Yehuda Katz
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 |
--------------------------------------------------------------------------------
/geokey/static/lib/jquery/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright jQuery Foundation and other contributors, https://jquery.org/
2 |
3 | This software consists of voluntary contributions made by many
4 | individuals. For exact contribution history, see the revision history
5 | available at https://github.com/jquery/jquery
6 |
7 | The following license applies to all parts of this software except as
8 | documented below:
9 |
10 | ====
11 |
12 | Permission is hereby granted, free of charge, to any person obtaining
13 | a copy of this software and associated documentation files (the
14 | "Software"), to deal in the Software without restriction, including
15 | without limitation the rights to use, copy, modify, merge, publish,
16 | distribute, sublicense, and/or sell copies of the Software, and to
17 | permit persons to whom the Software is furnished to do so, subject to
18 | the following conditions:
19 |
20 | The above copyright notice and this permission notice shall be
21 | included in all copies or substantial portions of the Software.
22 |
23 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 |
31 | ====
32 |
33 | All files located in the node_modules and external directories are
34 | externally maintained libraries used by this software which have their
35 | own licenses; we recommend you read them, as their terms may differ from
36 | the terms above.
37 |
--------------------------------------------------------------------------------
/geokey/static/lib/modernizr/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (C) 2012 by Modernizr (http://modernizr.com)
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 |
--------------------------------------------------------------------------------
/geokey/static/lib/moment/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2011-2016 Tim Wood, Iskren Chernev, Moment.js contributors
2 |
3 | Permission is hereby granted, free of charge, to any person
4 | obtaining a copy of this software and associated documentation
5 | files (the "Software"), to deal in the Software without
6 | restriction, including without limitation the rights to use,
7 | copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | copies of the Software, and to permit persons to whom the
9 | Software is furnished to do so, subject to the following
10 | conditions:
11 |
12 | The above copyright notice and this permission notice shall be
13 | included in all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
17 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 | OTHER DEALINGS IN THE SOFTWARE.
23 |
--------------------------------------------------------------------------------
/geokey/subsets/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ExCiteS/geokey/53b0bf85ffd30c9e958f028bf9ece5f6ef8d600f/geokey/subsets/__init__.py
--------------------------------------------------------------------------------
/geokey/subsets/migrations/0001_initial.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals
3 |
4 | from django.db import models, migrations
5 | try:
6 | from django.contrib.postgres.fields import JSONField
7 | except ImportError:
8 | from django_pgjson.fields import JsonBField as JSONField
9 | from django.conf import settings
10 | import geokey.core.mixins
11 |
12 |
13 | class Migration(migrations.Migration):
14 |
15 | dependencies = [
16 | ('projects', '0005_auto_20150202_1041'),
17 | migrations.swappable_dependency(settings.AUTH_USER_MODEL),
18 | ]
19 |
20 | operations = [
21 | migrations.CreateModel(
22 | name='Subset',
23 | fields=[
24 | ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
25 | ('name', models.CharField(max_length=100)),
26 | ('description', models.TextField(null=True, blank=True)),
27 | ('created_at', models.DateTimeField(auto_now_add=True)),
28 | ('filters', JSONField(null=True, blank=True)),
29 | ('where_clause', models.TextField(null=True, blank=True)),
30 | ('creator', models.ForeignKey(to=settings.AUTH_USER_MODEL)),
31 | ('project', models.ForeignKey(related_name='subsets', to='projects.Project')),
32 | ],
33 | options={
34 | },
35 | bases=(geokey.core.mixins.FilterMixin, models.Model),
36 | ),
37 | ]
38 |
--------------------------------------------------------------------------------
/geokey/subsets/migrations/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ExCiteS/geokey/53b0bf85ffd30c9e958f028bf9ece5f6ef8d600f/geokey/subsets/migrations/__init__.py
--------------------------------------------------------------------------------
/geokey/subsets/models.py:
--------------------------------------------------------------------------------
1 | """Models for subsets."""
2 |
3 | from django.conf import settings
4 | from django.db import models
5 |
6 | try:
7 | from django.contrib.postgres.fields import JSONField
8 | except ImportError:
9 | from django_pgjson.fields import JsonBField as JSONField
10 | from simple_history.models import HistoricalRecords
11 |
12 |
13 | from geokey.core.mixins import FilterMixin
14 |
15 |
16 | class Subset(FilterMixin, models.Model):
17 | """Stores a single subset."""
18 |
19 | name = models.CharField(max_length=100)
20 | description = models.TextField(blank=True, null=True)
21 | created_at = models.DateTimeField(auto_now_add=True)
22 | creator = models.ForeignKey(settings.AUTH_USER_MODEL)
23 | project = models.ForeignKey('projects.Project', related_name='subsets')
24 | filters = JSONField(blank=True, null=True)
25 | where_clause = models.TextField(blank=True, null=True)
26 | history = HistoricalRecords()
27 |
--------------------------------------------------------------------------------
/geokey/subsets/serializers.py:
--------------------------------------------------------------------------------
1 | """Serializers for subsets."""
2 |
3 | from rest_framework.serializers import ModelSerializer
4 |
5 | from geokey.subsets.models import Subset
6 |
7 |
8 | class SubsetSerializer(ModelSerializer):
9 | """Serializer for a subset."""
10 |
11 | class Meta:
12 | """Serializer meta."""
13 |
14 | model = Subset
15 | depth = 1
16 | fields = ('id', 'name', 'description', 'created_at')
17 |
--------------------------------------------------------------------------------
/geokey/subsets/tests/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ExCiteS/geokey/53b0bf85ffd30c9e958f028bf9ece5f6ef8d600f/geokey/subsets/tests/__init__.py
--------------------------------------------------------------------------------
/geokey/subsets/tests/model_factories.py:
--------------------------------------------------------------------------------
1 | """Model factories used for tests of subsets."""
2 |
3 | import factory
4 |
5 | from geokey.users.tests.model_factories import UserFactory
6 | from geokey.projects.tests.model_factories import ProjectFactory
7 |
8 | from ..models import Subset
9 |
10 |
11 | class SubsetFactory(factory.django.DjangoModelFactory):
12 | class Meta:
13 | model = Subset
14 |
15 | name = factory.Sequence(lambda n: 'project %d' % n)
16 | description = factory.LazyAttribute(lambda o: '%s description' % o.name)
17 | creator = factory.SubFactory(UserFactory)
18 | project = factory.SubFactory(ProjectFactory)
19 |
--------------------------------------------------------------------------------
/geokey/superusertools/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ExCiteS/geokey/53b0bf85ffd30c9e958f028bf9ece5f6ef8d600f/geokey/superusertools/__init__.py
--------------------------------------------------------------------------------
/geokey/superusertools/base.py:
--------------------------------------------------------------------------------
1 | """Base for superuser tools."""
2 |
3 | from rest_framework.permissions import BasePermission
4 |
5 |
6 | class IsSuperuser(BasePermission):
7 | """A permission to check if user is a superuser."""
8 |
9 | def has_permission(self, request, view):
10 | """
11 | Check if user is a superuser.
12 |
13 | Parameters
14 | ----------
15 | request : rest_framework.request.Request
16 | Object representing the request.
17 | view : rest_framework.views.APIView
18 | View that called the permission.
19 |
20 | Returns
21 | -------
22 | Boolean
23 | Indicating if user is a superuser.
24 | """
25 | return request.user and request.user.is_superuser
26 |
--------------------------------------------------------------------------------
/geokey/superusertools/mixins.py:
--------------------------------------------------------------------------------
1 | """Mixins for superuser tools."""
2 |
3 |
4 | class SuperuserMixin(object):
5 | """A mixin for superuser."""
6 |
7 | exception_message = 'No rights to access superuser tools.'
8 |
9 | def dispatch(self, request, *args, **kwargs):
10 | """
11 | Dispatch the request.
12 |
13 | Check if user is a superuser, display an error message if not.
14 |
15 | Parameters
16 | ----------
17 | request : django.http.HttpRequest
18 | Object representing the request.
19 |
20 | Returns
21 | -------
22 | django.http.HttpResponse
23 | """
24 | if not request.user.is_superuser:
25 | return self.render_to_response({
26 | 'error': 'Permission denied.',
27 | 'error_description': self.exception_message
28 | })
29 |
30 | return super(SuperuserMixin, self).dispatch(request, *args, **kwargs)
31 |
--------------------------------------------------------------------------------
/geokey/superusertools/tests/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ExCiteS/geokey/53b0bf85ffd30c9e958f028bf9ece5f6ef8d600f/geokey/superusertools/tests/__init__.py
--------------------------------------------------------------------------------
/geokey/templates/account/account_inactive.html:
--------------------------------------------------------------------------------
1 | {% extends 'base.html' %}
2 | {% block title %} | Inactive account{% endblock %}
3 |
4 | {% block main %}
5 |
10 |
11 |
12 | {% include 'snippets/messages.html' %}
13 |
14 |
15 |
Your account is inactive; likely because you have not confirmed your email address yet. We've emailed you new instructions for verifying your email address. Follow the link provided to activate your account. If you don't receive an email, please make sure you've checked your spam folder.
16 |
17 |
18 | {% endblock %}
19 |
--------------------------------------------------------------------------------
/geokey/templates/account/email/email_confirmation_message.txt:
--------------------------------------------------------------------------------
1 | Dear {{ user.display_name }},
2 |
3 | {% load account %}{% user_display user as user_display %}{% load i18n %}{% autoescape off %}{% blocktrans with site_name=current_site.name %}User {{ user_display }} at {{ site_name }} has given this as an email address.
4 |
5 | To confirm this is correct, go to {{ activate_url }}
6 | {% endblocktrans %}{% endautoescape %}
7 |
--------------------------------------------------------------------------------
/geokey/templates/account/email/email_confirmation_signup_message.txt:
--------------------------------------------------------------------------------
1 | {% include "account/email/email_confirmation_message.txt" %}
2 |
--------------------------------------------------------------------------------
/geokey/templates/account/email/email_confirmation_signup_subject.txt:
--------------------------------------------------------------------------------
1 | {% include "account/email/email_confirmation_subject.txt" %}
2 |
--------------------------------------------------------------------------------
/geokey/templates/account/email/email_confirmation_subject.txt:
--------------------------------------------------------------------------------
1 | {% load i18n %}
2 | {% autoescape off %}
3 | {% blocktrans %}Confirm E-mail Address{% endblocktrans %}
4 | {% endautoescape %}
5 |
--------------------------------------------------------------------------------
/geokey/templates/account/email/password_reset_key_message.txt:
--------------------------------------------------------------------------------
1 | Dear {{ user.display_name }},
2 |
3 | {% load i18n %}{% blocktrans with site_domain=current_site.domain %}You're receiving this e-mail because you or someone else has requested a password for your user account at {{site_domain}}.
4 | It can be safely ignored if you did not request a password reset. Click the link below to reset your password.{% endblocktrans %}
5 |
6 | {{ password_reset_url }}
7 |
8 | {% if username %}{% blocktrans %}In case you forgot, your username is {{ username }}.{% endblocktrans %}
9 |
10 | {% endif %}{% blocktrans with site_name=current_site.name %}Thanks for using {{site_name}}!{% endblocktrans %}
11 |
--------------------------------------------------------------------------------
/geokey/templates/account/email/password_reset_key_subject.txt:
--------------------------------------------------------------------------------
1 | {% load i18n %}
2 | {% autoescape off %}
3 | {% blocktrans %}Password Reset E-mail{% endblocktrans %}
4 | {% endautoescape %}
5 |
--------------------------------------------------------------------------------
/geokey/templates/account/email_confirm.html:
--------------------------------------------------------------------------------
1 | {% extends 'base.html' %}
2 | {% block title %} | Confirm email address{% endblock %}
3 |
4 | {% block main %}
5 |
10 |
11 |
12 | {% include 'snippets/messages.html' %}
13 |
14 |
15 |
The email confirmation link was invalid, possibly because it has already expired. Please request a new email confirmation .
16 |
17 |
18 | {% endblock %}
19 |
--------------------------------------------------------------------------------
/geokey/templates/account/password_reset.html:
--------------------------------------------------------------------------------
1 | {% extends 'base.html' %}
2 | {% block title %} | Reset password{% endblock %}
3 |
4 | {% block main %}
5 |
10 |
11 |
12 | {% include 'snippets/messages.html' %}
13 |
14 |
31 |
32 | {% endblock %}
33 |
34 | {% block libraries %}
35 |
36 | {% endblock %}
37 |
--------------------------------------------------------------------------------
/geokey/templates/account/password_reset_done.html:
--------------------------------------------------------------------------------
1 | {% extends 'base.html' %}
2 | {% block title %} | Reset password successful{% endblock %}
3 |
4 | {% block main %}
5 |
10 |
11 |
12 | {% include 'snippets/messages.html' %}
13 |
14 |
15 |
We've emailed you instructions for resetting your password. You should be receiving them shortly. If you don't receive an email, please make sure you've entered the address you registered with, and check your spam folder.
16 |
17 |
18 | {% endblock %}
19 |
--------------------------------------------------------------------------------
/geokey/templates/account/password_reset_from_key_done.html:
--------------------------------------------------------------------------------
1 | {% extends 'base.html' %}
2 | {% block title %} | Set new password successful{% endblock %}
3 |
4 | {% block main %}
5 |
10 |
11 |
12 | {% include 'snippets/messages.html' %}
13 |
14 |
15 |
Your new password has been set. You may go ahead and sign in now.
16 |
17 |
18 | {% endblock %}
19 |
--------------------------------------------------------------------------------
/geokey/templates/account/verification_sent.html:
--------------------------------------------------------------------------------
1 | {% extends 'base.html' %}
2 | {% block title %} | Verify email address{% endblock %}
3 |
4 | {% block main %}
5 |
10 |
11 |
12 | {% include 'snippets/messages.html' %}
13 |
14 |
15 |
We've emailed you instructions for verifying your email address. You should be receiving them shortly. Follow the link provided to finalise the sign up process. If you don't receive an email, please make sure you've checked your spam folder.
16 |
17 |
18 | {% endblock %}
19 |
--------------------------------------------------------------------------------
/geokey/templates/categories/category_navigation.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
Category
4 |
5 |
6 | {% if project.islocked %} {% endif %}
7 | {{ category.name }}
8 |
9 |
10 |
11 |
16 |
17 |
--------------------------------------------------------------------------------
/geokey/templates/geometries/placemarks.kml:
--------------------------------------------------------------------------------
1 | {% extends 'gis/kml/base.kml' %}
2 | {% load kml_tags %}
3 |
4 | {% block placemarks %}
5 | {% for place in data %}
6 |
7 | {{ place|kml_name }}
8 | {{ place|kml_desc|safe }}
9 | {{ place|kml_geom|safe }}
10 | {{ place|kml_style }}
11 |
12 | {% endfor %}
13 | {% endblock %}
14 |
--------------------------------------------------------------------------------
/geokey/templates/handlebars/_created-field.hbs:
--------------------------------------------------------------------------------
1 | ×
2 | The contribution has been created
3 |
4 |
10 |
16 |
--------------------------------------------------------------------------------
/geokey/templates/handlebars/_datefield.hbs:
--------------------------------------------------------------------------------
1 |
7 |
13 |
--------------------------------------------------------------------------------
/geokey/templates/handlebars/_datetimefield.hbs:
--------------------------------------------------------------------------------
1 |
7 |
13 |
--------------------------------------------------------------------------------
/geokey/templates/handlebars/_lookupfield.hbs:
--------------------------------------------------------------------------------
1 |
11 |
--------------------------------------------------------------------------------
/geokey/templates/handlebars/_multiplelookupfield.hbs:
--------------------------------------------------------------------------------
1 |
11 |
--------------------------------------------------------------------------------
/geokey/templates/handlebars/_numericfield.hbs:
--------------------------------------------------------------------------------
1 |
7 |
8 |
14 |
--------------------------------------------------------------------------------
/geokey/templates/handlebars/_textfield.hbs:
--------------------------------------------------------------------------------
1 |
7 |
--------------------------------------------------------------------------------
/geokey/templates/handlebars/_timefield.hbs:
--------------------------------------------------------------------------------
1 |
7 |
13 |
--------------------------------------------------------------------------------
/geokey/templates/handlebars/createdfield.hbs:
--------------------------------------------------------------------------------
1 |
2 | {{> created-field}}
3 |
4 |
--------------------------------------------------------------------------------
/geokey/templates/handlebars/field.hbs:
--------------------------------------------------------------------------------
1 |
2 | ×
3 |
{{name}} ({{key}})
4 |
5 | {{#ifCond fieldtype 'TextField'}}
6 | {{> textfield}}
7 | {{/ifCond}}
8 | {{#ifCond fieldtype 'NumericField'}}
9 | {{> numericfield}}
10 | {{/ifCond}}
11 | {{#ifCond fieldtype 'DateTimeField'}}
12 | {{> datetimefield}}
13 | {{/ifCond}}
14 | {{#ifCond fieldtype 'DateField'}}
15 | {{> datefield}}
16 | {{/ifCond}}
17 | {{#ifCond fieldtype 'TimeField'}}
18 | {{> timefield}}
19 | {{/ifCond}}
20 | {{#ifCond fieldtype 'LookupField'}}
21 | {{> lookupfield}}
22 | {{/ifCond}}
23 | {{#ifCond fieldtype 'MultipleLookupField'}}
24 | {{> multiplelookupfield}}
25 | {{/ifCond}}
26 |
27 |
--------------------------------------------------------------------------------
/geokey/templates/handlebars/fields.hbs:
--------------------------------------------------------------------------------
1 |
2 | {{> created-field}}
3 |
4 | {{#each fields}}
5 |
6 | {{#ifCond fieldtype 'TextField'}}
7 | {{> textfield}}
8 | {{/ifCond}}
9 | {{#ifCond fieldtype 'NumericField'}}
10 | {{> numericfield}}
11 | {{/ifCond}}
12 | {{#ifCond fieldtype 'DateTimeField'}}
13 | {{> datetimefield}}
14 | {{/ifCond}}
15 | {{#ifCond fieldtype 'DateField'}}
16 | {{> datefield}}
17 | {{/ifCond}}
18 | {{#ifCond fieldtype 'TimeField'}}
19 | {{> timefield}}
20 | {{/ifCond}}
21 | {{#ifCond fieldtype 'LookupField'}}
22 | {{> lookupfield}}
23 | {{/ifCond}}
24 | {{#ifCond fieldtype 'MultipleLookupField'}}
25 | {{> multiplelookupfield}}
26 | {{/ifCond}}
27 |
28 | {{/each}}
29 |
--------------------------------------------------------------------------------
/geokey/templates/handlebars/fieldselect.hbs:
--------------------------------------------------------------------------------
1 |
2 |
3 | Select filter field
4 | Date created
5 | {{#each fields}}
6 | {{name}} ({{key}})
7 | {{/each}}
8 |
9 |
10 |
--------------------------------------------------------------------------------
/geokey/templates/handlebars/helpers.js:
--------------------------------------------------------------------------------
1 | Handlebars.registerHelper('value', function(feature, field) {
2 | var value = (feature.properties[field.key] ? feature.properties[field.key] : '—');
3 |
4 | switch (field.fieldtype) {
5 | case 'LookupField':
6 | for (var j = 0, lenj = field.lookupvalues.length; j < lenj; j++) {
7 | if (field.lookupvalues[j].id === value) {
8 | value = field.lookupvalues[j].name;
9 | break;
10 | }
11 | }
12 | break;
13 | case 'DateTimeField':
14 | value = moment(value).fromNow() + ' ('+ moment(value).format('llll') +')';
15 | break;
16 | }
17 | return value;
18 | });
19 |
20 | Handlebars.registerHelper('ifCond', function(v1, v2, options) {
21 | if(v1 === v2) {
22 | return options.fn(this);
23 | }
24 | return options.inverse(this);
25 | });
--------------------------------------------------------------------------------
/geokey/templates/handlebars/usergroupusers.hbs:
--------------------------------------------------------------------------------
1 | {{#each users}}
2 | {{ display_name }} remove
3 | {{/each}}
--------------------------------------------------------------------------------
/geokey/templates/handlebars/userstypeaway.hbs:
--------------------------------------------------------------------------------
1 | {{#each this}}
2 | {{ display_name }}
3 | {{/each}}
--------------------------------------------------------------------------------
/geokey/templates/oauth2_provider/authorize.html:
--------------------------------------------------------------------------------
1 | {% extends 'base.html' %}
2 |
3 | {% block title %} | Authorise application{% endblock %}
4 |
5 | {% block main %}
6 |
11 |
12 |
39 | {% endblock %}
40 |
--------------------------------------------------------------------------------
/geokey/templates/projects/navigation.html:
--------------------------------------------------------------------------------
1 |
35 |
--------------------------------------------------------------------------------
/geokey/templates/projects/project_attributes.html:
--------------------------------------------------------------------------------
1 |
2 | {{ private_label }}
3 | {% if inactive %}Archived {% endif %}
4 |
5 |
6 | Created by {{ creator }} on {{ created_at }}
7 |
--------------------------------------------------------------------------------
/geokey/templates/projects/projects_involved.html:
--------------------------------------------------------------------------------
1 | {% extends 'base.html' %}
2 |
3 | {% block title %} | Other projects{% endblock %}
4 |
5 | {% block main %}
6 |
11 |
12 |
13 | {% include 'snippets/messages.html' %}
14 |
15 | {% for project in projects %}
16 |
17 |
18 |
{{ project.name }}
19 |
{{ project.role }}
20 |
21 |
22 |
23 | {{ project.contributions }}
24 | contributions
25 |
26 |
27 | {% empty %}
28 |
29 |
30 |
No projects found.
31 |
32 |
33 | {% endfor %}
34 |
35 | {% endblock %}
36 |
--------------------------------------------------------------------------------
/geokey/templates/snippets/error.html:
--------------------------------------------------------------------------------
1 |
10 |
11 |
12 |
13 |
14 |
{{ error_description }}
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/geokey/templates/snippets/footer.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
8 |
9 |
13 |
14 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/geokey/templates/snippets/google_analytics.html:
--------------------------------------------------------------------------------
1 | {% if GOOGLE_ANALYTICS %}
2 |
11 | {% endif %}
12 |
--------------------------------------------------------------------------------
/geokey/templates/snippets/messages.html:
--------------------------------------------------------------------------------
1 | {% if DEBUG %}
2 |
3 |
The administrator has enabled DEBUG mode for this platform. This very likely means that the platform is run as a test environment and things may break. Please get in touch with the administrator if you constantly experience problems.
4 |
5 | {% endif %}
6 |
7 | {% for message in messages %}
8 |
9 | × Close
10 | {{ message|linebreaks }}
11 |
12 | {% endfor %}
13 |
--------------------------------------------------------------------------------
/geokey/templates/snippets/project_help.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
1 Create categories
5 |
Categories define what data you want your contributers to map. Say you want to create a map of the favourite places in London; then you would create a category for each restaurants, bar and great outdoor spots you like.
6 |
Each category will have fields, that specify what information will be collected for that category. For example, a restaurant has a name, an address and the cuisine.
7 |
Based on categories, the client application will create forms your contirbutors have to fill in order to add data to your project.
8 |
9 |
2 Provide access to your data through data groupings
10 |
Data groupings provide users access to a subset of all data collected within a project. For each data group you create a set of filters to decide which data can be found in that data grouping. For example, you can create a grouping with all Italian restaurants that have a rating higher than 5.
11 |
12 |
You can also select user groups, which will be allowed to access the data in a data grouping.
13 |
14 |
3 Grant permissions to users with user groups.
15 |
Using user groups you can grant users permissions to your project. For each user group you can set whether its members can moderate, contribute or only read data. Furthermore, you can grant user groups access to the data groupings you created before.
16 |
17 |
18 |
--------------------------------------------------------------------------------
/geokey/templates/snippets/social_apps.html:
--------------------------------------------------------------------------------
1 | {% load socialaccount %}
2 |
3 | {% if social_apps %}
4 |
11 | {% endif %}
12 |
--------------------------------------------------------------------------------
/geokey/templates/snippets/usergroup_editor.html:
--------------------------------------------------------------------------------
1 |
5 |
6 | {% if project.islocked %}
7 |
8 |
The project is locked, therefore user group cannot be edited. If you wish to edit it, you have to unlock the project in the project settings first.
9 |
10 | {% else %}
11 |
12 |
13 |
14 |
17 |
18 | {% endif %}
19 |
20 | {% if users.all %}
21 |
22 | {% for user in users %}
23 |
24 | {{ user }}
25 | {% if not project.islocked %}
26 | {% if users|length > 1 or not admins %}remove {% endif %}
27 | {% endif %}
28 |
29 | {% empty %}
30 | No users have been added to this user group yet.
31 | {% endfor %}
32 |
33 | {% else %}
34 |
35 |
We couldn't find any users assigned to this user group.
36 |
37 | {% if project.islocked %}
38 |
Unfortunately, you cannot add new users when the project is locked.
39 | {% else %}
40 |
Type a display name in the input field to find the user you want to add, then click on the name in the results list to add the user to this user group.
41 | {% endif %}
42 |
43 | {% endif %}
44 |
--------------------------------------------------------------------------------
/geokey/templates/socialaccount/authentication_error.html:
--------------------------------------------------------------------------------
1 | {% extends 'base.html' %}
2 | {% block title %} | Authentication error{% endblock %}
3 |
4 | {% block main %}
5 |
10 |
11 |
12 |
13 |
14 |
An error occurred while attempting to authenticate you. Please try to
sign in again.
15 |
16 |
17 |
18 | {% endblock %}
19 |
--------------------------------------------------------------------------------
/geokey/templates/socialaccount/login_cancelled.html:
--------------------------------------------------------------------------------
1 | {% extends 'base.html' %}
2 | {% block title %} | Authentication cancelled{% endblock %}
3 |
4 | {% block main %}
5 |
10 |
11 |
12 |
13 |
14 |
You decided to cancel the authentication process using one of your existing accounts. If this was a mistake, please proceed to
sign in page.
15 |
16 |
17 |
18 | {% endblock %}
19 |
--------------------------------------------------------------------------------
/geokey/templates/subsets/subset_navigation.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
Subset
4 |
5 |
6 | {% if project.islocked %} {% endif %}
7 | {{ subset.name }}
8 |
9 |
10 |
11 |
15 |
16 |
--------------------------------------------------------------------------------
/geokey/templates/superusertools/navigation.html:
--------------------------------------------------------------------------------
1 |
22 |
--------------------------------------------------------------------------------
/geokey/templates/superusertools/platform_settings.html:
--------------------------------------------------------------------------------
1 | {% extends 'base.html' %}
2 |
3 | {% block title %} | Superuser tools - Platform settings{% endblock %}
4 |
5 | {% block main %}
6 |
12 |
13 |
14 | {% include 'snippets/messages.html' %}
15 |
16 |
40 |
41 | {% endblock %}
42 |
43 | {% block libraries %}
44 |
45 | {% endblock %}
46 |
--------------------------------------------------------------------------------
/geokey/templates/superusertools/provider_list.html:
--------------------------------------------------------------------------------
1 | {% extends 'base.html' %}
2 |
3 | {% block title %} | Superuser tools - Providers{% endblock %}
4 |
5 | {% block main %}
6 |
12 |
13 |
14 | {% include 'snippets/messages.html' %}
15 |
16 |
17 |
18 |
19 |
Providers allow users to connect their social accounts and sign in to the {{ PLATFORM_NAME }} using them.
20 |
In order to enable a provider, the application must be registered on its API tools to retrieve the required credentials.
21 |
22 |
23 |
24 |
25 |
26 |
27 | {% for provider in providers %}
28 | {% if forloop.first %}
29 |
38 | {% endif %}
39 | {% empty %}
40 |
41 |
There are no providers available.
42 |
43 | {% endfor %}
44 |
45 |
46 |
47 | {% endblock %}
48 |
--------------------------------------------------------------------------------
/geokey/templates/superusertools/provider_overview.html:
--------------------------------------------------------------------------------
1 | {% extends 'base.html' %}
2 |
3 | {% block title %} | Superuser tools - Provider: {{ provider.name }}{% endblock %}
4 |
5 | {% block main %}
6 |
12 |
13 |
14 | {% include 'snippets/messages.html' %}
15 |
16 |
43 |
44 | {% endblock %}
45 |
46 | {% block libraries %}
47 |
48 | {% endblock %}
49 |
--------------------------------------------------------------------------------
/geokey/templates/users/usergroup_navigation.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
User group
4 |
5 |
6 | {% if project.islocked %} {% endif %}
7 | {{ usergroup.name }}
8 |
9 |
10 |
11 |
17 |
18 |
--------------------------------------------------------------------------------
/geokey/templates/users/usergroup_overview.html:
--------------------------------------------------------------------------------
1 | {% extends 'base.html' %}
2 |
3 | {% block bodydata %}
4 | data-project-id="{{ project.id }}"
5 | data-project-locked="{{ project.islocked }}"
6 | data-usergroup-id="{{ usergroup.id }}"
7 | {% endblock %}
8 |
9 | {% block title %} | Project: {{ project.name }} - User group: {{ usergroup.name }} - Overview{% endblock %}
10 |
11 | {% block main %}
12 |
22 |
23 |
24 | {% include 'snippets/messages.html' %}
25 |
26 |
27 |
28 | {% include 'users/usergroup_navigation.html' %}
29 |
30 |
31 |
32 | {% include 'snippets/usergroup_editor.html' with users=usergroup.users.all %}
33 |
34 |
35 |
36 | {% endblock %}
37 |
38 | {% block libraries %}
39 |
40 |
41 |
42 |
43 |
44 | {% endblock %}
45 |
--------------------------------------------------------------------------------
/geokey/users/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ExCiteS/geokey/53b0bf85ffd30c9e958f028bf9ece5f6ef8d600f/geokey/users/__init__.py
--------------------------------------------------------------------------------
/geokey/users/management/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ExCiteS/geokey/53b0bf85ffd30c9e958f028bf9ece5f6ef8d600f/geokey/users/management/__init__.py
--------------------------------------------------------------------------------
/geokey/users/management/commands/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ExCiteS/geokey/53b0bf85ffd30c9e958f028bf9ece5f6ef8d600f/geokey/users/management/commands/__init__.py
--------------------------------------------------------------------------------
/geokey/users/management/commands/check_confirm.py:
--------------------------------------------------------------------------------
1 | """Command `check_confirm`."""
2 |
3 | from pytz import utc
4 | from datetime import datetime, timedelta
5 |
6 | from django.core.management.base import BaseCommand
7 |
8 | from allauth.account import app_settings
9 | from allauth.account.models import EmailAddress, EmailConfirmation
10 |
11 |
12 | class Command(BaseCommand):
13 | """A command to check which users should be inactivated."""
14 |
15 | def set_user_inactive(self, yesterday):
16 | outstanding = EmailAddress.objects.filter(
17 | verified=False,
18 | user__is_active=True,
19 | user__is_superuser=False)
20 |
21 | for address in outstanding:
22 | try:
23 | confirmation = EmailConfirmation.objects.filter(
24 | email_address=address).latest('id')
25 |
26 | if confirmation.sent < yesterday:
27 | address.user.is_active = False
28 | address.user.save()
29 | except EmailConfirmation.DoesNotExist:
30 | if app_settings.EMAIL_VERIFICATION in ["optional", "required"]:
31 | address.user.is_active = False
32 | address.user.save()
33 |
34 | def handle(self, *args, **options):
35 | now = datetime.utcnow() - timedelta(1)
36 | yesterday = datetime(
37 | now.year, now.month, now.day, 0, 0, 0).replace(tzinfo=utc)
38 |
39 | self.set_user_inactive(yesterday)
40 |
--------------------------------------------------------------------------------
/geokey/users/migrations/0002_auto_20150106_1420.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 |
4 | from django.db import migrations
5 |
6 |
7 | def create_anonymous(apps, schema_editor):
8 | User = apps.get_model("users", "User")
9 | if not User.objects.filter(display_name='AnonymousUser').exists():
10 | User.objects.create(
11 | display_name='AnonymousUser',
12 | password='',
13 | email=''
14 | )
15 |
16 |
17 | class Migration(migrations.Migration):
18 |
19 | dependencies = [
20 | ('users', '0001_initial'),
21 | ]
22 |
23 | operations = [
24 | migrations.RunPython(create_anonymous),
25 | ]
26 |
--------------------------------------------------------------------------------
/geokey/users/migrations/0002_auto_20150824_1603.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 |
4 | from django.db import models, migrations
5 |
6 |
7 | class Migration(migrations.Migration):
8 |
9 | dependencies = [
10 | ('users', '0001_initial'),
11 | ]
12 |
13 | operations = [
14 | migrations.AlterField(
15 | model_name='user',
16 | name='email',
17 | field=models.EmailField(unique=True, max_length=254),
18 | ),
19 | migrations.AlterField(
20 | model_name='user',
21 | name='last_login',
22 | field=models.DateTimeField(null=True, verbose_name='last login', blank=True),
23 | ),
24 | ]
25 |
--------------------------------------------------------------------------------
/geokey/users/migrations/0002_auto_20150904_1113.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 |
4 | from django.db import models, migrations
5 |
6 |
7 | class Migration(migrations.Migration):
8 |
9 | dependencies = [
10 | ('users', '0001_initial'),
11 | ]
12 |
13 | operations = [
14 | migrations.AlterField(
15 | model_name='user',
16 | name='display_name',
17 | field=models.CharField(unique=True, max_length=50, error_messages={b'unique': b'A user is already registered with this display name.'}),
18 | preserve_default=True,
19 | ),
20 | migrations.AlterField(
21 | model_name='user',
22 | name='email',
23 | field=models.EmailField(unique=True, max_length=75, error_messages={b'unique': b'A user is already registered with this email address.'}),
24 | preserve_default=True,
25 | ),
26 | ]
27 |
--------------------------------------------------------------------------------
/geokey/users/migrations/0003_auto_20150611_1307.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 |
4 | from django.db import models, migrations
5 | try:
6 | from django.contrib.postgres.fields import JSONField
7 | except ImportError:
8 | from django_pgjson.fields import JsonBField as JSONField
9 |
10 |
11 | class Migration(migrations.Migration):
12 |
13 | dependencies = [
14 | ('users', '0002_auto_20150106_1420'),
15 | ]
16 |
17 | operations = [
18 | migrations.AddField(
19 | model_name='usergroup',
20 | name='filters',
21 | field=JSONField(null=True, blank=True),
22 | preserve_default=True,
23 | ),
24 | migrations.AddField(
25 | model_name='usergroup',
26 | name='where_clause',
27 | field=models.TextField(null=True, blank=True),
28 | preserve_default=True,
29 | ),
30 | ]
31 |
--------------------------------------------------------------------------------
/geokey/users/migrations/0004_auto_20150617_0902.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 |
4 | from django.db import migrations
5 |
6 |
7 | class Migration(migrations.Migration):
8 |
9 | dependencies = [
10 | ('users', '0003_auto_20150611_1307'),
11 | ]
12 |
13 | operations = [
14 | migrations.RunSQL('DROP TABLE IF EXISTS users_groupingusergroup;')
15 | ]
16 |
--------------------------------------------------------------------------------
/geokey/users/migrations/0005_auto_20150825_0933.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 |
4 | from django.db import models, migrations
5 |
6 |
7 | class Migration(migrations.Migration):
8 |
9 | dependencies = [
10 | ('users', '0002_auto_20150824_1603'),
11 | ('oauth2_provider', '0002_08_updates'),
12 | ]
13 |
14 | operations = [
15 | migrations.RunSQL('DROP TABLE IF EXISTS oauth2_provider_application;')
16 | ]
17 |
--------------------------------------------------------------------------------
/geokey/users/migrations/0006_merge.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 |
4 | from django.db import models, migrations
5 |
6 |
7 | class Migration(migrations.Migration):
8 |
9 | dependencies = [
10 | ('users', '0002_auto_20150904_1113'),
11 | ('users', '0005_auto_20150825_0933'),
12 | ]
13 |
14 | operations = [
15 | ]
16 |
--------------------------------------------------------------------------------
/geokey/users/migrations/0007_auto_20151006_1110.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 |
4 | from django.db import models, migrations
5 |
6 |
7 | class Migration(migrations.Migration):
8 |
9 | dependencies = [
10 | ('users', '0006_merge'),
11 | ]
12 |
13 | operations = [
14 | migrations.AlterField(
15 | model_name='user',
16 | name='email',
17 | field=models.EmailField(unique=True, max_length=254, error_messages={b'unique': b'A user is already registered with this email address.'}),
18 | ),
19 | ]
20 |
--------------------------------------------------------------------------------
/geokey/users/migrations/0008_historicalusergroup.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 |
4 | from django.db import migrations, models
5 | try:
6 | from django.contrib.postgres.fields import JSONField
7 | except ImportError:
8 | from django_pgjson.fields import JsonBField as JSONField
9 | import django.db.models.deletion
10 | from django.conf import settings
11 |
12 |
13 | class Migration(migrations.Migration):
14 |
15 | dependencies = [
16 | ('projects', '0008_historicalproject'),
17 | ('users', '0007_auto_20151006_1110'),
18 | ('users', '0004_auto_20150617_0902'),
19 | ]
20 |
21 | operations = [
22 | migrations.CreateModel(
23 | name='HistoricalUserGroup',
24 | fields=[
25 | ('id', models.IntegerField(verbose_name='ID', db_index=True, auto_created=True, blank=True)),
26 | ('name', models.CharField(max_length=100)),
27 | ('description', models.TextField(null=True, blank=True)),
28 | ('can_contribute', models.BooleanField(default=True)),
29 | ('can_moderate', models.BooleanField(default=False)),
30 | ('filters', JSONField(null=True, blank=True)),
31 | ('where_clause', models.TextField(null=True, blank=True)),
32 | ('history_id', models.AutoField(serialize=False, primary_key=True)),
33 | ('history_date', models.DateTimeField()),
34 | ('history_type', models.CharField(max_length=1, choices=[('+', 'Created'), ('~', 'Changed'), ('-', 'Deleted')])),
35 | ('history_user', models.ForeignKey(related_name='+', on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL, null=True)),
36 | ('project', models.ForeignKey(related_name='+', on_delete=django.db.models.deletion.DO_NOTHING, db_constraint=False, blank=True, to='projects.Project', null=True)),
37 | ],
38 | options={
39 | 'ordering': ('-history_date', '-history_id'),
40 | 'get_latest_by': 'history_date',
41 | 'verbose_name': 'historical user group',
42 | },
43 | ),
44 | ]
45 |
--------------------------------------------------------------------------------
/geokey/users/migrations/0009_auto_20180502_1258.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 |
4 | from django.db import migrations, models
5 |
6 |
7 | class Migration(migrations.Migration):
8 |
9 | dependencies = [
10 | ('users', '0008_historicalusergroup'),
11 | ]
12 |
13 | operations = [
14 | migrations.AlterField(
15 | model_name='user',
16 | name='last_login',
17 | field=models.DateTimeField(null=True, verbose_name='last login', blank=True),
18 | ),
19 | ]
20 |
--------------------------------------------------------------------------------
/geokey/users/migrations/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ExCiteS/geokey/53b0bf85ffd30c9e958f028bf9ece5f6ef8d600f/geokey/users/migrations/__init__.py
--------------------------------------------------------------------------------
/geokey/users/templatetags/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ExCiteS/geokey/53b0bf85ffd30c9e958f028bf9ece5f6ef8d600f/geokey/users/templatetags/__init__.py
--------------------------------------------------------------------------------
/geokey/users/templatetags/filter_tags.py:
--------------------------------------------------------------------------------
1 | """Template tags for filtering tags."""
2 |
3 | from django import template
4 | from django.utils.safestring import mark_safe
5 |
6 | from geokey.categories.models import Field
7 |
8 | register = template.Library()
9 |
10 |
11 | @register.simple_tag
12 | def is_selected(value, arr):
13 | if str(value) in arr:
14 | return 'selected'
15 | return ''
16 |
17 |
18 | @register.simple_tag
19 | def show_restrict(rules, category):
20 | if rules:
21 | if str(category.id) in rules:
22 | if rules[str(category.id)] == {}:
23 | return mark_safe('Restrict further ')
25 |
26 | return ''
27 |
28 |
29 | @register.filter(name='is_in')
30 | def is_in(d, key_name):
31 | if d is not None:
32 | if str(key_name) in d:
33 | return True
34 |
35 | return False
36 |
37 |
38 | @register.inclusion_tag('snippets/data_fields_rules.html')
39 | def show_fields(filters, category):
40 | if filters and str(category.id) in filters:
41 | cat_rules = filters.get(str(category.id))
42 |
43 | context = {
44 | 'locked': category.project.islocked,
45 | 'min_date': cat_rules.pop('min_date', None),
46 | 'max_date': cat_rules.pop('max_date', None),
47 | 'fields': [],
48 | }
49 |
50 | for key in cat_rules:
51 | try:
52 | context['fields'].append({
53 | 'category_id': category.id,
54 | 'field': category.fields.get_subclass(key=key),
55 | 'rule': cat_rules[key],
56 | })
57 | except Field.DoesNotExist:
58 | pass
59 |
60 | return context
61 |
62 |
63 | @register.filter(name='minval')
64 | def minval(d):
65 | if d is not None:
66 | if d.get('minval'):
67 | return d.get('minval')
68 |
69 | return ''
70 |
71 |
72 | @register.filter(name='maxval')
73 | def maxval(d):
74 | if d is not None:
75 | if d.get('maxval'):
76 | return d.get('maxval')
77 |
78 | return ''
79 |
--------------------------------------------------------------------------------
/geokey/users/templatetags/social.py:
--------------------------------------------------------------------------------
1 | """Template tags for social features."""
2 |
3 | from django import template
4 | from django.db.models import Q
5 |
6 | from allauth.socialaccount import providers
7 | from allauth.socialaccount.models import SocialApp
8 |
9 |
10 | register = template.Library()
11 |
12 |
13 | @register.assignment_tag
14 | def get_social_apps():
15 | """Get all enabled social apps."""
16 | social_apps = SocialApp.objects.exclude(Q(client_id__exact='')).distinct()
17 |
18 | for social_app in social_apps:
19 | try:
20 | provider = providers.registry.by_id(social_app.provider)
21 | except:
22 | provider = None
23 |
24 | social_app.provider = provider
25 |
26 | return social_apps
27 |
--------------------------------------------------------------------------------
/geokey/users/tests/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ExCiteS/geokey/53b0bf85ffd30c9e958f028bf9ece5f6ef8d600f/geokey/users/tests/__init__.py
--------------------------------------------------------------------------------
/geokey/users/tests/test_serializers.py:
--------------------------------------------------------------------------------
1 | """Tests for serializers of users."""
2 |
3 | from django.test import TestCase
4 |
5 | from rest_framework.serializers import ValidationError
6 | from allauth.socialaccount.models import SocialAccount
7 |
8 | from .model_factories import UserFactory
9 | from ..serializers import UserSerializer
10 |
11 |
12 | class UserSerializerTest(TestCase):
13 |
14 | def test_get_social_accounts_when_empty(self):
15 | user = UserFactory.create()
16 | serializer = UserSerializer(user)
17 | self.assertEqual(serializer.get_social_accounts(user), [])
18 |
19 | def test_get_social_accounts_when_connected_to_facebook(self):
20 | user = UserFactory.create()
21 | social_account = SocialAccount.objects.create(
22 | user=user, provider='facebook', uid='123')
23 | serializer = UserSerializer(user)
24 | self.assertEqual(
25 | serializer.get_social_accounts(user),
26 | [{
27 | 'id': social_account.id,
28 | 'provider': 'facebook'
29 | }]
30 | )
31 |
32 | def test_validate_display_name(self):
33 | UserFactory.create(**{'display_name': 'name'})
34 | user = UserFactory.create()
35 | serializer = UserSerializer(user)
36 |
37 | try:
38 | serializer.validate_display_name('name')
39 | except ValidationError:
40 | pass
41 | else:
42 | self.fail('validate_display_name did not raise ValidationError')
43 |
44 | def test_validate_email(self):
45 | UserFactory.create(**{'email': 'name@example.com'})
46 | user = UserFactory.create()
47 | serializer = UserSerializer(user)
48 |
49 | try:
50 | serializer.validate_email('name@example.com')
51 | except ValidationError:
52 | pass
53 | else:
54 | self.fail('validate_email did not raise ValidationError')
55 |
--------------------------------------------------------------------------------
/geokey/users/tests/test_templatetags.py:
--------------------------------------------------------------------------------
1 | """Tests for template tags of users."""
2 |
3 | from django.test import TestCase
4 |
5 | from geokey.categories.tests.model_factories import CategoryFactory
6 |
7 | from ..templatetags import filter_tags
8 |
9 |
10 | class TemplateTagsTest(TestCase):
11 | def test_show_restrict(self):
12 | category = CategoryFactory.create()
13 | self.assertEqual(
14 | filter_tags.show_restrict({str(category.id): {}}, category),
15 | ''
16 | 'Restrict further '
17 | )
18 | self.assertEqual(
19 | filter_tags.show_restrict({'2': {}}, category),
20 | ''
21 | )
22 |
23 | def test_is_selected(self):
24 | dict = ["1", "2", "3"]
25 |
26 | self.assertEqual(filter_tags.is_selected(1, dict), 'selected')
27 | self.assertEqual(filter_tags.is_selected(4, dict), '')
28 |
29 | def test_is_in(self):
30 | dict = {
31 | '1': {},
32 | '2': {}
33 | }
34 |
35 | self.assertTrue(filter_tags.is_in(dict, 1))
36 | self.assertFalse(filter_tags.is_in(dict, 4))
37 |
38 | def test_minval(self):
39 | self.assertEqual(filter_tags.minval({'minval': 5}), 5)
40 | self.assertEqual(filter_tags.minval({}), '')
41 |
42 | def test_maxval(self):
43 | self.assertEqual(filter_tags.maxval({'maxval': 5}), 5)
44 | self.assertEqual(filter_tags.maxval({}), '')
45 |
--------------------------------------------------------------------------------
/geokey/version.py:
--------------------------------------------------------------------------------
1 | """Version of GeoKey."""
2 |
3 | VERSION = (1, 11, 2, 'final', 0)
4 |
5 |
6 | def get_version():
7 | """
8 | Return current version of GeoKey.
9 |
10 | Returns
11 | -------
12 | str
13 | Current version.
14 | """
15 | version = '%s.%s' % (VERSION[0], VERSION[1])
16 | if VERSION[2]:
17 | version = '%s.%s' % (version, VERSION[2])
18 |
19 | sub = ''
20 | if VERSION[3] != 'final':
21 | mapping = {'alpha': 'a', 'beta': 'b', 'rc': 'c'}
22 | sub = mapping[VERSION[3]] + str(VERSION[4])
23 |
24 | return version + sub
25 |
--------------------------------------------------------------------------------
/local_settings.example/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ExCiteS/geokey/53b0bf85ffd30c9e958f028bf9ece5f6ef8d600f/local_settings.example/__init__.py
--------------------------------------------------------------------------------
/local_settings.example/wsgi.py:
--------------------------------------------------------------------------------
1 | """WSGI configuration."""
2 |
3 | import os
4 |
5 | from django.core.wsgi import get_wsgi_application
6 |
7 |
8 | try:
9 | import local_settings
10 | settings_module = 'settings'
11 | except ImportError:
12 | settings_module = 'geokey.core.settings.project'
13 |
14 |
15 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', settings_module)
16 | application = get_wsgi_application()
17 |
--------------------------------------------------------------------------------
/manage.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | """Default Django manager, when using local settings."""
3 |
4 | import os
5 | import sys
6 |
7 |
8 | if __name__ == '__main__':
9 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'local_settings.settings')
10 | from django.core.management import execute_from_command_line
11 | execute_from_command_line(sys.argv)
12 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "GeoKey",
3 | "version": "0.0.0",
4 | "devDependencies": {
5 | "grunt": "*",
6 | "grunt-contrib-concat": "*",
7 | "grunt-contrib-handlebars": "*",
8 | "grunt-contrib-uglify": "*",
9 | "grunt-contrib-watch": "*"
10 | },
11 | "scripts": {
12 | "grunt": "grunt"
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/requirements-dev.txt:
--------------------------------------------------------------------------------
1 | factory-boy==2.11.1
2 | django-debug-toolbar==1.7
3 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | Django>=1.8.19,<1.12
2 | django-aggregate-if==0.5
3 | django-allauth==0.33.0
4 | django-braces==1.11.0
5 | django-crontab==0.7.1
6 | django-hstore==1.4.2
7 | django-model-utils==3.1.2
8 | django-oauth-toolkit==0.12.0
9 | django-pgjson==0.3.1
10 | django-simple-history==1.8.2
11 | django-nose==1.4.5
12 | djangorestframework==3.9.4
13 | djangorestframework-gis==0.14.0
14 | easy-thumbnails==2.4.2
15 | gdata==2.0.18
16 | gdal==1.10.0
17 | iso8601==0.1.12
18 | moment==0.8.2
19 | nose==1.3.7
20 | pillow==6.2.0
21 | psycopg2==2.7.3.1
22 | pytz==2017.2
23 | python-magic==0.4.15
24 | requests[security]==2.20.0
25 | tweepy==3.5.0
26 | facebook-sdk==2.0.0
27 | oauth2client==4.1.2
28 | oauthlib==2.0.6
29 | google-api-python-client==1.6.4
30 |
--------------------------------------------------------------------------------
/setup.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | """GeoKey setup."""
4 |
5 | from os.path import join
6 | from setuptools import setup, find_packages
7 |
8 | from geokey.version import get_version
9 |
10 |
11 | name = 'geokey'
12 | version = get_version()
13 | repository = join('https://github.com/ExCiteS', name)
14 |
15 |
16 | def get_install_requires():
17 | """
18 | Get requirements (ignore links, exclude comments).
19 |
20 | Returns
21 | -------
22 | list
23 | Requirements for GeoKey.
24 | """
25 | requirements = list()
26 | for line in open('requirements.txt').readlines():
27 | if line.startswith('#') or line.startswith('git+https') or line == '':
28 | continue
29 | requirements.append(line.rstrip())
30 | return requirements
31 |
32 |
33 | setup(
34 | name=name,
35 | version=version,
36 | description='Platform for participatory mapping',
37 | url='http://geokey.org.uk',
38 | download_url=join(repository, 'tarball', version),
39 | author='ExCiteS',
40 | author_email='excites@ucl.ac.uk',
41 | license='Apache 2.0',
42 | packages=find_packages(),
43 | include_package_data=True,
44 | install_requires=get_install_requires(),
45 | )
46 |
--------------------------------------------------------------------------------